123 lines
6.1 KiB
Markdown
123 lines
6.1 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` | `["*"]` — **proposed, needs approval-engine's confirmation** |
|
||
|
|
| 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`.
|
||
|
|
|
||
|
|
### The `tenants` value is the one input still owed
|
||
|
|
|
||
|
|
`["*"]` is proposed because approval issuance is not obviously tenant-
|
||
|
|
partitioned, and the alternative — an explicit tenant list — cannot be invented
|
||
|
|
here. `audit_core/senders.py` states that omitting a tenant restriction "should
|
||
|
|
be justified per sender, not adopted by default", so this needs
|
||
|
|
`approval-engine` to either confirm the wildcard with its reasoning or supply
|
||
|
|
the list. Tenant identifiers are opaque to Audit Core; their shape is owned by
|
||
|
|
the IAM Profile and `tenant-engine`.
|
||
|
|
|
||
|
|
### `secret_policy`
|
||
|
|
|
||
|
|
`redact` accepts the event and redacts a secret-shaped field, so a legitimate
|
||
|
|
event is not lost over one field. For a load-bearing source that trade is worth
|
||
|
|
re-examining: `reject` refuses the event instead, which for approvals converts a
|
||
|
|
redactable field into a delivery failure the source must retry. `redact` is the
|
||
|
|
recommendation — losing a revocation record is worse than storing it with one
|
||
|
|
field redacted — but it is `approval-engine`'s call to make explicitly rather
|
||
|
|
than inherit.
|
||
|
|
|
||
|
|
## 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 |
|
||
|
|
| `tenants` confirmation | `approval-engine` | see above |
|
||
|
|
| `secret_policy` confirmation | `approval-engine` | see above |
|
||
|
|
| 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.
|