# Attended OpenBao session — four open custody questions One founder-attended session that settles the questions currently blocking four owner threads. Everything in it is read-only against OpenBao. It provisions nothing, approves nothing, and rotates nothing. Prepared 2026-09-09 under RPF-WP-0035. Not yet run. ## Why a session rather than a reply Four owner threads are each blocked on a fact that only an authenticated read can establish, and each has been answered so far with "I will not guess": | Question | Thread | What is undecidable from repo source | | --- | --- | --- | | Q1 | secrets-engine `546403e4` | Whether the legacy path `secret/coulomb/whynot-design/npm/publish` still exists and holds a real token | | Q2 | secrets-engine `546403e4`, ops-warden `b6212006` | Which field backs the authoritative npm lane. Two dated live receipts here name `NPM_AUTH_TOKEN`; secrets-engine says `npm_token` and ops-warden has already changed their catalog to it. Both can be true if the path carries both fields. Field names are not visible in KV v2 metadata | | Q3 | internal | The 2026-09-09 activation receipt records `policy_applied: false` for both KeyCape approval lanes while `role_applied: true`. Reads verified, so the policies must exist — but existence and repo agreement were never confirmed | | Q4 | CCR-2026-0019 | Which netkingdom OIDC roles and bound group claims already exist, as input to the operator group claim that lane is missing | | Q5 | risk-nexus `ee702ac9` | Which fields the governed backup lane actually carries, as RPF-WP-0029-T02 context | ## Authority and containment Authority is the governed `openbao-platform-admin-login` lane: `founder_required`, attended OIDC through `bao login -method=oidc -path=netkingdom role=platform-admin`. The owner command is never run directly. ```sh make openbao-open-questions SESSION_RECEIPT=/tmp/.json ``` Use the Make target rather than typing the underlying command: it is short enough not to be broken by terminal wrapping, it refuses a `SESSION_RECEIPT` that already exists or is missing, and it clears any ambient token before invoking the envelope. `scripts/openbao-attended-exec.py` supplies the WSL browser launcher and then `exec`s into `warden access openbao-platform-admin-login --exec`, so Warden keeps the envelope: it captures both streams, owns the temporary token helper and self-revokes when the command returns. Use a receipt path that does not exist — the writer opens it `O_EXCL` at mode 0600 and refuses to overwrite. The runner prints nothing. Its entire output is the receipt. **To settle the npm field alone**, run only the two questions that bear on it: ```sh make openbao-open-questions SESSION_QUESTIONS=Q1,Q2 SESSION_RECEIPT=/tmp/.json ``` `--questions` defaults to all five. Q5 is the only step that reads the backup lane, so naming a subset is also how to exclude it. **Ambient-token guard.** The Make target clears these before invoking the envelope; the runner independently refuses to start if `OPENBAO_TOKEN`, `BAO_TOKEN` or `VAULT_TOKEN` is set in the environment. A standing token would let these reads succeed without the attended login, producing a receipt that looks attended and is not. Unset it first; the envelope supplies the identity. `--allow-ambient-token` overrides, and then the receipt records `attended_identity: false` — which is the honest label for that read, not a formality. ## What the runner reads, and the one honest caveat | Step | Call | Emitted | | --- | --- | --- | | Q1 | `secrets list`, then `kv metadata get` on the legacy path if the mount exists | mount present, path present, current version, created/updated time | | Q2 | `kv get` on `platform/workloads/coulomb/whynot-design/npm-publish` | **sorted field names only**, plus KV version | | Q3 | `policy read` for both KeyCape approval policies | present, matches-repo-source, sha256 of each normalized text | | Q4 | `list auth/netkingdom/role`, then `read` each | role names, bound claims, groups/user claim, token policies, TTL | | Q5 | `kv get` on `platform/workloads/railiance/backup/offsite-lane` | **sorted field names only**, plus KV version | **The caveat, stated plainly:** Q2 and Q5 are data reads. Field names cannot be obtained from KV v2 metadata, so the value transits the runner's memory. It is never printed, never passed on argv, never written to disk, and never placed in the receipt — `field_names()` returns key names and the values go out of scope with the function. If that is not acceptable for the backup lane in particular, drop Q5: it is context for RISK-F-0010, not a dependency of it. For Q5 the receipt records `predecessor_material_recorded: false`, and no value, fingerprint, length or shape of any predecessor credential is captured — which is the constraint risk-nexus set. ## What each answer unblocks - **Q1 + Q2 → secrets-engine and ops-warden.** Q2 is now the more urgent of the two. ops-warden changed their catalog and playbook from `NPM_AUTH_TOKEN` to `npm_token` on secrets-engine's statement, while this repository holds two dated live receipts — including an attended founder fetch that exited zero — naming `NPM_AUTH_TOKEN` as the field. If those receipts are right, that change points the front door at a field that does not exist and the lane breaks on next use. Q2 enumerates the real field names: `npm_token` only, `NPM_AUTH_TOKEN` only, or both, and each outcome names exactly one side that has to move, as a reviewed lane change carrying its own approval. If Q1 finds a populated legacy path, that is a stale duplicate holding a real token and becomes its own disposition item — do not delete it inside this session. - **Q3 → internal.** Either the policies match the repo, and the activation's `policy_applied: false` meant "no change needed", or they drift and that is a finding to fix under RPF-WP-0035 before anyone treats the verifier lanes as clean. - **Q4 → CCR-2026-0019.** Existing bound claims show what the estate already uses for operator lanes. This is **input, not confirmation** — the authorized group claim is NetKingdom's and KeyCape's to state, and the receipt says so in-line so a later reader cannot mistake the listing for an approval. - **Q5 → risk-nexus.** Confirms the governed lane is populated with the expected field names, supporting the fail-closed argument already made on that thread. ## Explicitly out of scope - **The rapp-qonto KeyCape client rotation** (ops-warden `c1aafba4`). It is a two-custodian CAS write with a service restart and needs its own reviewed request first. Do not fold it into a read-only session because the operator happens to be authenticated. - **Predecessor share invalidation** for RPF-WP-0029-T02. That is a provider-side action in the Nextcloud UI, not an OpenBao operation, and it needs the provider owner. It can share the same sitting, but it is a separate step with a separate receipt. - **Any write, seed, rotation or policy apply.** The runner contains no mutating verb; if a question turns out to need one, it comes back as a request. - **Client-side reads for the approval clients.** CCR-2026-0019/0020 remain in_flight; this session does not advance them beyond Q4's input. ## After the session 1. Store the receipt under `docs/evidence/` with the run date, values absent. 2. Reply to secrets-engine (Q1/Q2), risk-nexus (Q5) and, if Q3 drifts, record the finding against RPF-WP-0035. 3. If Q1 finds a populated legacy path, open a disposition item for it rather than acting on it in the moment.