Doctrine

Credential references must carry domain context

credentialsnamingkeychainsecuritycontracts

Credential references must carry domain context

Doctrine

Every credential reference — Keychain entries, environment variables, code lookups, config files — MUST encode enough context for a reader to answer three questions without prior knowledge:

1. What provider domain? (Google AI Studio, Anthropic API, Supabase, Apple Developer, etc.) 2. What project or deployment? (camber-db, heartwood-db, orbit-mcp, etc.) 3. What scope? (read-only, admin, edge-function invocation, etc.)

A credential entry that requires the reader to already know the answer is a naked reference — it transfers risk from the writer to every future reader.

Rule

Keychain entries (security add-generic-password): the -s (service) field encodes the provider domain; the -a (account) field encodes the project and scope.

Format: service=<provider-domain>, account=<PROJECT>_<SCOPE>_<KEY_TYPE>

Examples of compliant entries:

  • service=google-ai-studio, account=CAMBER_GEMINI_API_KEY
  • service=anthropic, account=CAMBER_CLAUDE_API_KEY
  • service=supabase, account=CAMBER_DB_SERVICE_ROLE_KEY
  • service=apple-developer, account=HCB_DISTRIBUTION_CERT

Examples of naked refs (violations):

  • service=heartwood, account=GEMINI_API_KEY — heartwood is not a provider domain; which Google project? which API surface?
  • service=openai, account=ANTHROPIC_API_KEY — wrong service bucket entirely
  • service=anthropic, account=CAMBER_DB_URL — Supabase credential under Anthropic service
  • service=heartwood, account=METACULUS_API_TOKEN — Metaculus is not heartwood domain

Environment variables: must include project prefix. GEMINI_API_KEY alone is naked; CAMBER_GEMINI_API_KEY carries project context.

Code lookups: any function that reads a credential must reference the canonical Keychain path or env var name. Hardcoded secret values in code are a security violation, not just a naming violation.

CREDENTIAL_REGISTRY.md: remains the SSOT index. Every Keychain rename must be reflected here. The registry entry must include: provider domain, project, scope, Keychain service+account path, and last-verified date.

Anti-patterns

  • Bare API_KEY under a generic service — forces the reader to already know what system it belongs to
  • Cross-contaminated service buckets (Anthropic key under OpenAI service)
  • Provider-domain confusion (using a product name like heartwood as the Keychain service when the credential belongs to an external provider like Google)
  • Renaming the Keychain entry without updating all downstream code that reads from the old path

Relationship to ORA-2026-0044 (names carry contracts)

This doctrine is a specialization of ORA-2026-0044 for credentials. If names carry contracts, credential names carry security contracts. A naked credential reference is the security equivalent of naming a module utils — it tells you nothing about what it does, and forces every consumer to carry implicit knowledge the name should have encoded.

Origin

2026-04-26 shepherd audit of Keychain entries during CMB-1816 (credential hygiene + Gemini photo reclassification). Found 5 naked refs with cross-contaminated service buckets. The cost: sessions reading credentials had to guess which key belonged to which system, and one photo reclassification run (CMB-1791) fell back to Haiku because the Gemini key wasn't findable under its actual Keychain path.