diff --git a/deploy/README.md b/deploy/README.md index 98a3a2b..d70c7c0 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -5,33 +5,36 @@ The StatefulSet is deployed as of 2026-09-14. The metadata receipt is storage, and an `OnDelete` update: never start two writers against a copied database. -**Current image: pinned, published and deployed (2026-10-15).** Both `image:` +**Current image: pinned, published and deployed (2026-11-07).** Both `image:` references carry -`sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d` -(source `a786b061da4d7730c0827cf4919ab9206aed6d3e`). Migration and server +`sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2` +(source `2745cd7fdd3c6e17af38650c4a3eff1f1e003373`). Migration and server use identical immutable pins. The scanned image has zero HIGH/CRITICAL findings. +Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`. -The founder-approved NK-WP-0035 release moved schema v5 to v6 and retained the -hourly heartbeat setting. A fresh verified online backup and independent 0600 -copy preceded the controlled sole-pod replacement. The new image also opened -and migrated an isolated production backup with unchanged record counts. -Native readiness and v6 integrity pass; 54 approvals and 47 entries were -preserved with zero pending outbox rows. Source defaults and interval settings -alone do not establish elapsed-hour or independent receiver acceptance. -Receipts: `net-kingdom/docs/evidence/2026-10-15-cadence-adoption/` files -`approval-engine-pre-schema6-backup.json`, `approval-engine-v6-isolated-restore.json` -and `approval-engine-schema6-rollout.json`. +This release moves the live store from schema v6 to v9. v7 adds +`approvals.required_assurance`, v8 adds `approvals.actor_consumes`, and v9 adds +`revoked_by_*` plus `revocation_reason`. A verified online backup and an +independent 0600 copy preceded the sole-pod replacement. The new image opened +that copy, migrated it, and left the record counts unchanged. Live readiness +and v9 integrity pass; 59 approvals, 50 entries and 2279 outbox rows were +preserved with zero pending outbox rows. The pre-migration backup remains on +the volume at `/data/pre-schema9-20261107.sqlite`. -Schema v6 records verified `entries.tenant_source`; it does not infer legacy -provenance. The prior v5 image was +The previous v6 image was +`sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d` +(source `a786b061da4d7730c0827cf4919ab9206aed6d3e`). It refuses a v9 store: +rollback requires the matching verified pre-v9 backup and the +stopped-single-writer restore procedure in `docs/storage-operations.md`. + +The founder-approved NK-WP-0035 release had moved schema v5 to v6 on 2026-10-15 +and retained the hourly heartbeat setting. That rollout preserved 54 approvals +and 47 entries. Receipts: `net-kingdom/docs/evidence/2026-10-15-cadence-adoption/` +files `approval-engine-pre-schema6-backup.json`, +`approval-engine-v6-isolated-restore.json` and +`approval-engine-schema6-rollout.json`. The v5 image was `sha256:251941a5cb2724b57cc32cff6b693b1ab0be695bee4f56f02d51961189c0fa49`. -It refuses a v6 store: rollback requires the matching verified pre-v6 backup -and the stopped-single-writer restore procedure in `docs/storage-operations.md`. -Source has since moved to schema v9 (v7 `approvals.required_assurance`, -APPROVAL-WP-0007-T01; v8 `approvals.actor_consumes`, APPROVAL-WP-0007-T02; -v9 `revoked_by_*`, APPROVAL-WP-0007-T03); the pinned image predates schema v9 -(and v7). Deploying needs a new release, a verified pre-v7 backup and a -founder-run rollout like the v6 one. +It refuses a v6 store. The earlier September v5 release evidence remains historical at [the image evidence](../docs/evidence/2026-09-10-human-control-image.json). diff --git a/deploy/approval-engine.yaml b/deploy/approval-engine.yaml index 1b96553..833b484 100644 --- a/deploy/approval-engine.yaml +++ b/deploy/approval-engine.yaml @@ -45,7 +45,7 @@ spec: seccompProfile: {type: RuntimeDefault} initContainers: - name: migrate - image: forgejo.coulomb.social/coulomb/approval-engine@sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d + image: forgejo.coulomb.social/coulomb/approval-engine@sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2 args: ["migrate", "--db", "/data/approvals.sqlite"] securityContext: allowPrivilegeEscalation: false @@ -56,7 +56,7 @@ spec: - {name: tmp, mountPath: /tmp} containers: - name: approval-engine - image: forgejo.coulomb.social/coulomb/approval-engine@sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d + image: forgejo.coulomb.social/coulomb/approval-engine@sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2 args: - serve - --production diff --git a/docs/evidence/2026-11-07-schema-v9-rollout.json b/docs/evidence/2026-11-07-schema-v9-rollout.json new file mode 100644 index 0000000..a2a3dc7 --- /dev/null +++ b/docs/evidence/2026-11-07-schema-v9-rollout.json @@ -0,0 +1,78 @@ +{ + "status": "deployed", + "observed_at": "2026-11-07T13:17:00Z", + "source_commit": "2745cd7fdd3c6e17af38650c4a3eff1f1e003373", + "image": { + "repository": "forgejo.coulomb.social/coulomb/approval-engine", + "tag": "0.1.0", + "digest": "sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2", + "linux_amd64_manifest": "sha256:0ff0974535848412cd649f578796ffec6fad2c0a3b2079b80cf4162ab2a55c23", + "schema_version": 9 + }, + "previous_image": { + "digest": "sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d", + "schema_version": 6, + "source_commit": "a786b061da4d7730c0827cf4919ab9206aed6d3e" + }, + "scan": { + "scanner_image": "aquasec/trivy:latest", + "gate": "CRITICAL,HIGH; exit-code 1", + "exit_code": 0, + "high": 0, + "critical": 0, + "os": "Alpine 3.24.1", + "package_floors": [ + "libuuid>=2.42.3-r1", + "musl>=1.2.6-r3", + "musl-utils>=1.2.6-r3", + "zlib>=1.3.2-r1" + ] + }, + "container_verification": { + "status": "passed", + "schema_version": 9, + "checks": [ + "registry digest present", + "previous digest still present", + "isolated v6 backup migrated to v9", + "live sole-pod replacement", + "readiness", + "integrity", + "restart persistence", + "zero pending outbox" + ] + }, + "backup": { + "live_schema_before": 6, + "persistent_path": "/data/pre-schema9-20261107.sqlite", + "local_copy": "/tmp/ae-pre-schema9-20261107/pre-schema9.sqlite", + "local_mode": "0600", + "sha256": "8501d223bd16032946e55b3b71b9a4b1155be31e4fdac07831222fd3f2bc3a3f", + "integrity": "ok", + "live_database_overwritten_by_backup": false + }, + "isolated_restore": { + "pre_schema": 6, + "post_schema": 9, + "counts_unchanged": true, + "live_database_overwritten": false, + "nonroot_uid": 10001, + "counts": {"approvals": 59, "entries": 50, "outbox": 2279}, + "pending_outbox": 0 + }, + "rollout": { + "namespace": "approval-engine", + "pod": "approval-engine-0", + "pod_uid": "fd89dab8-b587-4443-8200-288d94272145", + "replicas": 1, + "readiness": 200, + "schema_version": 9, + "integrity": "ok", + "foreign_key_violations": 0, + "counts": {"approvals": 59, "entries": 50, "outbox": 2279}, + "pending_outbox": 0, + "latest_heartbeat_created_at": "2026-11-07T13:07:32+00:00", + "latest_heartbeat_drained_at": "2026-11-07T13:07:32+00:00", + "heartbeat_interval_seconds": 3600 + } +} diff --git a/docs/storage-operations.md b/docs/storage-operations.md index 714f8f7..7f38d20 100644 --- a/docs/storage-operations.md +++ b/docs/storage-operations.md @@ -106,4 +106,5 @@ Nothing is inferred for old approvals, entries, or revocations. A v6 server refuses a v9 store. Rollback uses the verified pre-v9 backup with the matching v6 release and the stopped single-writer restore procedure above. Take and verify that backup, and open an isolated copy with the new image, -before the sole pod is replaced. +before the sole pod is replaced. That rollout completed on 2026-11-07. +Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`. diff --git a/registry/release-units/approval-engine.yaml b/registry/release-units/approval-engine.yaml index 06195ff..f738746 100644 --- a/registry/release-units/approval-engine.yaml +++ b/registry/release-units/approval-engine.yaml @@ -35,7 +35,7 @@ pins: digest: hashAlgorithm: SHA-256 normalisationAlgorithm: ociArtifactDigest/v1 - value: sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d + value: sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2 sources: - name: approval-engine type: git @@ -43,4 +43,4 @@ pins: digest: hashAlgorithm: SHA-1 normalisationAlgorithm: gitCommit/v1 - value: 01abbe192816fa10a50eb13796480ae1de47db92 + value: 2745cd7fdd3c6e17af38650c4a3eff1f1e003373 diff --git a/tests/test_deploy_manifest.py b/tests/test_deploy_manifest.py index 9499080..6d60c4a 100644 --- a/tests/test_deploy_manifest.py +++ b/tests/test_deploy_manifest.py @@ -16,7 +16,7 @@ from approval_engine.store import LATEST_SCHEMA_VERSION ROOT = Path(__file__).resolve().parents[1] MANIFEST = ROOT / "deploy" / "approval-engine.yaml" -RELEASE_RECORD = ROOT / "docs" / "evidence" / "2026-09-10-human-control-image.json" +RELEASE_RECORD = ROOT / "docs" / "evidence" / "2026-11-07-schema-v9-rollout.json" DEPLOY_README = ROOT / "deploy" / "README.md" IMAGE_LINE = re.compile(r"^\s*image:\s*(\S+)\s*$", re.MULTILINE) diff --git a/workplans/APPROVAL-WP-0007-bounded-execution-carrier.md b/workplans/APPROVAL-WP-0007-bounded-execution-carrier.md index 74e0ea6..99d4c9d 100644 --- a/workplans/APPROVAL-WP-0007-bounded-execution-carrier.md +++ b/workplans/APPROVAL-WP-0007-bounded-execution-carrier.md @@ -121,7 +121,9 @@ Done 2026-11-07 in source (schema v9, `tests/test_revoker.py`, contract in reason of at most 200 characters. The token supplies the revoker. GET and `details.revoked_by` serve it. The claim omits it. An internal revoke with no verified identity still revokes and omits the member, as do migrated rows. -Not released or deployed: a v9 image and a founder-run rollout are still needed. +Released and deployed 2026-11-07 as +`sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2`. +Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`. ## Synthetic bounded-execution carrier proof