Skip to content

feat(compliance): keep every compliance check as evidence - #560

Merged
bmscomp merged 2 commits into
mainfrom
feat/compliance-checks-stored
Oct 30, 2026
Merged

bmscomp merged 2 commits into
mainfrom
feat/compliance-checks-stored

Conversation

@bmscomp

@bmscomp bmscomp commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Why

A compliance check answered its report and kept nothing, so a cluster's check history lived only in pipeline logs. An auditor asking what was checked, when and by whom had nothing to be shown. EU banks must show their resilience testing under DORA; this is the first piece of an evidence pack for them (Phase 3a of the enterprise plan: store compliance results, then a tamper-evident audit log, then a signed export).

What

  • V27 compliance_checks: the report as JSON, checked_at, the reference name and the SHA-256 of the body sent, the cluster id, the verdict, and the actor and principal type. Nothing deletes these rows.
  • POST /api/conformity/check stores each report and names it in Location: /api/conformity/checks/{id}. The response body is unchanged.
    • A refused reference (400/409/413/503) stores nothing.
    • If the store fails, the caller (often a CI gate) still gets its verdict, without a Location, and the error is logged.
    • The call is now @Audited (RUN, type compliance), its audit row's target the check's id.
  • GET /api/conformity/checks lists them newest first. since (inclusive) and until (exclusive) are ISO-8601 instants; anything else is a 400. page/size as on /api/audit.
  • GET /api/conformity/checks/{id} answers one: the list's fields, referenceSha256, and the full report. 404 for an unknown id.
  • Book: the API reference documents the two endpoints, and the compliance chapter no longer says nothing is stored.

Deliberately not done

  • Retention. Stored checks are never deleted. A CI gate that runs a check on every commit grows the table without bound. Evidence usually has to be kept for years, so this wants a decision, not the 90-day run retention.
  • The hash is of the JSON body, which kates compliance check makes from the YAML file, not of the YAML file itself. An auditor can't hash the YAML file and get a match.
  • No CLI change. kates evidence export comes with the export PR.
  • No test for the store-failure path; it needs a mocked repository in its own test class.

Tests

Locally:

  • ./mvnw test -Dquarkus.grpc.codegen.skip=true -Dquarkus.http.test-port=0: 1773 tests, 0 failures, 3 skipped. 5 new tests in ComplianceResourceTest: stored with actor, SHA-256 and full report, plus the audit row; list by period, newest first, paged; bad since is a 400; unknown id is a 404; a refused reference stores nothing.
  • spotless:check
  • go test ./cmd -run TestMCPCaveat
  • scripts/check-book-style.sh

On real PostgreSQL (Testcontainers): ComplianceChecksIT (b2970af) runs V27 through Flyway and the period queries with either bound or none; a microsecond checkedAt reads back unchanged. With #561's branch, which carries this one, ./mvnw verify ran 1783 unit tests and all 98 ITs, 0 failures.

Not run locally: a book render, so the new #get-apiconformitychecks link is unchecked; it follows the pattern of the book's other API links.

A compliance check answered its report and kept nothing, so the history
of a cluster's checks lived only in pipeline logs. An auditor asking what
was checked, when and by whom had nothing to be shown. This is the first
piece of the evidence pack (plans/enterprise.md, Phase 3a).

- V27 compliance_checks: the report as JSON, when it ran, the reference
  name and the SHA-256 of the body sent, the cluster id, the verdict, and
  the actor. Nothing deletes these rows.
- POST /api/conformity/check stores each report and names it in Location.
  A refused reference stores nothing. If the store fails, the caller still
  gets its verdict without a Location, and the error is logged. The call
  is now @Audited (RUN, compliance), its target the check's id.
- GET /api/conformity/checks lists them newest first, bounded by since
  and until (ISO-8601; anything else is a 400), paged as /api/audit is.
- GET /api/conformity/checks/{id} answers one, with its full report.
- API reference and the compliance chapter no longer say a check stores
  nothing.

Verified locally: mvnw test (1773, 0 failures), spotless:check,
TestMCPCaveatRefAnchors, check-book-style.sh. V27 has run only on H2;
CI's ITs are its first Postgres run.
ComplianceChecksIT runs V27 as Flyway applies it and the period queries
with either bound or none, which ComplianceResourceTest only runs on H2.
A microsecond checkedAt reads back unchanged.
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