Credentials And Resumable Bootstrap
This page explains how GoingNinja handles API keys and sessions so that bootstrap can be resumable and shell-independent instead of depending on one lucky terminal window.
If you first need the beginner view of which accounts, domains, and provider access must exist before bootstrap can even start, read Before You Start.
If you need to prove that the machine can actually see the expected provider sessions and tokens, use the verification block below before assuming bootstrap is broken.
1. Why Resumable Bootstrap Needs A Credential Model
There is no serious “one-click” setup without a serious credential boundary.
The bootstrap script has to talk to real providers:
- GitHub
- Vercel
- Neon
- Cloudflare
- review providers such as Anthropic and Google
The hosted wiki assistant adds one more provider class:
- Mistral for the public wiki question-answer surface
If those credentials live only in ad-hoc environment variables, the system breaks as soon as the shell changes.
2. Scope Split
GoingNinja uses three layers:
| Layer | Holds | Example |
|---|---|---|
| global provider scope | reusable provider credentials | CLOUDFLARE_API_TOKEN, VERCEL_TOKEN, NEON_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, MISTRAL_DEV_API_KEY, MISTRAL_PROD_API_KEY, gh session |
| project secret scope | project-only secrets and URLs | SESSION_SECRET, database URL, webhook secret, healthcheck URL |
| repo metadata | non-secret record of what a project depends on | .execution/credential-registry.json |
Current service names:
- global provider scope:
rascher.global.providers - project scope:
rascher.project.<slug>
These names follow the current single-operator namespace. A different operator replaces rascher with their own namespace; the platform does not require that literal prefix.1
3. Shell-Independent Loading
The current OS repo already ships a deterministic loader:
cd /path/to/goingninja-os
./scripts/load-global-providers.sh check
eval "$(./scripts/load-global-providers.sh exports)"
gh auth status
The key point is not the exact shell syntax. The key point is that the shell can be recreated from:
- the repo
- the registry
- Keychain
- provider CLI sessions
not from hidden shell history.
3a. How To Verify Provider Access Formally
Do not test provider readiness by printing secret values. Use formal status checks instead.
From goingninja-os, the normal check order is:
npm run access:check
./scripts/load-global-providers.sh check
eval "$(./scripts/load-global-providers.sh exports)"
gh auth status
What each step proves:
npm run access:checkconfirms that the required CLIs exist and that the required default provider entries are present../scripts/load-global-providers.sh checkconfirms that each provider entry resolves toready(...)ormissing(...).eval "$(./scripts/load-global-providers.sh exports)"confirms that the current shell receives the provider exports.gh auth statusconfirms that the GitHub CLI session itself is alive.
Important boundary:
- local shell exports are not the same as GitHub Actions secrets
- GitHub Actions secrets are not the same as runtime app secrets
If one of those layers is missing, the machine may still fail even though another layer looks healthy.
4. What Lives In The Generated Repo
Each generated project repo contains a non-secret registry:
{
"global_provider_service": "rascher.global.providers",
"project_secret_scope": "<PROJECT_SLUG>",
"entries": [
{ "name": "gh", "kind": "session", "status": "required" },
{ "name": "CLOUDFLARE_API_TOKEN", "kind": "global_keychain", "status": "optional" },
{ "name": "VERCEL_TOKEN", "kind": "global_keychain", "status": "optional" },
{ "name": "NEON_API_KEY", "kind": "global_keychain", "status": "optional" },
{ "name": "ANTHROPIC_API_KEY", "kind": "global_keychain", "status": "optional" },
{ "name": "GEMINI_API_KEY", "kind": "global_keychain", "status": "optional" },
{ "name": "MISTRAL_DEV_API_KEY", "kind": "global_keychain", "status": "optional" },
{ "name": "MISTRAL_PROD_API_KEY", "kind": "global_keychain", "status": "optional" }
]
}
This file exists so a new reader or a new shell can see what is needed without exposing the values.
For hosted assistants, the runtime variable may still be a neutral app-local name such as MISTRAL_API_KEY.
The global provider scope keeps development and production keys separate so deploy targets can map the correct workspace key into that runtime variable without mixing environments.
5. Security Posture Today
What is true today:
- secrets are not committed into generated repos
- provider metadata is separated from provider values
- the loader works without inheriting shell variables
- the current local implementation is strong for a single macOS operator
Not yet true:
| Boundary | Current status |
|---|---|
| multi-user secret sharing | not implemented |
| cloud-native secret vault abstraction | not implemented |
| cross-platform secure storage | not implemented; current path is macOS Keychain |
Current threat-model statement:
- this protects against committed-file leakage and most “new shell lost my env” failures
- this does not protect against a compromised unlocked machine or local malware
- this does not yet solve multi-user secret sharing or centralized rotation
6. Sources
Notes
- Implementation.
scripts/load-global-providers.sh,.execution/credential-registry.json, and the Keychain servicerascher.global.providers.