railiance-platform/docs/openbao-open-questions-session.md
codex f0c2fd58cd
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Prepare the read-only attended session for four open custody questions
Four owner threads are each blocked on a fact only an authenticated read can
establish: whether the legacy whynot-design npm path still exists, which field
backs the authoritative lane, whether the two KeyCape approval policies match
repo source after an activation that recorded policy_applied false, which
netkingdom bound group claims already exist as input to CCR-2026-0019, and which
fields the governed backup lane carries.

Adds scripts/openbao_open_questions_session.py, which contains no mutating bao
verb and emits only a mode-0600 metadata receipt, plus the run-book in
docs/openbao-open-questions-session.md. Field-name resolution is a data read, so
the runner returns sorted key names and no value reaches argv, disk or the
receipt; that caveat is stated rather than glossed.

Not run. The rapp-qonto rotation and the RPF-WP-0029 provider invalidation are
explicitly out of scope.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLUjpv3ssxNRAEPPgLFnEB

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1275505@bnt-lap001
Assistant-Session: 97265baa-f08f-4032-b290-a1e2965a69c5
2026-09-09 20:07:51 +02:00

6 KiB

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 Which field backs the authoritative npm lane. My CCR says NPM_AUTH_TOKEN; secrets-engine says npm_token. 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.

scripts/openbao-attended-exec.py -- \
  /usr/bin/python3 /home/worsch/railiance-platform/scripts/openbao_open_questions_session.py \
  --receipt /tmp/<new-unique-name>.json

scripts/openbao-attended-exec.py supplies the WSL browser launcher and then execs 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.

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. A pointer plus a field name closes their custody question. If Q2 returns npm_token, my CCR-2026-0001 is wrong about the field and I correct it; if it returns NPM_AUTH_TOKEN, their catalog entry is the one that moves, 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.