# Catalog Lane Promotion — draft → active Date: 2026-07-01 Workplan: WARDEN-WP-0023 T05 `registry/routing/catalog.yaml` entries start as **`draft`** until an owner-confirmed concrete path exists. Draft lanes are hidden from default `warden route find` unless `--all` is passed. --- ## Promotion checklist Before changing `status: draft` → `status: active`: | # | Criterion | Evidence | | --- | --- | --- | | 1 | **Owner confirmed** | Owner repo workplan or State Hub note naming the lane ready | | 2 | **Concrete path** | Real OpenBao path, grant id, or exec command — no unresolved `` in the primary handoff | | 3 | **Playbook** | `wiki/playbooks/.md` with `#worker-checklist` section | | 4 | **Exec routing** | `exec_owner` + native command **or** `exec_capable: true` with tested `warden access` proxy | | 5 | **Resolvable** | `warden route show --json` shows `resolvable: true` when placeholders are documented | | 6 | **Tests** | Routing test or smoke proving lookup + handoff shape (no secret values in fixtures) | | 7 | **Review date** | Update `reviewed:` in catalog entry | | 8 | **Verification** | Positive + negative proof via **`bao token capabilities`** — never `bao kv get` (see below) | | 9 | **Rotation guidance** | Secret-vending lanes carry a `rotation:` block; `warden rotate-guide ` returns steps. Enforced by the `catalog_rotation_coverage` scorecard check (WP-0026 T06) | | 10 | **Delegation** | Entry carries a `delegation:` block (WP-0030). `mode: permanent` only for ops-warden's own front door. `mode: native` when the owner already fronts it. `mode: interim` requires `intended_owner` and `blocked_on`; the promotion note must name both and the retirement condition | Promotion PR touches: `registry/routing/catalog.yaml`, playbook, optional `tests/test_routing.py`, and a one-line note in `wiki/CredentialRouting.md` draft table. If `delegation.mode` is `interim`, the promotion note (PR body or State Hub progress) must state: 1. who the intended owner is 2. what is missing (`blocked_on`) 3. what would let ops-warden step back (`exec_owner` + proven owner front door) A proxy that works is not enough to promote without answering the ownership question. `warden route gaps` must list the lane after merge if it is interim. --- ## Capabilities-safe lane verification (WARDEN-WP-0026 T01) **Verifying a lane must never read the secret *data*.** A negative deny-test that runs `bao kv get ` will, if the deny fails (e.g. a privileged token fallback), print the secret value into a logged context — this is exactly the 2026-07-16 CCR-2026-0004 disclosure. Prove *allow/deny* with `bao token capabilities`, which returns the capability list, not the value. For KV v2, capabilities are checked against the **API data path** (`/data/`), not the `kv get` logical path. ```bash # Positive: the lane's own OIDC identity can read the data path. bao login -method=oidc -path=netkingdom role= # caller identity bao token capabilities "$(bao print token)" platform/data/ # → expect the list to include: read # Negative: a default-only identity is denied — no value is ever read. DEFAULT_TOKEN=$(bao token create -policy=default -field=token) # if denied, STOP — do not fall back bao token capabilities "$DEFAULT_TOKEN" platform/data/ # → expect: deny ``` - **Never** substitute `bao kv get` for the checks above. Reading a value to "confirm it's there" is the anti-pattern; presence is proven by `read` in the capability list. - If `bao token create -policy=default` is itself denied for your identity, that is a *pass for the deny direction* — **do not** fall back to your privileged login token to force the read. - Fetching a value **for use** (`--field` into an env var or file, or `warden access … --field`) is a separate, intended action — not verification. Record the capability lists (allow/deny) as the promotion evidence; they contain no secret material and are safe for CCRs, State Hub, and Git. --- ## Worked examples (already active) **`ops-warden-warden-sign-token`** — promoted 2026-07-01 after RAILIANCE-WP-0005: - Owner: `railiance-platform` credential broker - Concrete grant: `ops-warden/warden-sign` - Playbook: `wiki/playbooks/ops-warden-warden-sign-token.md` - Smoke: `make credential-exec-ops-warden-smoke` **`issue-core-ingestion-api-key`** — promoted 2026-07-02 after RAILIANCE-WP-0009 (CCR-2026-0002): KV path live, ExternalSecret `issue-core/issue-core-runtime` SecretSynced, positive + negative verification audit-logged. **`openrouter-llm-connect`** — promoted 2026-07-02 after RAILIANCE-WP-0010 (CCR-2026-0003): KV path live, ExternalSecret `activity-core/llm-connect-provider-secrets` SecretSynced, llm-connect rolled out on the OpenBao-delivered value, positive + negative verification audit-logged. --- ## Draft lanes (2026-07-17) | Catalog `id` | Blocker | | --- | --- | | `object-storage-sts` | NK-WP-0007 vending path not production-exercised | | `database-dynamic-credentials` | OpenBao database engine role paths TBD per workload | **Promoted 2026-07-16:** `railiance-backup-offsite-lane` — CCR-2026-0004 capabilities-safe re-verify (WP-0026 T07); primary field `NC_WEBDAV_TOKEN`; `risk: high` + EXPOSED taint on version 2 (operator may rotate optionally). **Promoted 2026-07-17:** `binky-company-email-imap` — CCR-2026-0007 on mount `tenants/`; founder provisioned (KV version ≥2); capabilities-safe verify; primary field `IMAP_PASSWORD`; `risk: high`. Host `imap.ionos.de:993`. **Tenant path (WP-0028):** new client secrets use mount `tenants/`, not `platform/workloads/`. See `wiki/playbooks/tenant-secret-onboarding.md`. Re-run promotion when the owning repo closes the blocker; do not promote on playbook prose alone. --- ## See also - `wiki/CredentialRouting.md` — draft table index - `wiki/playbooks/ops-warden-warden-sign-token.md` — promotion reference - `wiki/AccessRouting.md#interim-custodianship` — delegation register doctrine - `warden route gaps` — queryable interim register