Skip to content

Apply attestation v1

Predicate type https://dragoscv.github.io/axiom/spec/attestation/apply/v1
Envelope in-toto Statement v1 (_type: https://in-toto.io/Statement/v1), optionally wrapped in DSSE
Producer axiom plan verify <bundle> --tree <dir> --attest <out.json> (old verb axiom verify), the GitHub Action with attest: true
Builder buildApplyAttestation in packages/canon/src/statement.ts
Legacy URI https://axiom.dev/attestation/apply/v1 — what 2.x produced. 3.x never produces it; a verifier that must accept 2.x statements treats both URIs as the same predicate (AXIOM_APPLY_ATTESTATION_V1_LEGACY in @codai/axiom-canon)
Status stable

The statement is written only after every artifact digest in the manifest has been checked against the tree (and, when the manifest declares one, the pre-image set). A mismatch exits 1 and writes no attestation. The builder reads no clock: two runs over the same inputs produce byte-identical JSON.

One entry for the manifest plus one per artifact that exists after the change, sorted by name:

name digest.sha256
the bundle file name given on the command line (e.g. manifest.jcs) hex of manifestDigest
each root-relative artifact path whose op is not delete hex of the file’s sha256

gh attestation verify can therefore match either the manifest or any single file it wrote.

Field Type Meaning
manifest { sha256: hex } the manifest digest
plan { sha256: hex } the plan digest the manifest was compiled from
profile string the check profile named by the manifest
tree "post" | "pre" which state of the tree was verified (--pre checks the declared pre-images before an apply)
paths { path, op, sha256 }[] every artifact path verified, sorted by path; sha256 is a hex digest or "absent" for deletes
preImage { path, sha256 }[], optional the manifest’s declared pre-image set, sorted by path
verifier { id, version } id = https://dragoscv.github.io/axiom/spec/builder/mcp@v2; version = the AXIOM version
source { repository?, ref?, sha?, runId? }, optional copied from GITHUB_REPOSITORY, GITHUB_REF, GITHUB_SHA, GITHUB_RUN_ID when present; never content-addressed
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{ "name": "manifest.jcs", "digest": { "sha256": "4f1c…e2" } },
{ "name": "src/hello.ts", "digest": { "sha256": "9b7a…10" } }
],
"predicateType": "https://dragoscv.github.io/axiom/spec/attestation/apply/v1",
"predicate": {
"manifest": { "sha256": "4f1c…e2" },
"plan": { "sha256": "c03d…7a" },
"profile": "default",
"tree": "post",
"paths": [
{ "path": "old.txt", "op": "delete", "sha256": "absent" },
{ "path": "src/hello.ts", "op": "create", "sha256": "9b7a…10" }
],
"verifier": { "id": "https://dragoscv.github.io/axiom/spec/builder/mcp@v2", "version": "3.0.0" },
"source": { "repository": "acme/web", "sha": "1a2b3c…" }
}
}
  1. Re-check the tree yourself — the statement is a claim; the tree is the evidence:

    Terminal window
    axiom plan verify bundle.json --tree . # exit 0 = every path matches the manifest
  2. Verify a CI-uploaded attestation (Sigstore, uploaded by the Action with attest: true):

    Terminal window
    gh attestation verify manifest.jcs --repo <owner>/<repo> \
    --predicate-type https://dragoscv.github.io/axiom/spec/attestation/apply/v1

    Attestations made by 2.x carry the legacy type; pass --predicate-type https://axiom.dev/attestation/apply/v1 for those.

  3. Check the predicate — predicate.manifest equals the digest you expect, tree is the state you meant (post after an apply), and verifier.id is the builder URI above.

Full walkthrough: Verify tree. Signing the bundle itself: Signing.