Verify a specific file
You have a binary digest (or any single artifact hash) and you want to know: was this file produced by a build I trust? This guide walks the v0.3 verifier flow — what the user runs, what the verifier finds, what cross-checks it does, and what causes pass or fail.
What you need
To verify a single file you need three things:
- The artifact's sha256 digest, or the artifact itself on disk.
- A signed policy that names the trusted functionaries (build identities) and the attestation steps the build is expected to have produced.
- Access to the build's attestations — either as local files, in a bundle, or via an Archivista evidence store.
The default case needs nothing extra. Since v0.3 product/material attestations inline their Merkle leaves, the product attestation alone already binds your file's digest to the signed tree:products root. The verifier matches your digest against a leaf and confirms it against the signed root — no separate inclusion-proof envelope:
- A product attestation (
https://aflock.ai/attestations/product/v0.3) whose subject istree:productsand whose predicate carries the inlineleaves.
The inclusion-proof path is the exception, for builds that carry a separately-emitted standalone inclusion-proof attestation (https://aflock.ai/attestations/inclusion-proof/v0.1) whose subject is the file digest.
Both paths are covered below.
The command
Default (inline leaves — the product attestation resolves the file by itself):
cilock verify \
--policy policy-signed.json \
--publickey policy-pubkey.pem \
--attestations product.attestation.json,build.attestation.json \
--subjects sha256:<binary-digest>Selective-disclosure / suppressed-leaves variant (add the inclusion-proof envelope):
cilock verify \
--policy policy-signed.json --publickey policy-pubkey.pem \
--attestations product.attestation.json,binary.inclusion-proof.json,build.attestation.json \
--subjects sha256:<binary-digest>A few notes on this command line:
--attestations(-a) is comma-separated, not space-separated. It is a cobraStringSlice. Multiple files must be joined with commas, or you must pass-arepeatedly.--subjects(-s) takes one or more<algorithm>:<digest>strings. The digest is the seed for the BFS. For a binary you have on disk, you can pass-f path/to/binaryinstead and the verifier will hash it for you.- If you are pulling evidence from Archivista, set
--enable-archivistaand let the seed-digest lookup fetch the relevant attestations for you.
Exit code 0 means verification passed. Any non-zero exit code means it failed; the stderr output names the failing rule.
The full set of flags is available via cilock verify --help.
What the verifier does, step by step
The verifier walks a subject-digest BFS (see the spine of the graph). For a single-file verification, the walk is:
-
Seed. The verifier starts with the file digest the user supplied.
-
Default path — resolve via the product attestation's inline leaves. The inclusion-proof bridge maps your seed digest to a product (or material) attestation that lists it as an inline leaf. The verifier verifies that attestation's signature against a trusted functionary, recomputes the leaf hash from the matching
(leafPath, fileDigest)leaf via the canonicalinclusionproof.LeafHashencoder, folds it through the inline tree, and confirms it reconstructs the attestation's signedtree:productsroot. The seed must equal a leaf'sfileDigest(the CVE-2026-22703 cross-check). That's the whole per-file proof — one signed attestation, no extra envelope.Alternative path — explicit inclusion-proof attestation (selective disclosure / suppressed leaves): if there's no matching inline leaf, the verifier instead (a) finds an inclusion-proof attestation whose subject is the seed, (b) verifies its signature, (c) reconstructs the leaf and folds it through the
auditPathto recompute the claimedtreeRoot, (d) cross-checksfileDigest == seed, then (e) finds and verifies the product attestation whosetree:productssubject equals thattreeRoot. Same guarantee, reached through a separate signed proof. -
Continue the BFS. From the product attestation, the BackRefs name the materials' tree root, the command-run, the git commit, and any other build evidence. The verifier walks those to confirm the policy's other steps are satisfied (SBOM present, SARIF clean, etc.).
-
Policy evaluation. Rego rules in the policy evaluate the collected predicates. If every step's
regopolicyrules pass, exit 0. If any rule denies, exit non-zero with the deny message.
When verification fails
Four failure modes specific to file verification, and what they mean. A signature the policy does not trust fails the same way it does for any verify; see First attestation, common failures.
| Failure | Cause |
|---|---|
no collection passed verification for step <name> | Nothing for that step verified. The attestation was not loaded, a collection loaded but its signature or functionary check failed (the "collection rejected" lines above it name why), or the file is committed in a Merkle tree and the inventory or inclusion proof that bridges it was not passed (attestation/policy/errors.go, ErrNoCollections). |
supplied artifact digest(s) [...] not present in any subject of step "<name>" collection | The collection verified, but the file's digest is not one of its subjects. Usually the file changed after it was attested, or it is a Merkle-tree member and needs its inclusion proof (ErrSubjectDigestMismatch). |
inclusion-proof: predicate's claimed treeRoot does not match expected root | The proof names a different tree root than the collection it is checked against. The proof is for another tree, or it was tampered with (plugins/attestors/inclusion-proof/inclusion_proof.go). |
policy was denied due to: ... | A step's Rego policy returned a deny. The text after the colon is the deny message: usually a missing SBOM, a failing SARIF rule, or a constraint on the git commit. |
The verifier never returns "success but with caveats." Any non-zero exit code is a real failure.
Recording the verification result
cilock verify automatically runs its built-in policyverify attestor, which emits a SLSA Verification Summary Attestation (VSA) describing the verify result. Use --vsa-outfile to write that VSA to disk on both pass and fail — a failed VSA is still useful evidence that the gate was run.
cilock verify \
--policy policy-signed.json --publickey policy-pubkey.pem \
--attestations product.attestation.json,binary.inclusion-proof.json \
--subjects sha256:<binary-digest> \
--vsa-outfile binary-verify.vsa.json \
--signer-file-key-path verify-key.pemThe signer flags are required if you want the VSA itself signed; without them the VSA writes as an unsigned in-toto Statement.
See also
- Inclusion proofs — the underlying primitive
- The spine of the graph — why the BFS finds the right attestations
- Verify in a release gate — wiring this into CI
Reference generated from the product documentation. Match commands and support details to your installed release.