Skip to content

feat: read check evidence through the control API - #1317

Merged
kvlonge merged 2 commits into
mainfrom
feat/check-evidence
Nov 6, 2026
Merged

kvlonge merged 2 commits into
mainfrom
feat/check-evidence

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Why

The UI's check panel shows the rows a failing check captured. Those rows are warehouse data, so reading them needs its own permission and an audit entry, separate from listing checks and from reading their SQL.

Changes

  • GET /api/control/locations/{location}/targets/{target}/checks/{binding_key}/results/{event_id}/evidence returns {columns, rows, truncated} for one recorded result, or null when that result does not belong to the check, target or location.
  • Columns are the sorted union of the captured rows' keys. Each row is aligned to them, with null for a missing key. Cells keep their JSON type, including booleans.
  • Needs view.evidence on the check's attached node, or on every node when that node is not in the current snapshot. No built-in default role grants it.
  • Every read, found or not, writes an evidence.read audit entry holding the scope, binding_key, event_id and found, never the rows. If the audit write fails, nothing is returned.
  • Evidence stored in an unexpected shape returns the generic 500 without echoing the stored value.
  • The SQL and evidence reads share one authorize, read and audit helper.
  • TypeScript client regenerated.

Verification

  • cargo test -p sqlbuild-orchestration --all-features: endpoint tests on SQLite and PostgreSQL cover the administrator read, developer denial with the narrowed scope, the audit entry, a result from another check returning null, a failed audit write disclosing nothing, and malformed stored evidence.
  • make check-ci, public-repository scan.
  • Review: one read-only pass. Its finding (malformed evidence echoed as a 400 before the audit) is fixed.
  • DuckShop: the edge case is the existing check_identity.json fixture, extended with captured rows.

People with view.evidence on a check's model can read the sample rows stored with one of its results. Columns are the rows' keys in sorted order, the order the warehouse stores them in, and a row without a key holds null there. Every read is audited, and a read whose audit cannot be written discloses nothing. The SQL and evidence reads now share one authorize, read and audit path.
@kvlonge
kvlonge enabled auto-merge (squash) November 6, 2026 03:53
@kvlonge
kvlonge merged commit bf4a2a2 into main Nov 6, 2026
91 of 94 checks passed
@kvlonge
kvlonge deleted the feat/check-evidence branch November 6, 2026 06:49
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