AUDIT-WP-0009-T01 — derive tamper_evidence from live attestation state
The Postgres backend returned tamper_evidence=True as a constant while docs/integrity.md permits the claim only when a live external chain-head attestation exists. The one attestation on record is 2026-08-16 and no job renews it, so audit-core was telling every sender it had a property whose precondition was unverified — the §9.6 defect it twice corrected in gate-house's doctrine, turned inward. evaluate_tamper_evidence() derives the flag from the chain report and the mounted attestation, distinguishing seven states. Absence, staleness, mismatch, an undated or unreadable attestation, a chain break, and an unwalkable chain all degrade the claim rather than leave it standing. Unreadable is treated as absent on purpose: a malformed file must not hold up a claim a missing file would drop. The freshness window is 168h against an intended daily cadence — seven cadences, so a handful of missed runs degrade the claim rather than a single one flapping it. Window and cadence are one contract in docs/integrity.md. Production /readyz will now report tamper_evidence: false until AUDIT-WP-0009-T02 schedules attestation. The claim was already false; it now says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0185wifnLzCxjEY2MT1XbK7L Assistant: claude-code Assistant-Model: opus Assistant-Process: 713962@bnt-lap001 Assistant-Session: 2718d99d-d3ff-478f-83a2-3a30f01a02fc
This commit is contained in:
parent
95dcb78e17
commit
2f7f475e85
7 changed files with 408 additions and 12 deletions
|
|
@ -120,7 +120,7 @@ Compatibility rules (not yet implemented):
|
|||
| `custody_class` | `development`, `operational`, `archive`, or `hot_search` |
|
||||
| `retention_days` | Maximum age before eligible deletion; `None` is a lifecycle statement (no expiry), not a recovery guarantee |
|
||||
| `immutable` | Whether stored records are protected from in-place alteration |
|
||||
| `tamper_evidence` | Whether manifests, hash chains, or signatures exist |
|
||||
| `tamper_evidence` | Whether manifests, hash chains, or signatures exist **and their preconditions are currently live** — backends derive this, they do not declare it |
|
||||
| `durable` | Whether survival is expected across process restarts and host reboots |
|
||||
| `recoverable_days` | Cited platform backup window; `None` if not declared |
|
||||
| `recoverable_source` | Where the recoverable window is cited from |
|
||||
|
|
@ -165,7 +165,10 @@ integrity proofs, or survival of `/tmp` across reboots.
|
|||
- `custody_class`: `operational`
|
||||
- `retention_days`: unset in production (the service does not expire rows)
|
||||
- `immutable`: true (trigger `events_append_only`; not a claim against the database owner)
|
||||
- `tamper_evidence`: true (hash chain + verify + external head attestation; not WORM)
|
||||
- `tamper_evidence`: **derived per read**, not constant — true only while the
|
||||
chain verifies and a fresh, matching external head attestation is mounted
|
||||
(`docs/integrity.md`, freshness window 168h; not WORM). Absent, stale,
|
||||
unreadable, or mismatched attestation reports false.
|
||||
- `durable`: true
|
||||
- `recoverable_days`: 30, cited from the platform `data.backup` provision
|
||||
- `recoverable_source`: `resource-control/data/capability/platform-audit-storage.json#provisions[capability=data.backup]`
|
||||
|
|
|
|||
|
|
@ -39,10 +39,39 @@ owner can. Tamper evidence against that class of attacker requires a
|
|||
1. `verify` exists and fails on a rewritten row
|
||||
2. an external head attestation exists and verify-against-attestation
|
||||
reports a missing cited head as a break
|
||||
3. that attestation is **fresh** — its `observed_at` is within the
|
||||
freshness window below
|
||||
|
||||
It still does not mean WORM, object lock, or ITC-CAP `data.archive`.
|
||||
It does not raise provision maturity to D5.
|
||||
|
||||
## Attestation cadence and freshness window
|
||||
|
||||
An attestation dated once is not a live precondition. The claim is
|
||||
derived from the mounted attestation on every read, not declared:
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Intended attestation cadence | daily |
|
||||
| Freshness window | **168 hours (7 days)** |
|
||||
| Mount path | `AUDIT_CORE_ATTESTATION_PATH` |
|
||||
|
||||
The window is seven times the cadence so that a handful of missed runs
|
||||
degrade the claim rather than a single one flapping it. Widening the
|
||||
window without shortening the cadence weakens the claim and is a
|
||||
change to this contract, not a tuning knob.
|
||||
|
||||
`tamper_evidence` degrades to `False`, with the reason recorded, when
|
||||
the attestation is absent, unreadable, undated, older than the window,
|
||||
or cites a head the live chain does not carry — and when the chain
|
||||
itself is broken or cannot be walked. Unreadable is treated as absent
|
||||
deliberately: a malformed file must not hold up a claim that a missing
|
||||
file would drop.
|
||||
|
||||
Until `AUDIT-WP-0009-T02` schedules the attestation job, no attestation
|
||||
is mounted in production and `/readyz` reports `tamper_evidence: false`.
|
||||
That is the honest reading of the current state, not a regression.
|
||||
|
||||
Do not write the attestation into the Barman prefix
|
||||
(`platform-pg/` on `resource:platform:audit-storage`). That copy is
|
||||
restored with the table. A second copy may follow the logical-offsite
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue