Skip to content

feat: tamper-evident receipt chain with signed checkpoints (#758) - #770

Merged
Weegy merged 7 commits into
mainfrom
feat/758-receipt-hash-chain
Aug 20, 2026
Merged

feat: tamper-evident receipt chain with signed checkpoints (#758)#770
Weegy merged 7 commits into
mainfrom
feat/758-receipt-hash-chain

Conversation

@Weegy

@Weegy Weegy commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Closes #758. Builds directly on the turn_receipts table from #757 (PR #763, merged) — the branch is fully synced with main (incl. #759/#760).

What

The receipt record (#757) becomes tamper-evident: every row joins a hash chain, appends are serialized into one linear chain, and periodic Ed25519 checkpoints — signed with a key the database never holds — anchor the head outside the DB. Until now a DB admin could edit any audit row without detection; now an edit breaks the chain visibly at the exact row, and a wholesale rewrite fails against the signed checkpoints.

Threat model (stated, not implied): detection, not prevention. Destruction shows as sequence gaps and orphaned checkpoints. Per-row time is anchored by checkpoint cadence, not per-row (created_at stays outside the hash — a DB default cannot be hashed before it exists).

How

Tests (10 new + adapted #757 suite)

Canonicalization (key-order independence), chain build + verify, three tamper kinds (edit a payload → hash_mismatch at exactly that seq; delete a row → seq_gap; forge a suffix → link_mismatch against the trusted genesis), the transactional append against a stateful fake pool producing a chain that verifyChainSegment accepts end-to-end, replay-rollback invariants (no row, no head, no counter), signer rejection of RSA/garbage keys, sign→verify roundtrip with the exported public key, external anchor line round-trip, checkpoint dedup, empty-stream no-op.

  • Mutation check (rebuilt dist/): storing prev_hash where entry_hash belongs turns the chain-verification test red.
  • Full middleware suite green; typecheck + typecheck:test green.

Docs

CHANGELOG, handoff, docs/security-architecture.md §7b, and docs/ai-act-transparency.md — updated to say the mechanism now exists while keeping "cryptographically verifiable" a public non-claim until #761 ships the verify surface (a proof only we can run is not yet a proof).

Pre-PR review round (self-review findings, all addressed)

  • H1 (blocker) — genesis-append race: FOR UPDATE on a nonexistent head row locks nothing, so two concurrent FIRST appends on a fresh deployment both computed seq 1 and the loser's receipt was permanently lost. Fixed structurally: migration 0041 seeds the head row (seq 0, the hard-coded sha256 genesis literal, reproduction command in the header) so the lock always has a row to grab; test asserts the seeded state yields byte-identical appends to the fallback path.
  • M1 — a checkpoint-race loser (replica) no longer anchors or reports its own differently-timestamped signature: the anchor append is gated on the INSERT actually winning (rowCount === 1); test added.
  • M2 — the created_at/retention laundering channel (drop trigger → backdate → early reap presents as retention) is now explicitly documented in security-architecture §7b with a hard Provenance verification surface: verify endpoint, signed export, offline verifier, chain view #761 requirement: the verifier must check retention-gap age against the checkpoint timeline.
  • M3receiptChainPayload JSON-round-trips before hashing, so hash input and stored JSONB see the identical plain-JSON value (toJSON-bearing values would otherwise cause guaranteed spurious mismatches in the Provenance verification surface: verify endpoint, signed export, offline verifier, chain view #761 verifier).
  • LOWs: /provenance/public-key is always-on (configured:false on keyless deployments instead of a 404); handoff doc-pointer corrected.

Out (deliberate, per issue)

admin_audit chaining (phase 2), RFC 3161 / S3-Object-Lock anchor sinks (the JSONL anchor is the seam), and the whole verification surface (#761: verify endpoint, signed export, zero-dependency offline verifier, chain-status UI).


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Weegy added 7 commits August 20, 2026 12:19
…sh-chain

# Conflicts:
#	docs/CHANGELOG.md
#	docs/ai-act-transparency.md
#	docs/middleware-agent-handoff.md
#	docs/security-architecture.md
#	middleware/.env.example
#	middleware/src/config.ts
#	middleware/src/index.ts
#	middleware/src/receipts/store.ts
#	middleware/test/turnReceipts.test.ts
@Weegy
Weegy merged commit 6b246d4 into main Aug 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tamper-evident audit log: hash chaining, signed checkpoints, external anchoring

1 participant