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
This commit is contained in:
parent
633f68b81b
commit
bbe8c15494
5 changed files with 46 additions and 22 deletions
|
|
@ -16,7 +16,7 @@
|
|||
"approval-engine"
|
||||
],
|
||||
"tenants": [
|
||||
"*"
|
||||
"tenant:platform"
|
||||
],
|
||||
"may_write": true,
|
||||
"may_read": false,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ data:
|
|||
{
|
||||
"name": "approval-engine",
|
||||
"sources": ["approval-engine"],
|
||||
"tenants": ["*"],
|
||||
"tenants": ["tenant:platform"],
|
||||
"may_write": true,
|
||||
"may_read": false,
|
||||
"evidence_kind": "load-bearing"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ token appears here, in Git, in State Hub, or in a workplan.
|
|||
| `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** |
|
||||
| `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 |
|
||||
|
||||
|
|
@ -39,25 +39,21 @@ 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
|
||||
### Source return — 2026-09-08
|
||||
|
||||
`["*"]` 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`.
|
||||
`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.
|
||||
|
||||
### `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.
|
||||
`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
|
||||
|
||||
|
|
@ -80,8 +76,7 @@ older rule's breadth. `user-engine`'s sender and its policy are unchanged.
|
|||
| 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 |
|
||||
| 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
|
||||
|
|
|
|||
|
|
@ -314,6 +314,26 @@ def test_a_scope_entry_without_a_token_admits_nothing():
|
|||
assert registry.authenticate("Bearer live").name == "user-engine"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tenant", ["platform", "tenant:coulomb", "tenant:Platform", "tenant:platform ", "tenant:customer"])
|
||||
def test_approval_scope_restricts_a_stale_wildcard_registration(tenant):
|
||||
registry = SenderRegistry.from_env({
|
||||
"AUDIT_CORE_SENDERS": json.dumps([{
|
||||
"name": "approval-engine", "tokens": ["fixture-only"],
|
||||
"sources": ["*"], "tenants": ["*"],
|
||||
"may_read": True, "secret_policy": "redact",
|
||||
}]),
|
||||
"AUDIT_CORE_SENDERS_SCOPE_PATH": str(SCOPE_FILE),
|
||||
})
|
||||
identity = registry.authenticate("Bearer fixture-only")
|
||||
assert identity.permits_tenant("tenant:platform")
|
||||
assert not identity.permits_tenant(tenant)
|
||||
assert identity.permits_source("approval-engine")
|
||||
assert not identity.permits_source("user-engine")
|
||||
assert identity.may_write and not identity.may_read
|
||||
assert identity.secret_policy == "redact"
|
||||
assert identity.is_load_bearing
|
||||
|
||||
|
||||
def test_user_engine_evidence_kind_is_not_asserted_on_its_behalf():
|
||||
"""Undeclared means attributive by default, not a claim audit-core made."""
|
||||
scope = json.loads(SCOPE_FILE.read_text())
|
||||
|
|
|
|||
|
|
@ -264,6 +264,15 @@ approvals is omission, which tamper evidence does not address at all. T04 does.
|
|||
A consumer waiting on T02 before trusting approval evidence would be waiting on
|
||||
the wrong thing.
|
||||
|
||||
**2026-09-08 source return:** approval-engine now records the exact existing
|
||||
store scope `["tenant:platform"]` and explicitly selects `redact` in
|
||||
`docs/audit-source-registration.md`. This supersedes the two input waits above.
|
||||
The JSON and ConfigMap overlays are narrowed together. The overlay preserves
|
||||
secret_policy from the protected registry, so provisioning must set it there.
|
||||
T09 remains progress for the platform custody record, credential, admitted
|
||||
manifest application and positive/negative live ingestion evidence. No secret
|
||||
was created and no production manifest was applied by this source change.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T10
|
||||
status: todo
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue