Secrets Management
Secrets management in GOVERN follows the principle of least privilege: every secret is scoped to exactly the component that needs it, and no secret lives in source code, commit history, or build logs.
Secret Storage Locations
| Location | What lives there | Access |
|---|---|---|
| Wrangler secrets | Worker runtime secrets (Cloudflare-encrypted) | Engineers via wrangler secret |
| Cloudflare Pages env vars | Frontend build-time env vars | Cloudflare dashboard |
| 1Password (team vault) | Master copies, rotation records | Engineers with vault access |
Local .dev.vars | Development-only overrides (gitignored) | Local machine only |
Never: .env committed to git, secrets in wrangler.toml, secrets in build logs.
Full Secrets Inventory
API Gateway (Cloudflare Worker)
| Secret name | Purpose | Rotation frequency |
|---|---|---|
SUPABASE_URL | Supabase project URL | Never (stable) |
SUPABASE_SERVICE_ROLE_KEY | Full DB access (server-side only) | Annually or on breach |
ANTHROPIC_API_KEY | Claude API calls | Every 90 days |
OPENAI_API_KEY | TTS-1 voice synthesis | Every 90 days |
AUTH_SECRET | Bearer token for API auth | Every 90 days |
CHAIRMAN_USER_ID | Chairman’s Supabase UUID | Never (stable) |
UPSTASH_REDIS_REST_URL | Redis endpoint | Never (stable) |
UPSTASH_REDIS_REST_TOKEN | Redis auth token | Annually |
LANGFUSE_HOST | Langfuse observability endpoint | Never (stable) |
LANGFUSE_PUBLIC_KEY | Langfuse public key | Annually |
LANGFUSE_SECRET_KEY | Langfuse secret key | Annually |
GROQ_API_KEY | GroqChairman substrate calls | Every 90 days |
INNGEST_EVENT_KEY | Inngest event submission | Annually |
INNGEST_SIGNING_KEY | Inngest webhook verification | Annually |
Cloudflare Pages (Frontend)
| Variable | Purpose |
|---|---|
VITE_API_URL | API Gateway URL (not secret, but env-specific) |
VITE_SUPABASE_URL | Supabase URL (not secret) |
VITE_SUPABASE_ANON_KEY | Supabase anon key (public by design) |
Probe Container
| Variable | Purpose |
|---|---|
GOVERN_API_URL | GOVERN API endpoint |
GOVERN_API_KEY | Per-customer probe auth key |
GOVERN_SYSTEM_ID | Identifies which AI system this probe monitors |
Managing Wrangler Secrets
List current secrets
# Production environmentnpx wrangler secret list --env production
# Staging environmentnpx wrangler secret list --env stagingSet a secret
# Interactive (prompted for value — preferred, avoids shell history)npx wrangler secret put ANTHROPIC_API_KEY --env production
# From stdin (useful in CI)echo "sk-ant-..." | npx wrangler secret put ANTHROPIC_API_KEY --env productionDelete a secret
npx wrangler secret delete OLD_SECRET_NAME --env productionVerify a secret is accessible in the Worker
# The health endpoint checks key bindingscurl https://jarvis-api-gateway.ben-c1f.workers.dev/health | jq '.checks'
# A missing or invalid secret will show as "error" in the checks objectLocal Development Setup
For local development, create .dev.vars in each package that needs secrets:
# packages/api-gateway/.dev.vars (gitignored)SUPABASE_URL=https://your-project.supabase.coSUPABASE_SERVICE_ROLE_KEY=eyJ...ANTHROPIC_API_KEY=sk-ant-...AUTH_SECRET=local-dev-secret-do-not-use-in-prodUPSTASH_REDIS_REST_URL=https://...UPSTASH_REDIS_REST_TOKEN=AX...The .dev.vars file is read by wrangler dev automatically. It is listed in .gitignore at the repo root.
Never commit .dev.vars. If you accidentally commit it, rotate all secrets immediately.
Rotation Procedures
Rotating an Anthropic API key
- Log into
console.anthropic.com - Generate a new API key
- Copy the new key to 1Password
- Set the new key in Wrangler:
npx wrangler secret put ANTHROPIC_API_KEY --env production - The Worker picks up new secrets immediately (no redeploy needed for secrets)
- Test:
curl https://jarvis-api-gateway.ben-c1f.workers.dev/health - After 24 hours of confirmed healthy operation, revoke the old key in Anthropic console
- Record the rotation date in 1Password
Rotating AUTH_SECRET
AUTH_SECRET rotation requires coordinating with all clients that use it:
- Generate new secret:
openssl rand -hex 32 - Update in Wrangler (staging first, test, then production)
- Update in all CI/CD pipelines that call the API
- Update in the Internal Dashboard’s stored credentials
- Update in any cron jobs or monitoring tools
- Verify all systems still healthy
- Record rotation in 1Password
Emergency rotation (suspected breach)
If a secret is suspected to be compromised:
- Immediately rotate the secret — do not wait
- Check access logs for unauthorized use
- Post in
#ops-alerts: “Emergency rotation: [SECRET_NAME] suspected compromised. Rotating now.” - After rotation, audit what the compromised key could have accessed
- File an incident report within 24 hours
Security Policy
-
Least privilege — Each component gets only the secrets it needs. The API gateway does not have deploy keys. CI does not have the service role key.
-
No secrets in code — Enforce with
git-secretsortrufflehogpre-commit hooks. -
Rotate on team changes — When an engineer leaves, rotate all secrets they had access to.
-
Audit secret usage — Quarterly review of which secrets are still needed. Remove unused secrets.
-
Different secrets per environment — Development, staging, and production always use different credentials. Never share a production secret with a development environment.
Pre-commit Secret Scanning
# Install trufflehog (run once)brew install trufflehog
# Scan before committingtrufflehog filesystem . --only-verified
# Or use the git-secrets toolgit secrets --scanAdd to .git/hooks/pre-commit for automatic scanning on every commit.