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
|
||||
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
|
||||
|
||||
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
|
||||
be short-lived and cost-tuned. Immutable archive is the evidence record.
|
||||
|
||||
6. **Tamper evidence is explicit.** Audit Core should store signed or
|
||||
hash-chained manifests for retained batches so operators can later prove
|
||||
whether a record set was changed, omitted, or truncated.
|
||||
6. **Tamper evidence is explicit, and bounded.** Audit Core should store
|
||||
signed or hash-chained manifests for retained batches so operators can later
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
title: 'Proposed: audit-core takes the approval evidence half (security layer model
|
||||
v0.3 §9.4)'
|
||||
status: open
|
||||
status: closed
|
||||
origin: cross-repo
|
||||
origin_ref: net-kingdom security-layer-model_v0.3 §9.4
|
||||
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
|
||||
half as unowned rather than assume it.'
|
||||
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