- the signed receipt itself,
- the policy snapshot the receipt was evaluated against (so rules can be re-run),
- chain proofs and seal (when the receipt is part of a chain),
- the Rekor transparency proof (when anchored),
- the public keys used to sign the receipt and chain proofs (informational only),
- a top-level manifest that hashes everything together.
GET /v1/.well-known/signing-keys is deprecated and self-asserted and must
not be used as a trust root. The bundle’s own trusted_keys.json is
informational and never used to authenticate signatures.
At-a-glance
Bundle layout
The 10 sub-claims
verifyBundle() returns one structured result per sub-claim. Every
relevant sub-claim is reported — the verifier never short-circuits past
the first failure.
1. bundle_manifest
File presence + per-file SHA-256 + manifest digest match.
Failure codes: bundle.unknown_version, bundle.unknown_profile,
bundle.file_missing, bundle.file_digest_mismatch,
bundle.manifest_digest_mismatch.
2. integrity
Recomputed integrity hash matches the receipt’s stored value.
Failure code: integrity.mismatch.
3. signature
Ed25519 signature verified against out-of-band trust roots. What the
signature covers depends on the receipt version: a v1 receipt signs
the bare integrity_hash string, while a v2 receipt signs a
canonical envelope of evidence_manifest_digest, integrity_hash,
policy_snapshot_digest, receipt_schema_version,
signature_algorithm, signature_kid and timestamp. Recorded
receipts are v2. See Receipt Reference
§2.3 for the exact envelope.
The verifier rebuilds the v2 envelope from the receipt’s stored
signature_kid and signature_algorithm rather than hardcoded values,
so tampering with either field fails this sub-claim.
Failure codes: signature.unknown_kid, signature.invalid,
signature.not_signed, signature.no_external_trust_root.
4. snapshot_replay
Bundled snapshot.id matches receipt.policy_snapshot_id; re-running
the bundled rules against the bundled context reproduces the receipt’s
integrity_hash.
Failure codes: snapshot_replay.snapshot_id_mismatch,
snapshot_replay.hash_mismatch,
snapshot_replay.evaluator_unavailable,
snapshot_replay.skipped_in_browser (advisory).
On a v1 receipt,
snapshot_replay.status === 'valid' binds
snapshot.id and snapshot.rules only — snapshot.policy_versions
and snapshot.created_at are informational. On a v2 receipt the
sub-claim additionally checks policy_snapshot_digest, which covers
id, rules, policy_versions and created_at together.5. transparency
If the bundle ships transparency_proof.json: DSSE envelope’s subject
digest equals receipt’s integrity hash; sha256(dsse_envelope) equals
entry_body.spec.envelopeHash.value; Rekor’s SET signature verifies
against a trusted Rekor log key.
Failure codes: transparency.body_subject_mismatch,
transparency.envelope_body_hash_mismatch,
transparency.set_invalid, transparency.unknown_log_id,
transparency.envelope_decode_failed,
transparency.inclusion_proof_invalid,
transparency.inclusion_proof_unverified (advisory).
6. chain_link
Chain proof identifies this receipt (decision_id +
decision_integrity_hash); chain integrity hash recomputes; chain
signature verifies against external trust roots.
Failure codes: chain_link.hash_mismatch,
chain_link.signature_invalid,
chain_link.receipt_binding_mismatch.
7. chain_seal
Seal covers this receipt’s integrity hash; seal hash recomputes; seal
signature verifies.
Failure codes: chain_seal.hash_mismatch,
chain_seal.signature_invalid,
chain_seal.receipt_binding_mismatch.
8. canonicalization
Manifest’s canonicalization profile is one the verifier accepts
(meshqu-canonical/v0 for v1 bundles).
Failure codes: canonicalization.profile_mismatch,
canonicalization.vector_failure.
9. evidence
For a v2 receipt carrying an evidence_manifest_digest: the bundled
evidence_manifest.json re-digests to the value stored on the receipt,
and any custodian signatures on its items verify against the
caller-supplied custodianTrustedRoots. Reports not_applicable for v1
receipts and for v2 receipts with a null digest.
Failure codes: evidence.digest_mismatch,
evidence.bundled_manifest_invalid, evidence.custodian_unknown_kid,
evidence.custodian_signature_invalid,
evidence.custodian_signature_malformed.
10. approval_lineage
Activates when the receipt is v2 and the bundled snapshot has at
least one non-null policy_versions[i].approval_receipt_digest. For each
such version the verifier checks that the approval receipt is present in
policy_approval_receipts.json, that its recomputed digest matches the
snapshot entry, that policy_rules_hash matches by string equality, and
that the ratifier’s Ed25519 signature verifies against the
caller-supplied ratifierTrustedRoots. Reports not_applicable
otherwise.
Failure codes: approval_lineage.digest_mismatch,
approval_lineage.signature_invalid,
approval_lineage.unknown_ratifier,
approval_lineage.policy_rules_hash_mismatch.
How verified is determined
The browser UI’s headline verdict collapses 10 sub-claim results into one
of three states:
- Valid — every sub-claim passes cleanly.
- Verified with caveats — only advisory codes are present (e.g.
snapshot_replay.skipped_in_browser,transparency.inclusion_proof_unverified). Cryptographic checks all passed; the verifier honestly flags what it can’t fully attest in this context. - Failed — at least one hard failure code on any sub-claim.
Trust roots — required input
trustedRoots → signature.no_external_trust_root (the verifier
refuses to authenticate via the bundle’s own keys). Empty
rekorTrustedRoots is allowed but downgrades transparency to
inclusion_proof_unverified.
Cross-runtime parity
Two implementations:- Node in
@meshqu/core - Browser in
meshqu-verify
See also
- Decision Assurance — the assurance ladder.
- Bundles API — endpoint reference.
- Verifying Bundles — auditor workflow.