Chronicle. CheckpointStore behaviour
(chronicle v0.1.1)
Copy Markdown
Persistence boundary for independently anchored verification checkpoints.
Production implementations should write to a different trust boundary from
the audit database. Returning :not_found is valid only before the first
successful verification.
What "separate trust boundary" has to mean
Separate credentials, separate administrators, separate failure domain. A file written by the same host, with the same credentials, as the database it is meant to police is not an independent witness — it falls to whoever the database falls to, in the same breath, and its presence makes the property look available when it is not.
What is anchored here is only a position and a digest. Nothing about a checkpoint proves the ledger it came from was correct at that point; it proves the ledger has not been shortened or rewritten since. The chain supplies the rest.
Checkpoints come back as untrusted input
decode/1 raises on anything malformed rather than working around it,
because a checkpoint arrives from storage this library does not control and
cannot vouch for. It insists that a checkpoint's own ledger matches the key
it was filed under — otherwise one ledger's position could be presented as
another's, and a rollback would be compared against a boundary from an
entirely different chain, which it would clear easily.
Digests must be exactly 64 lowercase hex characters, matching what
Chronicle.Digest produces. A sequence of 0 paired with no digest is the
one legitimate degenerate case: a ledger verified while still empty.
The integrity of the checkpoint storage itself is assumed, not checked. An attacker who can write there can retire the anchor, and nothing in this module will notice.
Summary
Callbacks
@callback load(store :: atom()) :: {:ok, %{optional(String.t()) => Chronicle.Integrity.Checkpoint.t() | map()}} | :not_found | {:error, term()}
@callback save( store :: atom(), checkpoints :: %{required(String.t()) => Chronicle.Integrity.Checkpoint.t()} ) :: :ok | {:error, term()}