@decionis/dossier-verify
v0.1.0
Published
Independently verify a Decionis Decision Dossier's Ed25519 proof bundle offline, using only Node's built-in crypto. No Decionis account, SDK, or network dependency required.
Maintainers
Readme
@decionis/dossier-verify
Independently verify a Decionis Decision Dossier — the signed, non-repudiable record Decionis emits every time it allows or blocks a high-stakes action.
This package uses only Node's built-in crypto. It has zero runtime
dependencies and never talks to Decionis except to fetch the public dossier and
the public JWKS. If it prints VERIFIED, the Ed25519 signature is genuinely
Decionis's and the signed documents have not been altered by a single byte. You
do not need a Decionis account, API key, or SDK — that's the point.
CLI
# Verify a live dossier (JWKS auto-discovered from the proof bundle)
npx @decionis/dossier-verify https://api.decionis.com/public/decision-dossiers/<id>/proof-bundle
# Verify a dossier JSON you saved locally
npx @decionis/dossier-verify --file dossier.json --jwks https://api.decionis.com/.well-known/decision-dossier-jwks.json
# Machine-readable output
npx @decionis/dossier-verify <url> --jsonExit code 0 means verified, 1 means not verified, 2 means a usage or IO error.
Library
import { verifyDossierProofBundle, verifyDossierFromUrls } from "@decionis/dossier-verify";
// From objects you already hold
const result = verifyDossierProofBundle({ dossier_payload, public_jwks });
if (!result.verified) throw new Error("dossier failed verification");
// Or fetch + verify from public URLs (JWKS auto-discovered)
const { result: r } = await verifyDossierFromUrls({ dossierUrl });What it checks
For each signed artifact in the proof bundle:
- Public key — an
OKP/Ed25519JWK in the published JWKS matches the bundle's key id (or a rotated predecessor). - SHA-256 — the canonical form of the signed document hashes to the digest recorded in the bundle.
- Ed25519 signature — the signature verifies against the public key over the exact canonical bytes.
Canonicalization is deliberately simple and stable: recursively sort object keys,
leave arrays and scalars in place, then JSON.stringify. A parity test pins this
to the server's implementation so a server-produced signature always verifies here.
Reproducibility posture
A verified signature proves a dossier was not altered — but the stronger property
is reproducibility: a third party can re-run the exact recorded policy against
the exact recorded inputs and get the same verdict. That recompute needs the
deterministic engine (the reproduce endpoint), so it is not offline. What is
offline-checkable is whether a dossier carries what the engine needs to
reproduce it. assessDossierReproducibility(payload) reports one of:
reproduction_ready— carries the recorded outcome, policy version, rules hash, evaluation time, and inputs snapshot; the engine can recompute and hash-match the exact recorded bundle.incomplete— some reproduction inputs are present but not enough; names what is missing.signature_only— no reproduction metadata; a signed record, not a reproducible one.
The CLI prints this posture beneath the VERIFIED line (and includes it under
reproducibility in --json). It is informational — it never changes the
verified/exit status, which reflects the cryptographic check alone.
What it does not check
This verifies the cryptographic integrity of a dossier. It does not by itself
prove when the decision was made — that is covered separately by the dossier's
external timestamp anchor. It does not re-run the policy: the reproducibility
posture above is a coverage check, and the actual recompute uses the dossier's
reproduce endpoint.
