feat(evidence): the write-once Postgres evidence tier — codeberg leaves the audit path #2048

Merged
pipeline-bot merged 1 commit from feat/evidence-postgres-tier into trunk 2026-08-15 06:40:42 +00:00
Owner

Sean's directive: audit data belongs in Postgres. Signed release provenance and terminal deployment audits now live in a write-once pipeline_evidence table (history migration v2) — CNPG, barman-archived off-cluster, restore-drilled — instead of codeberg, whose 25 GiB quota stalled all four trains yesterday.

Design: the signers echo their exact signed bytes as output parameters and the OPERATOR inserts them (no DB credential in any workflow pod). bytea, never jsonb — DSSE survives no normalisation. Write-once = PK + ON CONFLICT DO NOTHING + digest read-back (identical = idempotent replay; different = terminal collision). A release is not Succeeded until its evidence is committed; a deploy audit records before the descriptor latches — so the Deployed·stalled chip class dies by construction. The exporter machinery and the 409-divergence apparatus retire wholesale; pre-2026-08-15 codeberg descriptors keep validating.

Guards rewritten in lockstep (provenance-contract, deployment-audit-contract with the acceptor still re-executed against fixtures, frozen-release-notes now resting on byte-exact write-once, codeberg-registry-retry pinning that the signers never touch the codeberg API again); evidence-export-contract retires with its subject. RUN-CONTRACT documents the 6 new keys; exported is deleted.

129/129 guards, full operator suite green (132 envtest specs incl. new coverage: transient put holds the release short of Succeeded, collision fails closed, retired-flow residue clears once).

Queued fast-follows: the HTTP read-back endpoint behind the evidence locators; post-deploy cleanup deletes the wedged -audit/-export workflows so the board goes fully green.

Sean's directive: audit data belongs in Postgres. Signed release provenance and terminal deployment audits now live in a write-once pipeline_evidence table (history migration v2) — CNPG, barman-archived off-cluster, restore-drilled — instead of codeberg, whose 25 GiB quota stalled all four trains yesterday. Design: the signers echo their exact signed bytes as output parameters and the OPERATOR inserts them (no DB credential in any workflow pod). bytea, never jsonb — DSSE survives no normalisation. Write-once = PK + ON CONFLICT DO NOTHING + digest read-back (identical = idempotent replay; different = terminal collision). A release is not Succeeded until its evidence is committed; a deploy audit records before the descriptor latches — so the Deployed·stalled chip class dies by construction. The exporter machinery and the 409-divergence apparatus retire wholesale; pre-2026-08-15 codeberg descriptors keep validating. Guards rewritten in lockstep (provenance-contract, deployment-audit-contract with the acceptor still re-executed against fixtures, frozen-release-notes now resting on byte-exact write-once, codeberg-registry-retry pinning that the signers never touch the codeberg API again); evidence-export-contract retires with its subject. RUN-CONTRACT documents the 6 new keys; exported is deleted. 129/129 guards, full operator suite green (132 envtest specs incl. new coverage: transient put holds the release short of Succeeded, collision fails closed, retired-flow residue clears once). Queued fast-follows: the HTTP read-back endpoint behind the evidence locators; post-deploy cleanup deletes the wedged -audit/-export workflows so the board goes fully green.
Sean's directive after the 2026-08-14 quota incident: audit data belongs
in Postgres. The signed evidence now rides the one store with proven
off-cluster durability — CNPG with barman archiving to Hetzner Object
Storage, restore-drilled — instead of a third party whose 25 GiB package
quota silently blocked image backups for a week and then stalled all
four release trains.

history: migration v2 adds pipeline_evidence (project, package_version,
name) PK, sha256 + bytea. The bytes are stored EXACTLY as signed — a
jsonb column would normalise DSSE payloads and break every signature.
PutEvidence is INSERT ... ON CONFLICT DO NOTHING plus a digest read-back:
identical digest = idempotent replay, different digest = terminal
identity collision (ErrEvidenceCollision). There is no update path.

operator: the signers echo their exact signed bytes as output parameters
(single-digit KB) and the OPERATOR performs the insert — no database
credential ever reaches a workflow pod. A release does not reach
Succeeded until its three payloads are recorded; a deployment audit
records its trio before the descriptor latches. The exporter machinery
(reconcileEvidenceExport, pipeline-evidence-export, the exported output,
EvidenceExportPending arming) retires entirely; residue flags clear once.

templates: pipeline-provenance and pipeline-deployment-audit drop every
codeberg touchpoint, including the 409-divergence apparatus (subsumption,
drift naming, published-copy adoption) that existed only to reconcile
against a remote store. Descriptor locators become
https://pipelines.sean.farm/evidence/... — the Postgres primary key
spelled as the future read URL (read-back endpoint is a queued
fast-follow).

guards: provenance-contract, deployment-audit-contract (acceptor
re-execution retained), frozen-release-notes, codeberg-registry-retry
(now: image backups stay best-effort AND the signers must never touch
the codeberg API again), run-evidence-contract (6 new keys documented,
exported deleted). evidence-export-contract retires with its subject.

The board consequence: a Deployed row can no longer stall on its audit —
an in-cluster INSERT has no quota, no WAF, no 504.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
sean/pipelines!2048
No description provided.