CUST-WP-0075: tenant-engine sender seed helper; re-qualify RPF-WP-0035-T02/T08
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Has been cancelled

- scripts/tenant_engine_audit_core_sender_seed.py: silent attended row-7 seed
  for MASON-WP-0007-T05 (wrap-migrate technique, CAS 0, never overwrites,
  metadata-only --dry-run, documented exit codes), with offline fake-bao tests.
- Lane review doc with the exact founder sequence and the read-only ESO
  token-create can-i check for MASON-WP-0007-T06.
- RPF-WP-0035-T02: SECRETS-WP-0007-T04 is done; real blocker is live KeyCape
  registration and client custody of secrets-engine-openbao (blocked_on
  key-cape). Design stays proposed.
- RPF-WP-0035-T08: receiver rollout with evidence_kind already accepted
  2026-09-11; moved the misplaced D1 correction note here from T02.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3775@bnt-lap001
Assistant-Session: cfacb6a5-ad5b-4f79-ac67-053e3b0d34a3
This commit is contained in:
codex 2026-10-03 08:28:32 +02:00
parent 401765f184
commit e7eb9db57e
6 changed files with 512 additions and 3 deletions

View file

@ -120,3 +120,12 @@ then perform the positive/negative/expiry/use-limit/revocation checks above.
Do not print login responses. Publish the consumer contract only after those
checks pass. A conflicting existing mount/role requires review, not overwrite.
No service-client secret is created, moved or requested by this source return.
## Gate check — 2026-10-03 (CUST-WP-0075)
Still proposed. SECRETS-WP-0007-T04 is done (2026-09-27), so the gate named
above is open, but the "before writing" preconditions are not: KeyCape has not
claimed a live registration of `secrets-engine-openbao`, and its client-credential
custody has no owning task (KeyCape contract: "a separate approved custody
action"). No reviewed child is written. RPF-WP-0035-T02 waits on key-cape naming
that task.

View file

@ -0,0 +1,93 @@
# tenant-engine audit-core sender: attended seed
Status: ready for review, not run. Owner: railiance-platform (OpenBao side) for
ops-mason MASON-WP-0007-T05 (plan row 7). Intake RPF-IN-0002. Prepared
2026-10-03 under CUST-WP-0075.
## What the founder approves
One attended sitting, run from a railiance-platform checkout at the reviewed
commit, with these three children in order. Each child prints nothing; read
warden's printed line, not its exit code (orientation §5).
```sh
cd ~/railiance-platform
export BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200
# 1. policy + Kubernetes-auth role (commit 8c44256). Exit 3 = existing object differs.
warden access openbao-platform-admin-login --exec -- \
sh scripts/openbao-tenant-engine-audit-core-sender-eso-attended.sh
# 2. seed dry-run: KV metadata only, no value read or written.
warden access openbao-platform-admin-login --exec -- \
python3 scripts/tenant_engine_audit_core_sender_seed.py --dry-run \
--confirm 'SEED tenant-engine audit-core-sender' \
--receipt docs/evidence/tenant-engine-sender-seed-dry-run.json
# 3. seed: only if step 2's receipt says outcome dry_run_would_write (exit 0).
warden access openbao-platform-admin-login --exec -- \
python3 scripts/tenant_engine_audit_core_sender_seed.py \
--confirm 'SEED tenant-engine audit-core-sender' \
--receipt docs/evidence/tenant-engine-sender-seed.json
```
Each `warden access` is its own login. Receipts are created mode 0600, refused
if the file exists, and hold only paths, versions, booleans and an outcome
code. Commit them as evidence.
## What the seed does
`scripts/tenant_engine_audit_core_sender_seed.py` is the user-engine /
audit-core wrap-migrate technique (ops-mason
`plans/user-engine-openbao-runtime-custody.md` §6; audit-core runbook,
"wrap-migrated on 2026-08-14"): one platform-admin process reads the source and
writes the target, and the value travels only through process memory and the
`bao` child's stdin. Never argv, stdout, stderr, a file or the receipt.
1. Refuses unless `--confirm` is exact, HOME is a warden attended envelope, no
`BAO_TOKEN`/`VAULT_TOKEN` is set, and the identity has `platform-admin` and
not `root`.
2. Reads `platform/workloads/audit-core/senders` (KV v2, field `senders.json`)
and selects the one row named `tenant-engine`. Refuses if the row is
missing or duplicated, holds zero or more than one token (a rotation
overlap is in progress: finish it first), or is not write-only
(`may_write` true, `may_read` false).
3. If `platform/workloads/tenant-engine/audit-core-sender` exists: exit 0 when
it holds exactly `{token: <that token>}`, otherwise exit 3. Never overwrites.
4. Otherwise writes `{token}` with `cas=0`, reads it back (must be version 1 and
equal), and checks that the registry version did not move during the run.
The registry is never written. Exit codes: 0 ok (written or already
identical; dry-run: would write), 1 contained internal error, 2 precondition
refused before any write, 3 target exists and differs, 4 write failed,
5 verify failed, 6 dry-run found the target already present.
Tests: `tests/test_tenant_engine_audit_core_sender_seed.py` runs the helper as
a subprocess against a fake `bao` and asserts empty stdout/stderr, the token
never in `bao` argv or the receipt, CAS 0, idempotence, refusal of a differing
or deleted target, every precondition, and distinct write/verify codes.
## Operator check for MASON-WP-0007-T06 (read-only, not run)
Before the tenant-engine ClusterSecretStore goes live, the ESO controller must
be allowed to create ServiceAccount tokens in `tenant-engine`. Confirm the node
IP is `92.205.62.239` first (`kubectl get nodes -o wide`), then:
```sh
kubectl auth can-i create serviceaccounts --subresource=token \
-n tenant-engine --as=system:serviceaccount:external-secrets:external-secrets
```
`yes` is required. This is a SubjectAccessReview: it reads no object. A `no`
is a railiance-cluster RBAC matter, not a reason to widen the OpenBao role.
## Follow-ups outside the seed
- `openbao/policies/agent-high-risk-boundary.hcl` denies coding agents the
sender registry, but not the new
`platform/{data,metadata}/workloads/tenant-engine/audit-core-sender` paths.
Adding those deny lines is a separate reviewed policy change.
- Rotation stays overlap-first (plan §4): rotate in the registry, finish the
overlap so the sender holds one token, then re-seed. Because this helper
never overwrites, a rotated token needs a reviewed CAS-update variant. That
variant is not built.