Doctrine
ORA-2026-0115 — Credential grant registry discipline
ORA-2026-0115 — Credential grant registry discipline
Rule
Every external credential grant — Workspace DWD, OAuth client, IAM role, API key, vendor portal access, Stripe restricted key, Slack app install, GitHub App installation — MUST have a corresponding row in the fleet credential registry. A grant without a registry row is a security-debt violation; the registry, not the admin console, is the source of truth for what is granted, why, to whom, with what scopes, by whom, and last-validated when.
The registry lives at /Users/chadbarlow/Desktop/fleet/registries/credentials.md (markdown table — fleet-greppable, easy to audit). Promote to a heartwood-db table only when query patterns demand structured access; markdown is the default for fleet-discoverable surfaces because every seat can Read it without a connector.
Storage-format follow-on (peer-review note): Gemini reviewer (2026-05-01) flagged that a single 9-column markdown table risks (a) horizontal width hostile to CLI reads at scale and (b) git-blame collisions on concurrent writes. Counter-proposal: directory of files (registries/credentials/<credential_id>.md) with YAML frontmatter for structured fields + markdown body for audit trail. This is a valid future shape — file as FLT-0636-followon-storage-shape ticket if the registry crosses ~25 rows or experiences a write collision, whichever fires first. For now (single-digit-row registry, single-writer fleet writer-of-record), the markdown table holds.
Required fields per row
| Field | Meaning | Example |
|---|---|---|
what | Exact identifier (client_id / key fingerprint / role ARN / app ID) | 108547392145678901234 (21-digit SA client_id) |
where | Which system the grant lives in | admin.heartwoodcustombuilders.com → Security → DWD |
why | Literal use-site (which pipeline / surface / feature requires it) | gmail-financial-pipeline edge function impersonating admin@HCB |
scopes | Explicit scope list — no +N More placeholders | gmail.readonly, gmail.metadata, gmail.modify, gmail.compose, calendar, drive, admin.directory.user.readonly, admin.directory.group.readonly |
owner | Who created it, when, with what authorization | Chad 2026-04-29 per FLT-0630 directive |
last_validated | Date last verified against use-site (drift detection) | 2026-04-29 |
state | ACTIVE / STALE_SINCE: <date> / UNDER_INVESTIGATION / DELETED <date> | ACTIVE |
provider_domain | Per ORA-2026-0075 — keychain service= field | workspace.google.com |
account_label | Per ORA-2026-0075 — keychain account= field | HCB_WORKSPACE_INTEGRATION_SA |
Why
HCB Gmail 403-trio incident, 2026-04-29. Three service accounts had Domain-Wide Delegation on the heartwoodcustombuilders.com Workspace: orbit-mcp-runtime (101150455469870397475), claude_1 (107312379978944480251), Data Migration (New) (111745453960285227386). The fleet had zero visibility into which surface used which SA, what scopes each held beyond truncated UI display (+3 More), who created Data Migration (New) (which carried gmail.modify + gmail.insert write scopes — high blast radius), or whether any were orphaned. When admin@HCB pipeline 403'd, the fleet spent hours decomposing which-grant-is-broken instead of querying a registry.
The diagnostic fork even reached the wrong root cause ("DWD missing for admin@HCB") because the registry didn't exist to disconfirm. The actual root cause was Google's super-admin SA-impersonation block — a structural fact discoverable in 30 seconds with a registry, but invisible without one.
Chad framing (2026-04-29): "part of the problem is lack of understanding and discipline and record for what settings are already set on what accounts and for what purpose."
How to apply
New grant
- Same turn as the grant: file the registry row. No grant lives undocumented past the turn that created it.
- Registry row is part of the FOLLOW-ONS line on the DONE post that authorized the grant. Untied grants are equivalent to dormant capabilities (ORA-2026-0036) but with negative blast radius — a live attack surface with no documented owner.
Existing grant (archaeology)
- Boy-Scout rule applies: the seat that discovers an undocumented grant fills the row before continuing. No "I'll file it later" — context decay makes later more expensive than now.
- If the use-site cannot be named after a 5-minute audit, the row is filed
state: UNDER_INVESTIGATIONwith the discovering seat's id and a follow-on ticket to identify or tombstone the grant.
Drift detection
last_validated <90 daysrows surface to STRAT shepherd as drift candidates each tick.- A row that has been
UNDER_INVESTIGATIONfor >14 days advances on the tombstone ladder (ORA-2026-0029 / Standing Directive §11): rename use-site label to_orphan_<original>, file deletion ticket as CRITICAL.
Cross-Workspace asymmetry
- When the same SA is granted on multiple Workspaces with different scope sets (e.g.,
orbit-mcp-runtimehad 5 scopes on HCB vs. 3 on camberzero), the registry MUST list both grants and call out the asymmetry. Asymmetric scope sets are a registry signal — usually means one Workspace was migrated without the other.
"+N More" UI placeholders
- Forbidden in the registry. The registry expands what the admin console truncates. If the admin console shows
+3 More, the seat filing the row clicks through to enumerate every scope explicitly.
Anti-patterns this prevents
- "Why does Workspace X have client_id Y granted? — let me try git-blame archaeology" (current state without registry)
- Grant proliferation — adding a new grant alongside existing grants without checking if existing ones cover the use-case
- "Scary to delete because we don't know what uses it" — orphaned grants that compound because removal is too risky without a registry to disconfirm dependence
- Diagnostic forks reaching wrong root causes because they cannot see what is actually configured
- "Gate on branch, credential in prod" (ORA-2026-0036 sibling) — provisioning credentials before the gate-and-registry are also live
Relationship to peer doctrines
- ORA-2026-0044 (names carry contracts): Registry rows MUST use shape names, not mechanism names —
hcb-workspace-integrationnotorbit-mcp-runtimeorData Migration (New). The registry enforces the naming doctrine at grant-creation time. - ORA-2026-0075 (credentials carry domain context): Registry rows pin the
service=<provider-domain>andaccount=<PROJECT>_<SCOPE>_<KEY_TYPE>keychain format. The registry is the SSOT index that 0075 mandates. - ORA-2026-0036 (credential-gate atomicity): Registry row + activation gate + credential provisioning are a 3-tuple that MUST land in the same merge. A row without a credential is OK (planning); a credential without a row is a violation.
- feedback_durable_auth_principle.md (candidate ORA): Registry rows include an
auth_class:field —platform-bound(durable: SA+DWD, GitHub App, AWS IAM) vs.user-bound(fragile: OAuth refresh token, user PAT). User-bound rows MUST carry a documented exception reason.
Initial registry rows (FLT-0636 closure)
The registry is seeded at FLT-0636 closure with these rows:
| what | where | account_label | provider_domain | state | last_validated | notes |
|---|---|---|---|---|---|---|
hcb-workspace-integration@hcb-workspace-prod.iam.gserviceaccount.com | admin.heartwoodcustombuilders.com → Security → DWD | HCB_WORKSPACE_INTEGRATION_SA | workspace.google.com | ACTIVE | 2026-04-29 | Sole consolidated SA for HCB Workspace. 13-scope DWD grant. Replaces 3 prior SAs. Per project_workspace_sa_consolidation_directive.md. |
orbit-mcp-runtime (HCB) | DELETED 2026-04-29 from HCB DWD | _orphan_orbit-mcp-runtime | workspace.google.com | DELETED 2026-04-29 | n/a | Replaced by hcb-workspace-integration. SA itself disabled with 24h dwell, scheduled for deletion. |
claude_1 (HCB) | DELETED 2026-04-29 from HCB DWD | _orphan_claude_1 | workspace.google.com | DELETED 2026-04-29 | n/a | Replaced by hcb-workspace-integration. |
Data Migration (New) (HCB) | DELETED 2026-04-29 from HCB DWD | _orphan_data_migration_new | workspace.google.com | DELETED 2026-04-29 | n/a | Replaced by hcb-workspace-integration. Carried gmail.insert write scope — likely never used in fleet code. |
orbit-mcp-runtime (camberzero) | admin.camberzero.com → Security → DWD | CAMBERZERO_ORBIT_MCP_RUNTIME_SA | workspace.google.com | STALE_SINCE: 2026-04-29 | n/a | Pending camberzero Workspace migration. Will be replaced by camberzero-workspace-integration per playbook. |
super@heartwoodcustombuilders.com | Cloud Identity Free / HCB Workspace | HCB_WORKSPACE_SUPER_ADMIN | workspace.google.com | ACTIVE | 2026-04-29 | Break-glass super-admin. 2FA enrolled. Authenticator app + 8 backup codes. Per reference_credentials_hcb_workspace_super_admin.md. |
Future credential-related work (camberzero migration, Stripe restricted keys, Slack app installs, GitHub App tokens) extends the registry rather than re-inventing the documentation surface.
Enforcement
- Code review on any PR that introduces a credential reference (env var, config block, edge function secret): reviewer asks "is the registry row filed?" before approving.
- Shepherd tick:
last_validated <90 daysrows surface as drift candidates. - Quarterly fleet audit: enumerate every external grant via admin console snapshots, diff against the registry. Untracked grants are filed as
UNDER_INVESTIGATIONrows.
Operator note
Chad 2026-04-29 — "i would like to consolidate all the settings into one for each account and it should have nothing to do with orbit by name or infra." The directive that closed the proximate HCB consolidation also seeded this registry doctrine: the consolidation surfaces what is true now; the registry guarantees we will remember it tomorrow.
See also
feedback_credential_settings_registry.md— origin feedback for this doctrineproject_workspace_sa_consolidation_directive.md— HCB migration directive that surfaced the gapreference_workspace_tenant_consolidation_playbook.md— 7-phase playbook for the next Workspace tenant- ORA-2026-0036 — credential-gate atomicity (sibling)
- ORA-2026-0044 — names carry contracts (registry naming)
- ORA-2026-0075 — credentials carry domain context (registry schema)
/Users/chadbarlow/Desktop/fleet/registries/credentials.md— the registry surface itself