Skip to main content
Evidence is only worth having if someone can check it. Hexr’s evidence store answers two independent questions, and conflating them is the most common way to overstate what an audit trail proves.

The two properties

intact — sequence

Each row carries a digest over its own content and the previous row’s digest. intact: true means the sequence was not altered after it was written.It says nothing about who wrote it.

signature_valid_rows — authorship

Each signed row carries a signature made inside the process, with that process’s SVID private key.signature_valid_rows counts rows whose signature verifies and whose certificate chains to the SPIFFE trust root.
The endpoint says this itself, in the response:
intact proves the SEQUENCE was not altered after it was written; it does not prove authorship. signature_valid_rows proves AUTHORSHIP: those rows were signed inside a SPIRE-attested process and the signature chains to the SPIFFE trust root. The two are independent — a chain can be intact and unsigned, or signed and broken.
A chain can be perfectly intact and entirely unsigned. That is still useful — it proves nobody edited history — but it is not proof that a particular agent did a particular thing.

Reading the fields

boolean
The hash chain holds. If false, break_at_index and break_at_row_id name the exact row where it stops.
integer
Rows carrying a signature at all.
integer
Rows whose signature verifies against the configured trust bundle. This is the number that matters for authorship.
integer
Signed, but the signature does not verify. Any non-zero value here is serious and should be investigated before anything else.
integer
Signed, but the certificate does not chain to the configured trust bundle — typically a row written under a trust domain the verifier does not have. Not the same as invalid: the signature may be perfectly good and simply unattributable here.
integer
Rows outside the hash chain, usually predating chaining being enabled. They are not evidence of tampering; they are evidence of age.
boolean
Whether the store has a trust bundle at all. If this is false, every signature result is meaningless — the store cannot verify anything.

The store rejects what it cannot verify

A row whose signature does not chain to the configured trust bundle is refused at write time:
This is deliberate. An evidence store that accepts unverifiable evidence is a log file with extra steps.
The most common cause is a trust bundle that has not caught up with a trust domain change. The evidence store caches its bundle at start, so after re-pointing a data plane at a different root, restart the evidence API before expecting signed rows to land.

What a signed row does not prove

Worth stating before an auditor asks.
  • It proves which process made the call — not that the call was correct, authorised by a human, or a good idea.
  • It proves the row was written inside an attested process — not that the process was uncompromised. A compromised agent signs its own actions perfectly well. What you gain is that those actions are attributable and bounded, not that they were prevented.
  • Absence of a row is not proof that nothing happened. A process with no identity writes no evidence — which is precisely why discovering uninstrumented processes is a separate control. See Per-process identity.