audit-core/docs/approval-engine-source-registration.md
tegwick bbe8c15494
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(admission): restrict approval audit sender to the platform tenant
Assistant: codex
Assistant-Model: gpt-5.6-luna
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
2026-09-08 17:01:41 +02:00

117 lines
6 KiB
Markdown

# approval-engine source registration
`AUDIT-WP-0009-T09` · intake `AUDIT-IN-0001` · statute §9.4, §9.6
The registration inputs for `approval-engine` as a distinct audit source,
onboarded under `INTENT.md` principle 4 — declared ownership, retention,
access, export and evidence policy, not merely events arriving.
This file is the owner-side record. Everything in it is non-secret. No sender
token appears here, in Git, in State Hub, or in a workplan.
## Declaration
| Field | Value |
| --- | --- |
| Sender name | `approval-engine` |
| Permitted `source` | `approval-engine` (exact; no wildcard) |
| `evidence_kind` | **`load-bearing`** (§9.4 — a control's soundness depends on the revocation event being present) |
| `completeness_trade` | none, and none is permitted — §9.6 requires emission atomicity of a load-bearing source |
| `may_write` | true |
| `may_read` | false — a source does not gain a read surface by emitting |
| `secret_policy` | `redact` (estate default; see below) |
| `tenants` | `["tenant:platform"]` — exact platform store tenant |
| Retention | no expiry set; recoverable history is the platform `data.backup` window, 30 days, `measured` |
| Custody class | `operational` — never `archive`, never WORM |
### Event classes
The four §9.4 classes, carried as distinct actions on one source:
| Class | Why it matters |
| --- | --- |
| issuance | the approval came into being |
| use | single consumption, a state change owned by `approval-engine` |
| supersession | the prior approval stopped being current |
| revocation | **the acute one** — the most valuable event to suppress |
Audit Core stores all four and derives nothing from them. It renders no verdict
on whether an approval is still valid (§9.4), asserted by test in
`tests/test_approval_validity_prohibition.py`.
### Source return — 2026-09-08
`approval-engine/docs/audit-source-registration.md` now records the exact
`["tenant:platform"]` scope and explicit `secret_policy: redact`. The tenant
choice follows the already accepted platform tenant decision and the Engine,
production CLI and deployment defaults; no cross-tenant scope is needed.
Both scope manifests now use that exact value. Tests prove that the overlay
removes a stale wildcard tenant/source/read grant and refuses near-miss tenant
spellings while retaining the accepted platform tenant.
`redact` retains a legitimate event with a secret-shaped field removed rather
than turning it into a delivery failure. This does not permit credentials in
producer payloads. The scope overlay deliberately does not override
`secret_policy`: the protected sender registry entry must set it explicitly
when platform provisioning occurs, and live admission must verify that value.
## Applied in this repository
| Input | Where |
| --- | --- |
| Non-secret scope | `deploy/senders-scope.json` + `deploy/senders-scope.yaml` (lockstep) |
| Receiver ingress | `deploy/networkpolicies.yaml`, `audit-core-approval-engine-ingress` |
| Evidence kind in the model | `audit_core/senders.py`, `SenderIdentity.evidence_kind` |
The scope overlay only applies to a sender the Secret already carries, so this
entry is **inert until the token exists**. That is what makes it safe to land
ahead of the credential rather than in the same change.
The ingress rule is narrower than `user-engine`'s: namespace **and** pod label
in a single `from` peer, so both are ANDed. A new sender should not inherit an
older rule's breadth. `user-engine`'s sender and its policy are unchanged.
## Still owed by others
| Input | Owner | Note |
| --- | --- | --- |
| Token at `approval-engine/approval-engine-audit`, key `audit-token` | OpenBao (`railiance-platform`), routed via `warden route` | Audit Core never holds or transports it |
| Receiver registry custody and explicit `secret_policy: redact` | `railiance-platform` | Link protected registry and sender credential in the first-provision record; no token generated here |
| Applying the manifests to `railiance01` | operator | Audit Core does not apply cluster changes unprompted |
## What Audit Core will and will not claim about this stream
Stated here because §9.6 requires the bound to travel with the trail, and
because a load-bearing source will otherwise be told less than it needs.
**Will:** every event it accepted is stored append-only, and the hash chain
detects alteration or truncation of what it received.
**Will not:** that the archive proves an approval event occurred, or that the
absence of one proves it did not. Completeness at the boundary is
`approval-engine`'s obligation and an archive cannot retrofit it.
### Open gates, and which of them block what
| Gate | Blocks admission? | What it actually bounds |
| --- | --- | --- |
| `T02` attestation scheduling | **No** | Evidence *quality*, not custody. See below. |
| `T04` heartbeat / missing-heartbeat findings | No | Detection of adversarial omission for rare classes — the one that matters most for revocation |
| `T06` reconciliation counts | No | The source's own ability to detect divergence |
| `T05` declared cadence | No | Held deliberately on the §17 Taxonomy schema |
**T02 is an evidence-quality gate, not an admission or deployment blocker.**
Admission depends on identity, scope, ingress and a token. Attestation freshness
governs what Audit Core may *claim*, not whether it accepts and durably stores.
The append-only trigger and hash chain operate regardless; what a stale
attestation removes is detection of a suffix rewrite by someone who owns the
database. Since `AUDIT-WP-0009-T01`, `/readyz` reports `tamper_evidence: false`
rather than overclaiming, and will keep doing so until T02 mounts a renewed
attestation.
It also is not the gate that matters most here. §9.6 is explicit that the acute
risk for approvals is **omission**, and tamper evidence does not address
omission at all — T04 does. So a consumer waiting on T02 before trusting
approval evidence would be waiting on the wrong control. Until T04 and T06
land, Audit Core cannot detect a suppressed revocation, and no reading of the
chain, attested or not, changes that.