T04 was the last open task, waiting on key-cape to accept or refuse ownership of the coding-agent OpenBao issuance identity. They accepted, in KEY-WP-0009-T03, on 2026-08-23: codex-railiance-platform is published in their config/service-clients.example.yaml with subject service:codex:railiance-platform, role coding-agent, scope openbao:login, 15m lifetime, and the service-auth semantics in docs/openbao-service-auth-contract.md. The split is the one we routed for — KeyCape issues, railiance-platform binds the OpenBao role, OpenBao enforces, no secret value in either repo. We found it by reading their repository. KEY-WP-0009-T04 records replying to ops-warden; the inbox has zero messages from key-cape, read or unread. The task sat `wait` on an answer that already existed. That is T05's own lesson arriving on T04: a blocker is a claim about the world at a date. So the same pass re-verified the two lanes pointing at key-cape against their source instead of bumping dates: - rapp-qonto-keycape-client -> verified: source-read. KEY-WP-0009-T02 did add bounded service-auth, but that is client_credentials JWT issuance for OpenBao machine login and does not front this client_secret_basic exchange or its rotation. Blocker stands, now with evidence rather than memory. - key-cape-oidc-login -> asked of key-cape today, which the entry had recorded as still outstanding since 2026-08-21. Also cleared the inbox that hid this: 9 stale unread, all superseded by shipped work, with late closes sent to secrets-engine and llm-connect on the two threads that had asked ops-warden something and never got an answer. 391 tests pass, ruff clean, boundary coverage 0 uncovered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ Assistant: claude-code Assistant-Model: opus Assistant-Process: 4014535@bnt-lap001 Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
344 lines
17 KiB
Markdown
344 lines
17 KiB
Markdown
---
|
|
id: WARDEN-WP-0033
|
|
type: workplan
|
|
title: "Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed"
|
|
domain: infotech
|
|
repo: ops-warden
|
|
status: finished
|
|
owner: ops-warden
|
|
topic_slug: netkingdom
|
|
planning_priority: P1
|
|
depends_on_workplans:
|
|
- WARDEN-WP-0030
|
|
created: "2026-08-21"
|
|
updated: "2026-08-28"
|
|
state_hub_workstream_id: "4627d89b-4b00-562a-81e9-76e96f90fa7e"
|
|
---
|
|
|
|
# WARDEN-WP-0033 — Native lane handoff
|
|
|
|
On 2026-08-20 `secrets-engine` accepted five of ops-warden's seven interim
|
|
proxy lanes for catalog admission (`SECRETS-WP-0006`, decision
|
|
`ae676382-1826-4e04-aa4e-bb77990c7a0d`), rejected two with reasons ops-warden
|
|
agrees with, drafted the five entries itself rather than waiting for the offered
|
|
contribution, and asked for a line-by-line review of the non-secret metadata.
|
|
|
|
In the same hour `railiance-platform` closed the `RISK-F-0009` coverage gap and
|
|
asked ops-warden for two things back.
|
|
|
|
This workplan is the response to both, plus the defect the review turned up in
|
|
ops-warden's own grading model — which is the most consequential item here and
|
|
would not have been found without the second pair of eyes.
|
|
|
|
## Why a workplan and not an adhoc
|
|
|
|
Four counterparties are waiting, one deliverable is a **cross-repo interface**
|
|
another repo will consume on a schedule, and the review carries approval
|
|
semantics — `secrets-engine` holds interim proxy ownership open until each lane
|
|
has approved native verification. The convention reserves adhocs for low-risk
|
|
work completed directly; this is none of those.
|
|
|
|
## Tasks
|
|
|
|
```task
|
|
id: WARDEN-WP-0033-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "154f2f03-387d-5fe6-a0f5-1929c46a2bd8"
|
|
```
|
|
|
|
**Review the five drafted catalog entries and reply.**
|
|
`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`,
|
|
`openrouter-llm-connect`, `forgejo-admin-api-token`,
|
|
`email-connect-transactional` at `secrets-engine@784be97`.
|
|
|
|
Review the axes they asked for: owner-repo coordinates, field grouping, workload
|
|
consumers, rotation/deactivation owners, delivery intent. Verify claims against
|
|
the authoritative `railiance-platform` CCRs — **never against a secret read**;
|
|
`bao kv get` on any of these paths is the 2026-07-16 vector and three of the five
|
|
are `risk: high`.
|
|
|
|
Accept their two rejections. `openbao-api-key` is a routing template rather than
|
|
one lane and `key-cape-oidc-login` belongs to key-cape — that is `ADR-0005`
|
|
applied to ops-warden by someone else, correctly.
|
|
|
|
```task
|
|
id: WARDEN-WP-0033-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "6996d07f-63bb-5708-a171-68c4b1bbddde"
|
|
```
|
|
|
|
**Correct ops-warden's per-path risk grading — the defect T01 exposed.**
|
|
|
|
`secrets-engine` graded `issue-core-ingestion-api-key` **high**; ops-warden grades
|
|
it **standard**, and deliberately: WP-0032-T05 regraded it *down* on 2026-08-19,
|
|
operator-sanctioned, because `test_high_risk_lanes_classified` asserted standard
|
|
and was judged right — "ordinary internal workload secrets are standard".
|
|
|
|
That reasoning was incomplete, and CCR-2026-0002 says so explicitly: the path
|
|
carries **both** `ISSUE_CORE_API_KEY` **and** `GITEA_BACKEND_TOKEN`, a Forgejo
|
|
backend token, and the CCR records keeping both as a deliberate field-set
|
|
decision.
|
|
|
|
**The root cause is structural, not a single bad call.** ops-warden grades a
|
|
*lane* by its headline field — the catalog carries one `fetch_command` naming one
|
|
field and no `fields` list at all — but the disclosure unit is the **path**: a
|
|
`bao kv get` returns every field stored there. So a lane can be graded on its
|
|
least dangerous contents. `ADR-0007` says every lane carries an explicit grade;
|
|
it does not say the grade must cover everything a read of that path would
|
|
disclose, and it should.
|
|
|
|
Fix the grade, then fix the model that produced it: record `fields` per lane and
|
|
grade on the union. Check the other 25 lanes for the same shape.
|
|
|
|
**Done 2026-08-21 — and it was two lanes, not one.** While verifying
|
|
`reuse-surface-hub-write-token` I told secrets-engine their second field was
|
|
unevidenced and asked them to confirm it. It was evidenced: `CCR-2026-0005`'s
|
|
`kv_path` block lists both fields and its notes describe the HMAC's alignment
|
|
with Forgejo org webhook id=1. A truncated grep, and a retraction sent within
|
|
twenty minutes so they would not spend time on it. That lane was under-graded on
|
|
exactly the same reasoning, and both had been regraded *down* in the same T05
|
|
pass — which is what makes this a systematic flaw rather than one bad call.
|
|
|
|
Blast radius checked and bounded: of the 8 remaining `standard` lanes, 6 have no
|
|
KV path at all (SSH, policy check, tunnel, principals, issue-sink, key-cape
|
|
login) so nothing is disclosed by a read. Two do have paths and no CCR field
|
|
evidence — `rein-openweights-openrouter-approle` and `coulomb-social-runtime-env`
|
|
(a whole k8s env Secret, which by shape almost certainly holds several fields).
|
|
Deliberately **not** regraded: `ADR-0008` §3 says an unknown field set is stated
|
|
rather than assumed, and grading is operator-sanctioned judgement, not backfill.
|
|
They are the open item on this task.
|
|
|
|
Shipped: both regrades with their evidence and the superseded reasoning kept
|
|
inline, `fields` recorded with its CCR source, the test that had been holding the
|
|
wrong answer inverted with an explanation of why it was wrong to trust it, and
|
|
**`ADR-0008`** — a lane's grade covers every field its path discloses. That is a
|
|
new binding rule, so it is a record rather than a wiki note.
|
|
|
|
```task
|
|
id: WARDEN-WP-0033-T03
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "a736f983-94da-5a4a-aaf9-5114485518a6"
|
|
```
|
|
|
|
**Emit the generated high-risk data-path artifact for `railiance-platform`.**
|
|
|
|
They asked for a versioned artifact of concrete high-risk data paths
|
|
(`id` + `data_path` + catalog revision) to consume instead of hand-maintaining
|
|
the deny list — the half of the `RISK-F-0009` fix ops-warden explicitly declined
|
|
to build *for* them. Emitting the artifact is not the same as amending their
|
|
policy: they still own what to deny. That boundary is the point of `ADR-0002`
|
|
and must survive this task.
|
|
|
|
Must be generated, never hand-edited, and must carry the catalog revision so a
|
|
consumer can tell what it was derived from. Depends on T02 — publishing the deny
|
|
set before fixing the grades would ship the wrong list to a consumer who will
|
|
apply it.
|
|
|
|
**Done 2026-08-21.** `scripts/emit_high_risk_paths.py` →
|
|
`registry/generated/high-risk-data-paths.yaml`: 19 high-risk lanes, 14 concrete
|
|
data paths, 5 with no single KV address listed separately so a consumer does not
|
|
read the absence as an omission. Carries `catalog_revision`, its date, and a
|
|
`catalog_dirty` flag — a revision that does not describe the file it came from is
|
|
worse than none.
|
|
|
|
The T02 dependency was not theoretical. The two regrades land in this artifact,
|
|
and `check_agent_read_boundary.py` now reports **2 uncovered** against a policy
|
|
railiance-platform closed to 0 yesterday. Emitting before regrading would have
|
|
handed them a list that confirmed a coverage claim that had just stopped being
|
|
true.
|
|
|
|
`fields` is emitted as `null` where no CCR declares the set, never as a
|
|
single-element guess — `ADR-0008` §3. Two CI tests: the artifact must be current,
|
|
and every high-risk lane must appear in it, so a lane graded high after the last
|
|
emit cannot silently fail to reach the consumer.
|
|
|
|
Boundary held: the header states this is an input and not a policy, and that
|
|
railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`).
|
|
|
|
```task
|
|
id: WARDEN-WP-0033-T04
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "5acac140-a586-5db3-b231-bbf236710786"
|
|
```
|
|
|
|
**Route the coding-agent issuance identity question.**
|
|
|
|
`RAILIANCE-WP-0017` is blocked on defining a distinct coding-agent issuance
|
|
identity and proving deny-wins when that identity is combined with workload read.
|
|
They asked ops-warden to route ownership.
|
|
|
|
Route it; do not absorb it (`ADR-0005`, `ADR-0003`). ops-warden owns actor
|
|
identity for `adm`/`agt`/`atm` **SSH certificates** and nothing else — a coding
|
|
agent's OpenBao issuance identity is an IAM question. The likely owner is
|
|
`key-cape`, with `user-engine` and `zone-engine` both plausibly involved. Say so
|
|
with reasoning rather than guessing, and record the answer either way.
|
|
|
|
Note the interaction with `ADR-0004`: the agent read-boundary already depends on
|
|
`WARDEN_AGENT_ID` being set, which is an honour-system marker on the ops-warden
|
|
side. A real issuance identity is what would make that boundary hold on the
|
|
OpenBao side too, so ops-warden is an interested consumer, not a bystander.
|
|
|
|
**Routed 2026-08-21 to `key-cape` (msg 903b2223); waiting on accept or refuse.**
|
|
Reasoning given: it is an identity and issuance question about a principal
|
|
authenticating to OpenBao, which is key-cape/Keycloak's. The precedent is an hour
|
|
old and runs the same direction — `secrets-engine` declined `key-cape-oidc-login`
|
|
as ops-warden's to hand them, on the grounds that login and identity-token
|
|
issuance stay with key-cape. Absorbing this would contradict agreeing with them.
|
|
|
|
Named the adjacent parties explicitly rather than leaving them to inference:
|
|
`zone-engine` has an interest (a coding-agent identity is a strong candidate zone
|
|
subject) and `user-engine` is **not** involved — this is a machine principal, not
|
|
an end-user account. Stated so nobody concludes it by elimination.
|
|
|
|
Asked for a refusal-with-pointer as an equally good answer. The failure mode to
|
|
avoid is the 2026-08-17 one recorded in `.claude/rules/finding-routing.md`:
|
|
ops-warden answered a question well and never routed it, and another repo ended
|
|
up filing it.
|
|
|
|
**Followed up 2026-08-23 after the immediate enforcement gap closed.**
|
|
`RAILIANCE-WP-0022` no longer waits for this ownership decision: the platform
|
|
owner deployed a dedicated coding-agent AppRole, proved deny-wins when it is
|
|
combined with workload read, and identified an exact-bound KeyCape JWT role as
|
|
the migration target. That makes the remaining question narrower and more
|
|
important rather than obsolete: who owns issuance of the durable
|
|
KeyCape/Keycloak-backed machine identity?
|
|
|
|
Direct follow-up `d25d4604-5713-42a8-8e3a-1ea31b5a5cc7` asks `key-cape` to
|
|
accept that target identity with an authoritative workplan/interface, or refuse
|
|
and name the actual owner. T04 remains `wait` until one of those two answers is
|
|
recorded; the live AppRole is operational evidence, not an ownership answer.
|
|
|
|
**Answered — accepted. Closed 2026-08-28.** `key-cape` accepted issuance
|
|
ownership in `KEY-WP-0009-T03` (`status: done`, 2026-08-23): the non-secret static
|
|
registration `codex-railiance-platform` is published in
|
|
`key-cape/config/service-clients.example.yaml` — subject
|
|
`service:codex:railiance-platform`, tenant `tenant:coulomb`, role `coding-agent`,
|
|
scope `openbao:login`, `client_credentials`, 15-minute lifetime — with the
|
|
service-auth claims, renewal, expiry and failure semantics in
|
|
`key-cape/docs/openbao-service-auth-contract.md` (`T02`). The split is exactly the
|
|
one the routing asked for: KeyCape owns JWT issuance and client disablement,
|
|
railiance-platform owns the exact-bound OpenBao role and policy, OpenBao owns
|
|
enforcement, and no secret value enters either repository.
|
|
|
|
**The answer was found by reading their repo, not by receiving it.**
|
|
`KEY-WP-0009-T04` records replying to ops-warden; no such message exists in the
|
|
ops-warden inbox — 0 messages from `key-cape`, read or unread. The acceptance had
|
|
been sitting done for five days while this task sat `wait` on it.
|
|
|
|
That is the T05 lesson landing on T04: a blocker is a claim about the world at a
|
|
date, and this one had stopped being true. `verified: source-read` is doing real
|
|
work here — it is the difference between "we asked" and "we checked". The
|
|
mechanism is right; what it needs is for someone to run it, which is why the
|
|
lanes below were re-verified in the same pass rather than date-bumped.
|
|
|
|
Consequence for `ADR-0004`: the honour-system `WARDEN_AGENT_ID` marker now has a
|
|
real issuance identity behind it on the OpenBao side. ops-warden remains a
|
|
consumer of that identity and does not own it.
|
|
|
|
```task
|
|
id: WARDEN-WP-0033-T05
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "75051d17-399b-5129-860b-ae00dae91c47"
|
|
```
|
|
|
|
**Make blocker staleness a mechanism instead of an intention.**
|
|
|
|
Four stale blockers surfaced in twelve hours: an OpenBao token recorded expired
|
|
that was valid, a verification script recorded ready that had never been written,
|
|
a ten-day `secrets-engine` question answerable from their source, and
|
|
`FLEX-WP-0007` cited as blocking `policy.enabled` seven weeks after it read
|
|
`finished`. `.claude/rules/finding-routing.md` has said *re-read a blocker before
|
|
trusting it* since `RISK-F-0001`. Saying it has not worked.
|
|
|
|
`warden route gaps` had a `--stale-days` threshold defaulting to 90, which was
|
|
not loose but **inert** — the register was created 2026-08-15, so it could not
|
|
fire before November.
|
|
|
|
**Done 2026-08-21.** Two changes, and the second matters more:
|
|
|
|
1. **Split the cadences.** `DEFAULT_STALE_DAYS` (90) still governs pointer
|
|
freshness — "is this the right owner and page" genuinely is quarterly. New
|
|
`DEFAULT_BLOCKER_STALE_DAYS` (14) governs interim blockers, calibrated on the
|
|
cases that cost something: ten days for the secrets-engine lanes, one day for
|
|
`RISK-F-0001`, ~50 for `FLEX-WP-0007`. At ~15 lanes it surfaces about one a
|
|
day rather than a wall, and it fires on zero lanes on age today.
|
|
|
|
**Then scaled by risk, after risk-nexus answered.** They accepted the offer to
|
|
converge and published their convention: 14 days critical/high, 30 medium, 60
|
|
low, with fix state *read* from the owning repo rather than remembered. Their
|
|
framing — "point `warden route gaps` at those windows and the two will agree
|
|
without either of us building a shared mechanism" — is better than a joint
|
|
tool, so `blocker_stale_days()` now maps lane `risk` onto exactly those
|
|
windows. `ungraded` takes the *shortest*, not the longest: `ADR-0007` makes an
|
|
absent grade a defect, so its blocker is the least trustworthy of all.
|
|
|
|
2. **`verified:` distinguishes re-checking from re-editing.** `reviewed` records
|
|
when someone touched the entry; nothing recorded whether the claim was
|
|
re-established. `owner-confirmed` and `source-read` count;
|
|
**`asked-and-waiting` and `unverified` do not**, and a lane in those states is
|
|
stale regardless of its date. `key-cape-oidc-login` is the proof: asked today,
|
|
zero days old, correctly flagged.
|
|
|
|
Current state: 14 non-draft interim lanes — 5 `owner-confirmed`, 1
|
|
`asked-and-waiting`, 8 `unverified`. The 8 are honest; they were carried forward
|
|
this session without a check and now say so instead of hiding behind a fresh date.
|
|
|
|
`--fail-on-stale` exits 3 so a cron job or gate can act. **Deliberately not a CI
|
|
test on age**: a date-triggered failure breaks the build on a calendar day with
|
|
no code change, punishing whoever commits next rather than whoever owns the
|
|
blocker. The CI test is structural instead — every interim lane must record
|
|
*how* it was verified, which fails on the commit that introduces the omission.
|
|
|
|
```task
|
|
id: WARDEN-WP-0033-T06
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "94f77f5a-f919-5328-832c-ba1d24c6431b"
|
|
```
|
|
|
|
**Correct first-time OpenBao administration routing.** `rapp-postgres` reported
|
|
on 2026-08-22 that `warden plan` mapped first-time
|
|
`database/config/platform-pg-2` administration to the generic
|
|
`openbao-api-key` template. It consequently proposed paste-once KV provisioning
|
|
and a workload OIDC role, neither of which can configure database connections,
|
|
policies, auth roles, or token roles. Their Desk session stopped without an
|
|
approval or secret action.
|
|
|
|
The authoritative platform runbook and rapp-postgres's live T04 evidence agree
|
|
on the missing distinction: this is one attended KeyCape-backed OpenBao identity
|
|
act at auth mount `netkingdom`, role `platform-admin`. It is not a credential
|
|
value handoff. Root stays offline break-glass authority and a workload role must
|
|
never be widened to make the operation pass.
|
|
|
|
Add an exact `openbao-platform-admin-login` lane, an operator playbook, and a
|
|
regression that makes the reported request resolve to `founder_required` with
|
|
`oidc_login` — never `paste_once_provision`. Verify the route, then return the
|
|
corrected non-secret command to rapp-postgres.
|
|
|
|
**Done 2026-08-22.** The new active lane resolves the exact reported request at
|
|
score 20, ahead of the generic KV template at 11, and returns one
|
|
`founder_required` act:
|
|
`bao login -no-print -method=oidc -path=netkingdom role=platform-admin`.
|
|
Planner output offers only `warden access openbao-platform-admin-login --fetch`
|
|
and the exact owner command; login lanes no longer inherit secret-value
|
|
transports (`--exec`, `--out`, `--wrap`). The lane is explicitly a high-risk,
|
|
non-workload human identity act, so the generated boundary artifact lists it as
|
|
having no KV address rather than inventing one.
|
|
|
|
Verification: 384 tests pass, Ruff passes, workload accounting resolves all 28
|
|
lanes (3 resolved, 17 unknown, 8 not-applicable), and the boundary invariant
|
|
reports 20 high-risk lanes, 14 concrete paths covered, 6 non-KV/pattern lanes,
|
|
0 uncovered. No login or credential action was performed.
|
|
|
|
## Related
|
|
|
|
- `secrets-engine` `SECRETS-WP-0006` — catalog admission, decision `ae676382`
|
|
- `RISK-F-0009` — closed by railiance-platform 2026-08-21; 0 uncovered
|
|
- `railiance-platform` `RAILIANCE-WP-0022` (boundary coverage), `RAILIANCE-WP-0017`
|
|
- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0007`
|
|
- `WARDEN-WP-0030` — the delegation register these five lanes retire from
|