Skip to content

feat(compliance): the check's audit row holds its report hash, so an edit shows - #562

Merged
bmscomp merged 1 commit into
mainfrom
feat/compliance-report-hash
Oct 30, 2026
Merged

bmscomp merged 1 commit into
mainfrom
feat/compliance-report-hash

Conversation

@bmscomp

@bmscomp bmscomp commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Merge #560, then #561, first. This PR targets main so CI runs, and carries #561's and #560's commits. Once they squash-merge, I'll merge main in; the squash of this PR should then use only its own commit's message.

Why

How do you prove a database admin didn't edit a stored compliance result by hand? With #560 and #561 alone you can't: the check's audit row recorded only verdict X, and the hash chain covers audit_events, not compliance_checks. A failed rule could be turned into a passed one, verdict kept, and nothing would show.

What

  • The check's audit row details become verdict FAIL, report sha256 …, reference sha256 …, so the chain holds the report's hash.
  • GET /api/conformity/checks/{id} answers reportSha256, computed from the stored report when asked. An edited report no longer matches its audit row.
  • ComplianceCheckRepository.store returns the stored row instead of its id (two callers, one IT).
  • Book: the compliance chapter gains Proving the Results Were Not Changed: the three records behind a check (stored check, chained audit row, an anchor kept outside the database), keeping the anchor in a pipeline, a verify script, what each failure means, and the limits. The API reference describes the new fields.

The chapter states the honest limit: the chain is unkeyed SHA-256, so a whole-table rewrite only shows against an anchor kept where the database's administrators can't write.

Tests (local)

  • ComplianceResourceTest (9, one new: a hand edit of report_json in the database makes reportSha256 differ from the one the audit row recorded), AuditVerifyTest, AuditChainTest: 19 pass
  • ComplianceChecksIT on Postgres (Testcontainers): 2 pass
  • spotless, TestMCPCaveat*, scripts/check-book-style.sh, lychee on the two pages
  • The book's jq filters checked against sample JSON shaped like the API's answers; not run against a live Kates API.

Not done

  • kates compliance check doesn't print the stored check's id, so the book finds the anchor via the gate principal's newest compliance audit row (one key per gate).
  • The audit listing reaches the newest 500 rows of a type; an older check's row can't be read back for the rowHash comparison.

@bmscomp
bmscomp changed the base branch from feat/audit-hash-chain to main October 30, 2026 20:38
@bmscomp bmscomp closed this Oct 30, 2026
@bmscomp bmscomp reopened this Oct 30, 2026
…edit shows

A stored compliance check could be edited in the database without a trace:
its audit row recorded only the verdict, and the audit log's hash chain
covers the audit rows, not the compliance_checks table. A database admin
could turn a failed rule into a passed one and keep the verdict.

The check's audit row now records "verdict X, report sha256 Y, reference
sha256 Z", and GET /api/conformity/checks/{id} answers reportSha256, the
SHA-256 of the report as stored, computed when asked. An edited report no
longer matches the hash its chained audit row holds; a rewrite of the chain
itself changes the rowHash of an anchor kept outside the database.

The compliance chapter gains "Proving the Results Were Not Changed": the
three records behind a check, how to keep the anchor in a pipeline, a
script that verifies a stored check, what each failure means, and the
limits. The API reference describes the new fields.
@bmscomp
bmscomp force-pushed the feat/compliance-report-hash branch from b63f922 to 941312d Compare October 30, 2026 22:27
@bmscomp
bmscomp merged commit 7b21999 into main Oct 30, 2026
61 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.

1 participant