railiance-platform/docs/credential-lane-designs/factory-audit-senders-review.md
codex 005c68eb4c
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Record native sender acceptance and retained audit readback gate
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
2026-09-11 14:23:07 +02:00

174 lines
9.4 KiB
Markdown

# Factory audit senders: concrete custody review
CCR-2026-0021 and CCR-2026-0022 were **approved** by the user on 2026-09-11,
replying "good, go on" to the explicit question naming the platform operator,
Audit Core owner, and each producer owner. The source review comments and the
two existing State Hub decisions record that approval. RPF-WP-0035-T08 owns
platform execution; AUDIT-WP-0009-T09/T11 retain receiver admission. Approval
alone does not mark custody delivered or either producer admitted.
## Approved scope
| Request | Producer / exact source | OpenBao path | Producer Secret / key |
| --- | --- | --- | --- |
| CCR-2026-0021 | approval-engine | platform/workloads/approval-engine/audit-sender | approval-engine/approval-engine-audit / audit-token |
| CCR-2026-0022 | informed-decision | platform/workloads/informed-decision/audit-sender | informed-decision/informed-decision-audit / token |
Each sender is limited to `tenant:platform`, write true, read false,
`evidence_kind: load-bearing`, `secret_policy: redact`. The producer receives
only its own `AUDIT_TOKEN`. `CUSTODY_REQUEST` is a non-secret provenance marker
stored beside that token, enabling an interrupted first provision to identify
its own version-1 value. It is not projected to the producer.
Each lane has its own exact-path policy, Kubernetes auth role and namespace-
restricted ClusterSecretStore. Only `external-secrets/external-secrets` may
log in to the reader role (15-minute session). Neither producer can read the
full sender registry or its sibling's token. The coding-agent boundary gains
exact denies on the two new data/metadata paths; existing rules are preserved.
The approved first-provision operation generates two independent values
in the attended platform process, store them with CAS=0, and append the exact
identities to `platform/workloads/audit-core/senders` with compare-and-set on
its observed KV version. That process necessarily reads the existing registry
in memory; it never emits its credentials or gives it to a producer. No token
passes through Git, a Hub record, command arguments or stdout/stderr.
## Historical receiver finding (resolved before custody)
On 2026-09-11 the native receiver is 1/1 Ready on
`forgejo.coulomb.social/coulomb/audit-core@sha256:c2fe39a0185b99be3fc0cb14d2de69772b8e66e20490097c9d11d90cc39719a6`.
Its `SenderIdentity` has **no evidence_kind support**. A synthetic registration
probe in the native pod fails the load-bearing contract; the same probe against
current Audit Core source passes. Readiness did not detect this contract gap.
`factory_audit_custody.py receiver-check` now enforces that contract before any
credential access. An approved CCR alone cannot bypass it. Audit Core must
build, publish, admit and roll out its current implementation and source scope
first. Its existing AUDIT-WP-0009-T09/T11 tasks retain that work; no completed
source task is reopened. No receiver restart or deployment was done here.
Approval Engine's namespace is also absent. Three of four ESO objects passed
server dry-run in their intended namespaces; its ExternalSecret was refused
because that namespace does not exist. This packet creates no namespace,
workload or network permission. Its owner must supply that prerequisite.
## Current execution status
Both independent version-1 credentials are provisioned and the authoritative
registry advanced with CAS 7→8, preserving existing senders and fields. The
fresh attended delivery retry completed at 2026-09-11 08:27 UTC: exact native
reader/scope/namespace checks passed; both ESO projections are Ready and match
custody; registry JSON matched before Audit Core reloaded. The temporary
namespace is absent and Warden exited 0 with session revocation confirmed.
The receiver is operational/durable and 1/1 Ready on c82e0442de0f.
Both CCRs remain **applied**. Native producer accepted/duplicate-after-restart
and receiver scope/read-refusal checks passed at 10:42 UTC. Independent archive
readback and audit bearer-revocation acceptance remain pending. The
completed reader-session revocation does not expire those audit bearers.
See the [seed](../evidence/2026-09-11-factory-audit-sender-seed.json) and
[native delivery](../evidence/2026-09-11-factory-audit-delivery-live.json) receipts.
Earlier failed login receipts remain historical. Do not repeat provisioning
or delivery for this unchanged successful result; continue producer acceptance.
## Executable sequence
Review the source and exact policies:
```sh
python3 scripts/credential-change.py render CCR-2026-0021
python3 scripts/credential-change.py render CCR-2026-0022
python3 scripts/factory_audit_custody.py plan
```
After a compatible receiver release, the credential-free check is:
```sh
python3 scripts/factory_audit_custody.py receiver-check \
--kubeconfig /operator/railiance-kubeconfig \
--expected-receiver-image forgejo.coulomb.social/coulomb/audit-core@sha256:ADMITTED_DIGEST \
--receipt /operator/unique-receiver-receipt.json
```
The seed command requires approved CCR files with all named owner reviews,
the expected image, exact Railiance cluster UID, ready/current pod, both target
namespaces and the Warden attended platform-admin login envelope. Route via
`warden route show openbao-platform-admin-login --json` before arranging access.
Use its installed attended wrapper; do not copy a token into the command.
Inside that envelope, invoke:
```sh
python3 scripts/factory_audit_custody.py seed \
--kubeconfig /operator/railiance-kubeconfig \
--expected-receiver-image forgejo.coulomb.social/coulomb/audit-core@sha256:ADMITTED_DIGEST \
--confirm 'PROVISION CCR-2026-0021 CCR-2026-0022' \
--receipt /operator/unique-custody-receipt.json
```
A successful seed deliberately reports
`custody_seeded_pending_delivery_and_receiver_reload`. It applies the exact
reader metadata and seeds custody, but does not apply ESO objects, reload the
shared receiver or claim live ingestion. Preserve that receipt. After an
interruption, review it and use `--resume` with a new receipt: only exact
request-owned version-1 custody is reused. Changed tokens, source scopes,
provenance, unknown duplicate identities and concurrent registry writes refuse.
No automatic deletion or rotation is attempted on failure.
Under the same reviewed lane, the subsequent attended delivery uses
`manifests/factory-audit-senders.yaml`; verify both stores/ExternalSecrets and
exact token equality inside the protected process. Sync the existing registry
ExternalSecret, verify its update, and reload Audit Core through its owner
runbook. Then run each real producer's accepted/duplicate and wrong-source,
wrong-tenant/read-refusal checks and retrieve evidence with the independent
operator reader. The delivery helper automates delivery, scope checks and receiver reload; it
does not deploy producers or automate their outbox acceptance.
Do not mark either CCR verified/active until those receipts exist.
## Attended delivery helper
After the seed receipt exists, run this silent command inside a fresh Warden
attended platform-admin envelope (do not rerun seed or reuse a revoked session):
```sh
python3 scripts/factory_audit_delivery.py \
--kubeconfig /operator/railiance-kubeconfig \
--server https://127.0.0.1:16444 \
--expected-receiver-image forgejo.coulomb.social/coulomb/audit-core@sha256:c82e0442de0fd181342916ae9cd5d6de41d859e1efda637bd93936c67873afa5 \
--confirm 'DELIVER CCR-2026-0021 CCR-2026-0022' \
--receipt /operator/unique-delivery-receipt.json
```
The helper pins the reviewed manifest bytes and native cluster/image. It
verifies exact policy, role, version-1 custody and provenance; independently
logs in as each native ESO reader; proves sibling, full-registry, metadata,
listing, wrong-SA and coding-agent-boundary denials; and revokes temporary
reader tokens. It checks exact projected token equality and ESO ownership in
captured memory, forces receiver-registry reconciliation and compares the
complete JSON before restarting the receiver. A uniquely owned temporary
namespace proves wrong-namespace login and explicit ESO namespace restriction
with no Secret created. Cleanup uses the namespace UID precondition.
The metadata-only receipt advances by phase. Its successful status is
`delivered_and_scope_verified_pending_producer_acceptance`. Failures preserve
completed phases for diagnosis; they do not rotate or delete permanent custody.
Receiver accepted/duplicate and negative HTTP checks, real producer outbox
recovery and bearer revocation remain owner acceptance work. Do not mistake
short-lived ESO-reader revocation for receiver bearer revocation.
## Revocation and limits
ESO login expiry does **not** expire an audit bearer. Stop the affected producer,
remove only its token from the receiver registry using CAS, reload the receiver
and prove refusal, then disable its reader/projection. Retain stored events and
KV provenance. Rotation is separately reviewed and overlap-first. Existing
senders and reader permissions remain intact.
`warden route show audit-core-senders` still points to the older Mason bootstrap.
The receiver runbook records the later OpenBao migration; this packet uses that
current authority and the platform's existing attended custody mechanics. It
creates no second registry or generic credential broker.
Factory policy/caller admission, registered human binding, CCR-2026-0019's
operator group, native runtime delivery and spending/operating acceptance stay
with their existing records. Sender approval does not admit any of those acts.