Assent to AUDIT-IN-0001 — approval evidence half, with conditions
gate-house proposed (security layer model v0.3 §9.4) that audit-core own the tamper-evident record of approvals while approval-engine owns the operative state. Assented, with two corrections and one condition. Correction 1: INTENT principle 6 overstated the delivered guarantee. docs/integrity.md is authoritative — an in-database chain does not withstand a database owner without the external chain-head attestation, and even then it is not WORM. Principle 6 now points at that bound. Correction 2: the chain proves alteration and truncation, not omission at source. A suppressed revocation leaves the chain intact. Condition: approval-engine must guarantee emission atomicity, so an approval cannot change state without the event being durably queued in the same transaction. Not a task audit-core can discharge for it. Boundary: no approval-validity query will be exposed — that would be deciding early under §6.1. Also declares audit-core's layer (Engine, not a decision point), which §11 requires and INTENT.md was missing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe Assistant: claude-code Assistant-Model: opus Assistant-Process: 4040362@bnt-lap001 Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
This commit is contained in:
parent
2e2d9d54b5
commit
3177d2cee0
3 changed files with 205 additions and 5 deletions
50
INTENT.md
50
INTENT.md
|
|
@ -17,6 +17,18 @@ Audit Core must integrate cleanly with NetKingdom, Railiance, OpenBao,
|
||||||
Kubernetes, identity providers, and application runtimes, but it must not depend
|
Kubernetes, identity providers, and application runtimes, but it must not depend
|
||||||
on NetKingdom to exist or operate.
|
on NetKingdom to exist or operate.
|
||||||
|
|
||||||
|
## Layer
|
||||||
|
|
||||||
|
Audit Core is **Engine layer** under the NetKingdom security layer model
|
||||||
|
(`net-kingdom/canon/standards/security-layer-model_v0.3.md`): it exposes a
|
||||||
|
deterministic API contract and holds operational custody of the records it
|
||||||
|
accepts.
|
||||||
|
|
||||||
|
It is explicitly **not a decision point**. Audit Core answers what was recorded;
|
||||||
|
it never answers whether an action is permitted, and it exposes no surface that
|
||||||
|
returns such a verdict. See `## Out Of Scope Initially` and
|
||||||
|
`history/2026-08-28-approval-evidence-assent.md`.
|
||||||
|
|
||||||
## Problem
|
## Problem
|
||||||
|
|
||||||
Modern platforms generate audit-relevant events in many places:
|
Modern platforms generate audit-relevant events in many places:
|
||||||
|
|
@ -111,9 +123,14 @@ The data plane owns:
|
||||||
5. **Immutable archive and hot search are separate concerns.** Hot search can
|
5. **Immutable archive and hot search are separate concerns.** Hot search can
|
||||||
be short-lived and cost-tuned. Immutable archive is the evidence record.
|
be short-lived and cost-tuned. Immutable archive is the evidence record.
|
||||||
|
|
||||||
6. **Tamper evidence is explicit.** Audit Core should store signed or
|
6. **Tamper evidence is explicit, and bounded.** Audit Core should store
|
||||||
hash-chained manifests for retained batches so operators can later prove
|
signed or hash-chained manifests for retained batches so operators can later
|
||||||
whether a record set was changed, omitted, or truncated.
|
prove whether a record set was changed or truncated. The delivered bound is
|
||||||
|
narrower than that aspiration and `docs/integrity.md` is authoritative on it:
|
||||||
|
an in-database chain does not withstand a database owner without the external
|
||||||
|
chain-head attestation, and the chain proves nothing about an event that was
|
||||||
|
never emitted. Completeness at the boundary is the emitting source's
|
||||||
|
property, not the archive's.
|
||||||
|
|
||||||
7. **Least-privilege access.** Tenants may access their own audit records
|
7. **Least-privilege access.** Tenants may access their own audit records
|
||||||
according to policy. Platform operators may access cross-tenant records only
|
according to policy. Platform operators may access cross-tenant records only
|
||||||
|
|
@ -225,6 +242,33 @@ NetKingdom must not be required for Audit Core's internal authorization model.
|
||||||
Audit Core may accept NetKingdom OIDC claims when configured, but should also
|
Audit Core may accept NetKingdom OIDC claims when configured, but should also
|
||||||
support a generic OIDC provider and local development auth mode.
|
support a generic OIDC provider and local development auth mode.
|
||||||
|
|
||||||
|
## Approval Evidence
|
||||||
|
|
||||||
|
Audit Core carries the **evidence half** of approvals as a distinct source, per
|
||||||
|
security layer model §9.4 and `AUDIT-IN-0001` (assented 2026-08-28).
|
||||||
|
|
||||||
|
`approval-engine` owns the operative approval state — the durable object, atomic
|
||||||
|
supersession, single consumption, and revocation. Audit Core owns the record of
|
||||||
|
what happened to it: the four event classes **issuance, use, supersession, and
|
||||||
|
revocation**.
|
||||||
|
|
||||||
|
Terms Audit Core accepts this under:
|
||||||
|
|
||||||
|
- `approval-engine` is registered as a distinct source, with its own sender
|
||||||
|
registration, tenancy mapping, retention profile, and `secret_policy`,
|
||||||
|
onboarded under principle 4 like any other source;
|
||||||
|
- `approval-engine` guarantees **emission atomicity** — an approval cannot be
|
||||||
|
issued, consumed, superseded, or revoked without the corresponding event being
|
||||||
|
durably queued in the same transaction. Audit Core cannot detect a suppressed
|
||||||
|
emission and will not imply that what it received is everything that happened;
|
||||||
|
- Audit Core exposes **no approval-validity query**. Records, yes; a verdict
|
||||||
|
answering whether an approval is still valid, never. That would be deciding
|
||||||
|
early under §6.1 and would couple authorization to the audit fabric, which is
|
||||||
|
what §9.4 exists to prevent. Callers needing current state ask
|
||||||
|
`approval-engine`.
|
||||||
|
|
||||||
|
Full reasoning: `history/2026-08-28-approval-evidence-assent.md`.
|
||||||
|
|
||||||
## Tenant And Scope Model
|
## Tenant And Scope Model
|
||||||
|
|
||||||
Audit Core should distinguish:
|
Audit Core should distinguish:
|
||||||
|
|
|
||||||
135
history/2026-08-28-approval-evidence-assent.md
Normal file
135
history/2026-08-28-approval-evidence-assent.md
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
# Approval evidence — audit-core's assent (AUDIT-IN-0001)
|
||||||
|
|
||||||
|
**Date:** 2026-08-28
|
||||||
|
**Intake:** `AUDIT-IN-0001`
|
||||||
|
**Requested by:** gate-house
|
||||||
|
**Standard:** `net-kingdom/canon/standards/security-layer-model_v0.3.md` §9.4 (proposed)
|
||||||
|
**Outcome:** assent, with two corrections to the rationale and one condition on
|
||||||
|
the emitting engine.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What was asked
|
||||||
|
|
||||||
|
gate-house proposed that audit-core own the **evidence half** of approvals —
|
||||||
|
issuance, use, supersession, and revocation, emitted as audit events — while a
|
||||||
|
new `approval-engine` owns the operative state: the durable object, atomic
|
||||||
|
supersession, single consumption, and revocation without holder cooperation.
|
||||||
|
|
||||||
|
The two reasons given for keeping the operative state out of audit-core are
|
||||||
|
correct and audit-core does not contest them:
|
||||||
|
|
||||||
|
- operational custody is append-only Postgres by design
|
||||||
|
(`docs/audit-backend-contract.md`), and an approval needs mutable
|
||||||
|
current-state semantics with compare-and-swap supersession; and
|
||||||
|
- `access-engine` must read approval state in-path, so putting it behind the
|
||||||
|
audit fabric would make an audit outage an authorization outage.
|
||||||
|
|
||||||
|
## The answer
|
||||||
|
|
||||||
|
**Assent.** The split is the right one. Approval evidence is a record of what
|
||||||
|
happened, not the authoritative answer to whether an approval is still valid,
|
||||||
|
and that distinction is what keeps this inside `INTENT.md`'s "policy decision
|
||||||
|
making" exclusion rather than a violation of it.
|
||||||
|
|
||||||
|
Two corrections and one condition follow. None of them reject the split; they
|
||||||
|
state what audit-core actually delivers so the standard does not rest on a
|
||||||
|
stronger claim than the implementation supports.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Correction 1 — principle 6 is an aspiration, and the delivered bound is weaker
|
||||||
|
|
||||||
|
gate-house's rationale cites `INTENT.md` principle 6 — *signed or hash-chained
|
||||||
|
manifests so operators can later prove whether a record set was changed,
|
||||||
|
omitted, or truncated* — as already being what authenticated approval entries
|
||||||
|
need forensically.
|
||||||
|
|
||||||
|
`docs/integrity.md` is more careful than principle 6, and it is the contract
|
||||||
|
that ships. In its own words: a chain *inside* the same database detects a
|
||||||
|
rewritten `payload_hash` **only if the attacker does not also recompute the
|
||||||
|
suffix** — and a database owner can. Tamper evidence against that class of
|
||||||
|
attacker requires the **external chain-head attestation**, and even with it:
|
||||||
|
|
||||||
|
> It still does not mean WORM, object lock, or ITC-CAP `data.archive`.
|
||||||
|
|
||||||
|
`tamper_evidence=True` is conditional on two preconditions being live
|
||||||
|
(`verify` failing on a rewritten row, and verify-against-attestation reporting
|
||||||
|
a missing cited head as a break). It is not a property of the store at rest.
|
||||||
|
|
||||||
|
**So: approval events get exactly the guarantee every other audit source gets —
|
||||||
|
no more.** That guarantee is real and it is useful, but it is bounded by the
|
||||||
|
attestation being taken and stored outside `platform-pg`. If §9.4 needs a
|
||||||
|
stronger property for approvals specifically — WORM, object lock, or a
|
||||||
|
transparency log — that is an engine gap to declare under §5.3, not a setting
|
||||||
|
audit-core can turn on.
|
||||||
|
|
||||||
|
## Correction 2 — the chain proves alteration, not omission at source
|
||||||
|
|
||||||
|
This is the more consequential one, and it is the reason for the condition
|
||||||
|
below.
|
||||||
|
|
||||||
|
The hash chain proves that accepted records were not **altered or truncated**.
|
||||||
|
It cannot prove anything about an approval event that was **never emitted**.
|
||||||
|
For an approval object the omission case is not a corner: a suppressed
|
||||||
|
*revocation* is precisely the event an attacker most wants missing, and it
|
||||||
|
leaves the chain perfectly intact. Verify would report `intact`.
|
||||||
|
|
||||||
|
Principle 6 claims audit-core can prove a record set was "omitted". Against a
|
||||||
|
compromised or buggy *sender*, it cannot, and neither can any append-only
|
||||||
|
archive. Completeness at the boundary is the emitter's property, not the
|
||||||
|
archive's.
|
||||||
|
|
||||||
|
## The condition — approval-engine owns emission atomicity
|
||||||
|
|
||||||
|
audit-core accepts the evidence half **on the condition that `approval-engine`
|
||||||
|
guarantees emission is atomic with the state change** — a transactional outbox
|
||||||
|
or equivalent, such that an approval cannot be issued, consumed, superseded, or
|
||||||
|
revoked without the corresponding event being durably queued in the same
|
||||||
|
transaction.
|
||||||
|
|
||||||
|
Without that, the evidence half is silently incomplete and audit-core has no
|
||||||
|
mechanism to detect the gap. audit-core will report what it received; it will
|
||||||
|
not imply that what it received is everything that happened.
|
||||||
|
|
||||||
|
This is a requirement on `approval-engine`, not a task audit-core can discharge
|
||||||
|
on its behalf. It should appear in `approval-engine`'s contract before the
|
||||||
|
evidence half is treated as load-bearing.
|
||||||
|
|
||||||
|
## Boundary audit-core states explicitly
|
||||||
|
|
||||||
|
`approval-engine` will be registered as a **distinct source**, with its own
|
||||||
|
sender registration, tenancy mapping, retention profile, and `secret_policy`
|
||||||
|
under the existing onboarding rules (principle 4: a source is onboarded when
|
||||||
|
ownership, retention, access, export, and evidence policy are declared and
|
||||||
|
validated — not when events start arriving).
|
||||||
|
|
||||||
|
**audit-core will not expose an approval-validity query.** No read surface will
|
||||||
|
answer "is this approval still valid". Records, yes; a verdict, never. Such a
|
||||||
|
surface would be deciding early under §6.1, and a consumer branching on an
|
||||||
|
audit-core answer would be routing an authorization decision through the audit
|
||||||
|
fabric — the exact coupling §9.4 exists to prevent. Callers who need current
|
||||||
|
state ask `approval-engine`.
|
||||||
|
|
||||||
|
The four event classes accepted as a distinct source: **issuance, use,
|
||||||
|
supersession, revocation**, per §9.4.
|
||||||
|
|
||||||
|
## Conformance note raised in passing
|
||||||
|
|
||||||
|
§11 requires that every repository in §4 declare its layer in `INTENT.md`.
|
||||||
|
audit-core declares none today. It is corrected in the same change: audit-core
|
||||||
|
is **Engine layer** — it exposes a deterministic API contract and holds
|
||||||
|
operational custody — and it is explicitly *not* a decision point, per the
|
||||||
|
boundary stated above.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What changed in this repository
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
| --- | --- |
|
||||||
|
| `INTENT.md` | layer declared; approval evidence named as a source; principle 6 cross-referenced to the `docs/integrity.md` bound |
|
||||||
|
| `intakes/intakes.md` | `AUDIT-IN-0001` closed, outcome `assent-with-conditions` |
|
||||||
|
| `history/` | this record |
|
||||||
|
|
||||||
|
Reply sent to gate-house on the State Hub inbox thread.
|
||||||
|
|
@ -7,7 +7,7 @@ id: AUDIT-IN-0001
|
||||||
kind: intake
|
kind: intake
|
||||||
title: 'Proposed: audit-core takes the approval evidence half (security layer model
|
title: 'Proposed: audit-core takes the approval evidence half (security layer model
|
||||||
v0.3 §9.4)'
|
v0.3 §9.4)'
|
||||||
status: open
|
status: closed
|
||||||
origin: cross-repo
|
origin: cross-repo
|
||||||
origin_ref: net-kingdom security-layer-model_v0.3 §9.4
|
origin_ref: net-kingdom security-layer-model_v0.3 §9.4
|
||||||
priority: medium
|
priority: medium
|
||||||
|
|
@ -30,5 +30,26 @@ description: 'gate-house proposes that audit-core own the tamper-evident record
|
||||||
approval events as a distinct source, say so and gate-house will record the evidence
|
approval events as a distinct source, say so and gate-house will record the evidence
|
||||||
half as unowned rather than assume it.'
|
half as unowned rather than assume it.'
|
||||||
created: '2026-08-28T20:35:09.148892Z'
|
created: '2026-08-28T20:35:09.148892Z'
|
||||||
updated: '2026-08-28T20:35:09.148892Z'
|
updated: '2026-08-28T21:10:00Z'
|
||||||
|
outcome: assent-with-conditions
|
||||||
|
closed: '2026-08-28T21:10:00Z'
|
||||||
|
resolution: 'Assent. The split is right: approval-engine owns the operative state,
|
||||||
|
audit-core owns the tamper-evident record of issuance, use, supersession, and
|
||||||
|
revocation as a distinct source. Two corrections to the rationale and one
|
||||||
|
condition. (1) INTENT principle 6 overstates the delivered guarantee;
|
||||||
|
docs/integrity.md is authoritative — an in-database chain does not withstand a
|
||||||
|
database owner without the external chain-head attestation, and even then it is
|
||||||
|
not WORM. Approval events get exactly the guarantee every other source gets,
|
||||||
|
no more; anything stronger is an engine gap to declare under §5.3. (2) The chain
|
||||||
|
proves alteration and truncation, not omission at source. A suppressed
|
||||||
|
revocation leaves the chain intact and verify reports intact; completeness at
|
||||||
|
the boundary is the emitter''s property, not the archive''s. CONDITION:
|
||||||
|
approval-engine must guarantee emission atomicity (transactional outbox or
|
||||||
|
equivalent) so an approval cannot change state without the event being durably
|
||||||
|
queued in the same transaction — a requirement on approval-engine, not a task
|
||||||
|
audit-core can discharge for it. Boundary stated: no approval-validity query
|
||||||
|
will ever be exposed; a verdict surface would be deciding early under §6.1.
|
||||||
|
Also raised: audit-core declared no layer, contrary to §11 — now declared Engine
|
||||||
|
layer, explicitly not a decision point.'
|
||||||
|
recorded_in: history/2026-08-28-approval-evidence-assent.md
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue