Skip to content

security: T-4 decision-ledger hash chain + STRIDE claim/evidence CI gate#40

Merged
noisyloop merged 1 commit into
mainfrom
claude/stride-t4-and-ci-gate
May 18, 2026
Merged

security: T-4 decision-ledger hash chain + STRIDE claim/evidence CI gate#40
noisyloop merged 1 commit into
mainfrom
claude/stride-t4-and-ci-gate

Conversation

@noisyloop

@noisyloop noisyloop commented May 18, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #39 (merged: STRIDE audit truth-up + E-5/T-5 fixes). That PR was merged before this final commit landed, so this PR carries the remaining two pieces the audit called for: build T-4 and add the claim/evidence CI gate. Single commit, clean on top of merged main.

T-4 — decision-ledger tamper-evident hash chain (was ❌ aspirational → now ✅)

The decision ledger previously had per-entry hashes only, so deleting or reordering entries was undetectable — a real hole in a non-repudiation/compliance-critical artifact.

  • Every LedgerEntry now carries previousHash, chained from GENESIS.
  • New streaming verifyChain() (readline, no OOM — consistent with D-4) fails closed on content tampering, deletion, or reordering, reporting the breaking index.
  • Chain head bootstraps from disk in initialize() so appends keep chaining across restarts.
  • Legacy pre-chain entries (no previousHash) remain verifiable: per-entry hash still checked, chain resumes from them — no migration needed.
  • docs/STRIDE.md T-4 corrected ❌ → ✅ 2026-05-18.

Structural fix — STRIDE claim/evidence CI gate

scripts/check-stride-claims.mjs (npm run check:stride, wired into security.yml):

  • Every finding in the STRIDE table must have a manifest entry (a new finding can't be added without a conscious decision).
  • A finding must be test-backed (an attack-path test that references the id) or explicitly audit-attested with a code anchor.
  • A non- finding must declare resolved:false — the doc and the manifest cannot silently diverge.

This is the durable fix for the D-6 class of "marked done, not built." It already caught a real drift during development (T-4 left ❌ in the doc after being implemented → gate failed until reconciled).

Test plan

…gate

Follow-through on the verification audit (per maintainer: build T-4,
add the claim<->test gate, keep the framework).

T-4 — decision ledger now has a real tamper-evident chain:
- Every LedgerEntry carries previousHash, chained from GENESIS; the head
  is bootstrapped from disk in initialize() so appends keep chaining
  across restarts.
- New streaming verifyChain() (readline, no OOM) fails closed on content
  tampering, deletion, OR reordering, reporting the breaking index.
- Legacy pre-chain entries (no previousHash) stay verifiable: their
  per-entry hash is still checked, the link check resumes from them.
- STRIDE T-4 corrected ❌ → ✅ 2026-05-18 (now genuinely implemented).

Claim/evidence gate (scripts/check-stride-claims.mjs, npm run
check:stride, wired into security.yml):
- Every STRIDE table finding must have a manifest entry.
- A ✅ finding must be test-backed (attack-path test that references the
  id) or explicitly audit-attested with a code anchor.
- A non-✅ finding must declare resolved:false — doc and manifest cannot
  silently diverge (the gate already caught one such drift on T-4).
This structurally prevents the D-6 class of "marked done, not built".

Full suite 126/126; gate PASS.

https://claude.ai/code/session_01ArAvRMiZgCwF5oNj3r94Ap
@noisyloop noisyloop merged commit 8e5300a into main May 18, 2026
11 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.

2 participants