Offline-verifiable warrants¶
WarrantOS does not ask you to trust its ledger. It lets anyone recompute it.
A warrantos check run produces an audit trail. The verification layer turns
that trail into a portable, tamper-evident artefact that a third party can
verify offline, with no access to your database and no network call. This is the
HTTPS analogy made literal: a document anyone can check.
What it gives you¶
- A tamper-evident ledger.
provenance.merklebuilds a deterministic, RFC 6962 style Merkle tree (leaf/node domain separation, odd-node promotion) over the ordered audit entries. One root digest fixes the entire ledger state: any insert, edit, delete, or reorder changes the root. - A signed checkpoint. With the optional
[attestation]extra, a checkpoint root is Ed25519-signed, binding the ledger state to a signer. - A portable
.warrantbundle.create_warrant()packages the prose digest, the CBOM, the relevant ledger entries, and the signed checkpoint into a single file that travels with the artefact. - An offline verifier.
warrantos verify-externalrecomputes the Merkle root from the entries and matches it against the checkpoint. The integrity half is pure stdlib and needs no key; only signature attribution needs[attestation]. - A browser verifier.
web/verify.htmlis a zero-backend, client-side verifier whose canonical-JSON parser is validated against the Python verifier by a differential test over the supported value domain (including astral-plane unicode). Bounded integers and strings are in domain; arbitrary-precision integers above 2^53 are out of domain and not part of the.warrantschema.
Fail-closed by default¶
An unsigned or signature-unavailable bundle verifies as overall INVALID
unless you pass --allow-unsigned explicitly. An attestation is never silently
accepted without a verified signer. Merkle inclusion proofs bind to
(index, size) and reject replayed, wrong-size, or extra-step proofs. Canonical
serialisation rejects NaN and Infinity, a known Python/JS divergence vector, and
is pinned with known-answer vectors.
Use it¶
# 1. Run a normal check; it writes a run directory under .warrant/runs/<id>.
warrantos check final.md \
--context context.json --actor-identity actor.json --profile final-prose
# 2. Bundle that run into a portable, verifiable artefact.
# Set WARRANTOS_SIGNING_KEY first to attribute the bundle to a signer.
warrantos attest final.md --run-dir .warrant/runs/<id> --out final.warrant
# 3. Verify it offline, anywhere, with no access to the original ledger.
warrantos verify-external final.warrant --prose final.md
# Pin the expected signer to assert attribution:
warrantos verify-external final.warrant --prose final.md --key <signer-pubkey-b64url>
# Accept an integrity-valid but unsigned bundle (drops attribution):
warrantos verify-external final.warrant --allow-unsigned
verify-external exits non-zero on any failure, so it drops straight into CI as
a release gate. The browser verifier (web/verify.html) accepts the same
.warrant for a no-install check by a reader who has only the file.
What signing requires¶
The standard library ships no public-key signing, so the Ed25519 signature path needs the optional extra:
The integrity check (recompute the root, match the checkpoint) needs nothing
beyond the standard library. The project ships no real default key; a
production adopter sets WARRANTOS_SIGNING_KEY.
Honest limits¶
- An unsigned bundle is integrity-verifiable but carries no attribution. It tells you the entries have not been tampered with, not who produced them.
- The
.warrantenvelope and canonical serialisation are a project-defined format, pinned with known-answer vectors and a Python/JS differential check, but not yet a published, versioned standard. A migration to an established signed-statement format (DSSE or COSE) is under consideration. SeeLIMITATIONS.md. - Verification proves the audit trail is intact and attributed. It does not prove the underlying claims are true. That is the job of the verdict gates, not the signature.