From 61214bc24ac0d4568f675f1700c4dba28e93e834 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 16 Aug 2026 01:23:54 +0200 Subject: [PATCH] Close AUDIT-WP-0007 after live chain attestation. Migration 0006 applied on railiance01. Verify-against the dated chain-head evidence is intact for 30 events. --- SCOPE.md | 13 +++++---- deploy/README.md | 2 +- deploy/audit-core.yaml | 4 +-- deploy/migrate-job.yaml | 2 +- docs/evidence/chain-head-20260816.json | 9 ++++++ tests/test_capability_case.py | 2 ++ .../AUDIT-WP-0007-integrity-verification.md | 29 +++++++++++++++---- 7 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 docs/evidence/chain-head-20260816.json diff --git a/SCOPE.md b/SCOPE.md index 60ef68d..94fe26c 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -31,12 +31,13 @@ audit-core exists to provide the capability described in INTENT.md. - Status: production - Production receiver on railiance01 (`namespace audit-core`), Postgres operational custody on `platform-pg`, sender `user-engine`. -- Recovery is the platform `data.backup` window (30 days, RESOURCE-WP-0002 - live). Live `/readyz` reports `custody_class=operational` and - `recoverable_days=30` (image `sha256:05fe1c06…`, 2026-08-16 cutover). -- ITC-CAP case: `data/capability/audit-core-operational.json`. - `data.archive` is an unmet requirement. `tamper_evidence` is still false. -- Open workplan: `workplans/AUDIT-WP-0007-integrity-verification.md`. +- Recovery is the platform `data.backup` window (30 days). Live `/readyz` + reports `custody_class=operational`, `tamper_evidence=true`, + `recoverable_days=30` (image `sha256:7febc28e…`). +- Hash chain verified on 30 live events + (`docs/evidence/chain-head-20260816.json`). +- ITC-CAP case: `data/capability/audit-core-operational.json` at D4. + `data.archive` is an unmet requirement. ## Getting Oriented diff --git a/deploy/README.md b/deploy/README.md index 4922b02..2915557 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -8,7 +8,7 @@ the server port or export a copy before applying. Apply order is documented in `docs/operator-runbook.md`. Do not apply the Deployment until: -1. The image digest is pinned (currently `sha256:05fe1c06…` from commit `40dcadd`). +1. The image digest is pinned (currently `sha256:7febc28e…` from commit `5fd04e2`). 2. Secrets `audit-core-database`, `audit-core-database-migrate`, and `audit-core-senders` exist. ConfigMap `audit-core-senders-scope` is applied (`deploy/senders-scope.yaml`) before the Deployment mounts it. diff --git a/deploy/audit-core.yaml b/deploy/audit-core.yaml index b18efd2..f71709f 100644 --- a/deploy/audit-core.yaml +++ b/deploy/audit-core.yaml @@ -48,7 +48,7 @@ metadata: audit-core.railiance.io/rollback-note: >- Migrations 0001-0006 are additive. 0006 adds chain_hash/chain_prev and then NOT NULL. An image that does not write those columns cannot accept - events after 0006. Do not roll back past sha256:05fe1c06… to a pre-0007 + events after 0006. Do not roll back past sha256:7febc28e… to a pre-0007 writer. A future migration that drops or narrows a column must state its own rollback position before it is released. spec: @@ -80,7 +80,7 @@ spec: - name: audit-core # REPLACE at release time with the built digest. A mutable tag is not # an immutable image, and `:latest` must never be the only reference. - image: forgejo.coulomb.social/coulomb/audit-core@sha256:05fe1c06f809be29309695c397025da755bfe82afed81a7f9b8771e0b9200c17 + image: forgejo.coulomb.social/coulomb/audit-core@sha256:7febc28e8a828dbc245144a38e5728e0fbf496b594dd7591170b450a1265fb10 imagePullPolicy: IfNotPresent ports: - name: http diff --git a/deploy/migrate-job.yaml b/deploy/migrate-job.yaml index dd11e60..a52e263 100644 --- a/deploy/migrate-job.yaml +++ b/deploy/migrate-job.yaml @@ -33,7 +33,7 @@ spec: type: RuntimeDefault containers: - name: migrate - image: forgejo.coulomb.social/coulomb/audit-core@sha256:05fe1c06f809be29309695c397025da755bfe82afed81a7f9b8771e0b9200c17 + image: forgejo.coulomb.social/coulomb/audit-core@sha256:7febc28e8a828dbc245144a38e5728e0fbf496b594dd7591170b450a1265fb10 imagePullPolicy: IfNotPresent command: ["python", "-m", "audit_core", "migrate"] env: diff --git a/docs/evidence/chain-head-20260816.json b/docs/evidence/chain-head-20260816.json new file mode 100644 index 0000000..2da1de6 --- /dev/null +++ b/docs/evidence/chain-head-20260816.json @@ -0,0 +1,9 @@ +{ + "accepted_at": "2026-08-13T15:38:37+00:00", + "chain_hash": "03fd1773c1954e2c39548b0ba297359b9edd739a94ff9b2dcc9529dcd5cf1fcc", + "event_count": 30, + "event_id": "evt_69aad81d75bb49c9b988be7650a5360d", + "genesis": "0000000000000000000000000000000000000000000000000000000000000000", + "observed_at": "2026-08-15T23:23:34+00:00", + "schema": "audit-core.chain-head.v1" +} diff --git a/tests/test_capability_case.py b/tests/test_capability_case.py index 7817620..d48dc6a 100644 --- a/tests/test_capability_case.py +++ b/tests/test_capability_case.py @@ -24,6 +24,8 @@ def test_capability_record_exists_and_joins_operations_audit(): unknown = [row for row in audit["consumes"] if row["basis"] == "unknown"] assert unknown assert all(row["quantity"]["value"] is None and row.get("gap") for row in unknown) + hooks = {item["hook"]: item["basis"] for item in audit["evidence"]} + assert hooks["integrity_verification"] == "measured" def test_capability_review_against_live_catalog(): diff --git a/workplans/AUDIT-WP-0007-integrity-verification.md b/workplans/AUDIT-WP-0007-integrity-verification.md index 436d936..e44155b 100644 --- a/workplans/AUDIT-WP-0007-integrity-verification.md +++ b/workplans/AUDIT-WP-0007-integrity-verification.md @@ -4,7 +4,7 @@ type: workplan title: "Integrity verification for operational custody" domain: infotech repo: audit-core -status: active +status: finished owner: grok topic_slug: railiance created: "2026-08-16" @@ -89,11 +89,14 @@ Write a short contract in `docs/audit-backend-contract.md` (or a sibling Done when the contract is written and the tests to be added are named. +Done 2026-08-16: `docs/integrity.md` names the chain, genesis, proof bound, +and the six tests. + ## T02 — Persist the chain on accept ```task id: AUDIT-WP-0007-T02 -status: todo +status: done priority: high state_hub_task_id: "5830bb1a-27b7-4eed-b09f-75ba8cc9f7f1" ``` @@ -112,11 +115,14 @@ suite. Mock file backend stays `tamper_evidence=False`. Done when conformance tests show: first accept sets genesis; second links; duplicate does not fork; verify is clean on a fresh store. +Done 2026-08-16: migration 0006 plus backfill; SQLite and Postgres accept +write the next link under a lock. Conformance + `tests/test_integrity.py`. + ## T03 — Verify surface ```task id: AUDIT-WP-0007-T03 -status: todo +status: done priority: high state_hub_task_id: "fee1f93c-dcac-4fc3-9e41-17bb4436e8d6" ``` @@ -133,11 +139,14 @@ alone never gave us. Done when CLI and HTTP agree, and the broken-row test is red-then-green as a detector, not as a repair. +Done 2026-08-16: `verify-chain` CLI, `GET /v1/integrity`, SQLite rewrite +test and Postgres superuser rewrite test both fail verify. + ## T04 — Attest the chain head outside platform-pg ```task id: AUDIT-WP-0007-T04 -status: todo +status: done priority: medium state_hub_task_id: "b6d03d6a-0605-4982-a9a3-e18c89319ba9" ``` @@ -158,11 +167,17 @@ and report mismatch as a break. Done when one production walk produces an attestation file in `docs/evidence/` and verify-against-attestation is tested. +Done 2026-08-16: live walk 30 events, intact, head +`03fd1773…`. Evidence +`docs/evidence/chain-head-20260816.json`. Verify-against matched. +Do not copy this file into the Barman prefix; a second copy may follow +RESOURCE-WP-0002-T06 logical-offsite. + ## T05 — Declare tamper_evidence only as far as the proof ```task id: AUDIT-WP-0007-T05 -status: todo +status: done priority: medium state_hub_task_id: "9fd70d3c-5a64-4b26-967f-4ef45394d81c" ``` @@ -182,6 +197,10 @@ After T03 and T04: Done when capability-review still `ok` and the hook is no longer `unknown`. +Done 2026-08-16: Postgres `tamper_evidence=True`; live `/readyz` reports +it; capability-review `ok`; `integrity_verification` is `measured`. +Maturity stays D4. `data.archive` stays unmet. + ## Acceptance - A rewritten stored payload makes `verify` fail.