Contracts

Authoritative reference for algorithm assignments across the autonomy.lock.json schema and the supply-chain pipeline.


Hash Roles

Two hash algorithms are used in this codebase. They serve different purposes and must never be confused or substituted for each other.

Field / purpose

Algorithm

Prefix

Hex length

Canonical source

behavioral_fingerprint

BLAKE3

blake3:

64

lock.ComputeFingerprint

agent_artifact.digest

SHA-256

sha256:

64

OCI registry manifest

policy_bundle.digest

SHA-256

sha256:

64

OCI registry manifest

inputs.prompt_hash

SHA-256 or BLAKE3

sha256:/blake3:

64

caller-supplied

inputs.tool_inputs_hash

SHA-256 or BLAKE3

sha256:/blake3:

64

caller-supplied

Policy bundle bundle_hash

SHA-256

sha256:

64

policy.Build

TOML lock CI golden gate

SHA-256

(none — raw hex)

64

lock.Fingerprint (TOML)

BLAKE3 — behavioral_fingerprint

behavioral_fingerprint is computed entirely in-process over the canonical JSON bytes of the lock file (with the behavioral_fingerprint field itself omitted to keep the computation self-consistent).

canon  = CanonicalBytes(lock)       // JSON, keys sorted, fingerprint excluded
digest = blake3.Sum256(canon)       // 32 bytes
stored = "blake3:" + hex(digest)    // stored in lock.behavioral_fingerprint

VerifyFingerprint rejects any stored value that does not carry the blake3: prefix (forward-compat algorithm check). There is no fallback to SHA-256.

BLAKE3 is used here (not SHA-256) because:

  • It is faster for in-process computation over arbitrary-length JSON.

  • Its output is prefix-tagged, making the algorithm unambiguous at a glance.

  • It is deliberately distinct from SHA-256 to prevent callers from accidentally treating a registry OCI digest as a behavioral fingerprint or vice versa.

SHA-256 — OCI digests

OCI image manifests are content-addressed by SHA-256 (OCI Image Layout Specification). The registry computes and returns sha256: digests for all pushed content. The lock file records these values verbatim:

agent_artifact.digest  = sha256:<hex>   ← registry manifest digest
policy_bundle.digest   = sha256:<hex>   ← bundle layer digest

autonomy verify step 2 resolves the live digest from the registry and compares it byte-for-byte with the lock field. Using BLAKE3 for OCI digests would produce a value the registry does not know, so only SHA-256 is used here.

What cosign signs

cosign signs the OCI manifest at its SHA-256 subject digest. The cosign signature payload embeds the sha256: digest of the image manifest as the signed subject. The behavioral_fingerprint (BLAKE3) is not directly covered by the cosign signature; it is verified separately in step 3 of the supply-chain pipeline (lock.VerifyFingerprint).


Supply-chain verification: algorithm assignment per step

Step 1 — Signatures   cosign verify → SHA-256 subject digest (registry standard)
Step 2 — OCI digests  live SHA-256 digest vs lock.agent_artifact.digest
                       SHA-256(bundle bytes) vs lock.policy_bundle.digest
Step 3 — Fingerprint  BLAKE3(canonical JSON) vs lock.behavioral_fingerprint
Step 4 — Semver       string comparison — no hashing

Each step has a distinct sentinel error so callers can distinguish failures:

Error

Step

Algorithm involved

ErrNotSigned

1

cosign / SHA-256 OCI digest

ErrDigestMismatch

2

SHA-256

ErrFingerprintMismatch

3

BLAKE3

ErrSemverIncompat

4

n/a


Schema enforcement

The JSON Schema at lock/schema/lock.schema.json encodes the algorithm contract as regex patterns:

"behavioral_fingerprint": { "pattern": "^blake3:[a-f0-9]{64}$" }
"agent_artifact.digest":   { "pattern": "^(sha256:|blake3:)[a-f0-9]{64}$" }
"policy_bundle.digest":    { "pattern": "^(sha256:|blake3:)[a-f0-9]{64}$" }

behavioral_fingerprint accepts only the blake3: prefix. OCI digest fields accept sha256: or blake3: (forward-compatible), though sha256: is the only value produced in practice by today’s OCI registries.


Canonical MVP artifacts

These are the artifacts the CI acceptance gates validate end-to-end.

Artifact

Canonical format

Canonical location

Behavioral lock file

autonomy.lock.json — UTF-8 JSON

demo/locks/example.lock.json

Policy bundle

.tar.gz containing manifest.json

output of autonomy policy build

OCI lock sidecar

JSON blob at <image>-lock tag

pushed by autonomy oci attach-lock

OCI policy sidecar

.tar.gz blob at <image>-policy tag

pushed by autonomy oci attach-policy

Telemetry WAL

Append-only JSONL (wal/)

demo/data/wal/ (bind-mount)

OCI attachment strategy

The autonomy oci commands probe the registry on first use and cache the result per registry host:

  1. OCI Referrers API (preferred) — OCI 1.1 manifest with a subject field. Supported by GitHub Container Registry, Zot, Harbor 2.x, AWS ECR.

  2. Sidecar tag fallback — derived tags <image>-lock and <image>-policy. Used by registry:2 (local dev and CI).

Both modes produce byte-identical content on pull. The OCI sidecar CI gate (ci/test_oci_attach_verify.sh) asserts this with diff -q.

Policy bundle manifest

The canonical bundle format is a .tar.gz archive containing manifest.json. The field policy_bundle_version in manifest.json drives the Step 4 semver check (sign.ErrSemverIncompat). The legacy manifest.toml format is no longer supported in the verification path; bundles produced by autonomy policy build always emit manifest.json.


What is explicitly NOT MVP-gating

The following are supported by the codebase but are not hard CI gates. They must not be promoted to gating status without an explicit decision.

Item

Status

Rationale

autonomy.lock.toml (TOML lock format)

Legacy / dev-only

Superseded by autonomy.lock.json; TestFingerprintGolden in lock/fingerprint_test.go is non-gating by design

manifest.toml in policy bundles

Removed

No longer read by the verification path; autonomy policy build emits manifest.json only; legacy TOML loading in policy.Load() emits a deprecation warning

cosign signatures

Required for make demo-run

demo/scripts/02_push_attach_sign.sh exits 1 if cosign is absent; use make demo-run-unsigned to bypass (weaker)

OCI Referrers API mode

Preferred but not required

CI uses registry:2 which falls back to sidecar tags; referrers mode is exercised by demo/scripts/registry_demo.sh

autonomy.signed-at timestamp annotation

Optional

Enforced only when AUTONOMY_TRUST_TIME=true; omitting it is valid for air-gapped environments

TOML lock SHA-256 fingerprint

Legacy / non-gating

lock.Fingerprint() computes SHA-256 over TOML bytes; the test TestFingerprintGolden in lock/fingerprint_test.go exists for regression coverage of the legacy utility but is explicitly excluded from the MVP gate

Canonical CI gate matrix

CI gate

Script

Hard/soft

BLAKE3 determinism

ci/test_lock_determinism.sh

Hard

Policy enforcement (allow/deny)

ci/test_policy_enforcement.sh

Hard

OCI sidecar byte-identity

ci/test_oci_attach_verify.sh

Hard

WAL durability (offline→drain)

ci/test_offline_telemetry_drain.sh

Hard

cosign sign + verify

ci/test_oci_attach_verify.sh (§7)

Soft — skipped if cosign absent

TOML canonicalize utility

GitHub Actions determinism job

Soft — utility correctness, not format gate

The Go unit tests backing the hard BLAKE3 gate are:

lock/lock_test.go::TestJSONFingerprintGolden        ← stored BLAKE3 matches recomputed (primary gate)
lock/lock_test.go::TestFingerprintAlgorithmIsBLAKE3 ← algorithm contract (not SHA-256)
lock/lock_test.go::TestCanonicalBytesRepeatable     ← canonical JSON bytes deterministic (100 runs)
lock/lock_test.go::TestComputeFingerprintDeterministic ← BLAKE3 stable across 10 independent calls