Skip to main content
Amended by 0107: tenant-owned credentials (API keys, certificates, OAuth tokens) are a third class, kept in the @stackra/connections store. The two mechanisms here are unchanged for our own keys.
Amendment proposed in 0257: rule 3 becomes “a human or the secret-manager flow sets a value; nobody reads one”.

Context

Secret values leak through files, logs, test fixtures, chat transcripts and CI debug steps. Every extra store is another place to leak from and another thing to rotate. Developer tooling tokens and application secrets have different readers and need different homes.

Decision

Two kinds of secret, two mechanisms, never a third.
  1. Names in git, values in the vault. A file may list a secret’s name and purpose, never its value.
  2. Infisical is canonical for developer and CI tokens. /agents is read only by tools/scripts/mcp.sh, which passes a token to the server process; agents never read it. CI reads /ci only, and authenticates by GitHub OIDC (no static token stored as a CI variable).
  3. A human sets, rotates and deletes every value. An agent declares the secret in code and names key and purpose in its report.
  4. No .env and no .env.example. There is no file fallback.
  5. Worker secrets and EAS secret variables are application secrets too. The store differs, the rule does not.
  6. CI must never run infisical export, infisical secrets get without --silent, printenv, encore secret get, or any step that echoes a token or its length.
  7. pnpm verify and tests need zero secrets.
  8. Alternative recorded, not adopted: Infisical Secret Sync pushing values into runtime stores. It makes a second writer per store. Revisit when more than one runtime holds the same secret (revival trigger below).

Consequences

  • Onboarding needs vault access, not a copied file.
  • Where Encore is not deployed (0011), the application-secret store is chosen by the first service that needs one, by ADR.

Enforcement

  • .agents/hooks/guard-bash.mjs denies encore secret set/get, wrangler secret put/bulk, reading .env and .dev.vars, and printenv; gitleaks runs in lefthook.yml and as pnpm secrets:scan.
  • Planned, in the same change as /constitution/secrets: guard-bash rules for infisical export and infisical secrets get without --silent, with a hook test.
  • Planned: a secrets-doctor script (names only), a no-.env validator check, and a CI workflow allowlist for secrets.*.

Revival trigger

Reopen Secret Sync when a secret must be identical in three or more runtime stores and a human-only write has caused drift twice.

Supersedes and sources

Supersedes: none. Sources: platform docs/adr/0005-secrets-infisical-and-encore, 0018-secrets-constitution, 0019-application-secrets-single-source-and-propagation; user rules secrets.md.