fix(comply): verify the tamper-evidence chain instead of asserting it#227
Open
rylinjames wants to merge 1 commit into
Open
fix(comply): verify the tamper-evidence chain instead of asserting it#227rylinjames wants to merge 1 commit into
rylinjames wants to merge 1 commit into
Conversation
Audit §3.10 / Part 1 #17 — the comply flagship integrity claim. summarize_audit_log computed its own rolling hash and reported it as the "tamper-evidence head", and the technical file + EU AI Act Art-12 mapping cited "tamper-evidence hash-chain" as evidence — but the code never verified anything. An edited / reordered / truncated audit log produced a clean summary and a signed conformity bundle. Meanwhile the runtime recorder writes a real prev_record_hash/record_hash chain and ships a tested verifier, record.verify_record_chain, that comply never called. Now: - summarize_audit_log verifies each file's chain with verify_record_chain (per-file, since the recorder resets the chain per session). Adds chain_verified (True/False/None), chained/unchained file counts, and the first broken file+index to tamper_evidence; adds an `integrity` block. - _iter_records now counts skipped lines (parse_error_count, non_dict_count, unreadable_file_count) instead of silently dropping them — a vanished line is an integrity signal, not noise. A broken chain OR any dropped line flips the summary status to "tampered". - Technical file renders the verification verdict (PASS / FAIL+location / n/a), not just an opaque head hash. - Art-12 record-keeping control flips to "gap" when the chain is broken or lines were dropped — tampered logs no longer count as covered evidence. Tests (tests/test_comply_chain_verification.py, 6 cases): valid chain verifies; edit / reorder / mid-file drop each break it with location; corrupt line is counted and flips status; unchained ActionGuard logs report None (no false claim). Existing comply export + CLI round-trip tests still pass; ruff clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Audit §3.10 / Part 1 #17 — the comply module's flagship integrity claim.
Problem
summarize_audit_logcomputed its own rolling hash and reported it as the "tamper-evidence head". The technical file and the EU AI Act Art-12 mapping then cited "tamper-evidence hash-chain" as evidence — but nothing was ever verified. An edited / reordered / truncated audit log produced a clean summary and a signed conformity bundle. Meanwhile the runtime recorder already writes a realprev_record_hash/record_hashchain and ships a tested verifier (record.verify_record_chain) that comply never called.Fix
summarize_audit_lognow verifies each file's chain withverify_record_chain(per-file — the recorder resets the chain per session). Addschain_verified(True / False / None), chained/unchained file counts, and the first broken file+index._iter_recordscounts skipped lines (parse_error_count,non_dict_count,unreadable_file_count) instead of silently dropping them. A broken chain or any dropped line flips the summarystatusto"tampered".PASS/FAIL — chain broken at <file> #<idx>/n/a), not just an opaque head hash.Tests
tests/test_comply_chain_verification.py(6 cases, all pass): valid chain verifies; edit / reorder / mid-file drop each break it with location; corrupt line counted + status flip; unchained ActionGuard logs reportNone(no false claim).Existing
test_comply.py(signed-bundle export + CLI export→verify round-trip) still passes.ruffclean.🤖 Generated with Claude Code