VERIFY.md with its own file names in. The chain: channel.pub reaches you out of band → it verifies entry.json → entry.json names the sha256 of every evidence file and every image digest, so one signature seals the bundle → the chart references those same digests → your Kyverno pins the same key at admission.
1 — The entry is signed. Steps 2–4 add no signatures; they recompute hashes against this sealed record.
evidence/ and compare to entry.json — a nine-line script in VERIFY.md. A mismatch is a rejection.
3 — The source provenance is real. Proves the source archive was built from the stated public repository at the stated commit, attested by the build platform’s identity, not Vexa’s word.
COSIGN_REPOSITORY is what points cosign at the signature repository instead of alongside the image; without it the command returns no signatures found. It is the same value your install.sh --signature-repository carries, and the entry’s own VERIFY.md fills it in for you.
On a PLATFORM ESTATE entry
An estate entry — one carrying anestate block, published from a running cluster rather than cut from a release tag — has no source archive, no SLSA provenance and no delivery receipt, so steps 3 and 4 do not apply and vexa-verify says so out loud instead of skipping quietly. Each absence is named in the signed document, so it is a statement you can hold us to:
validation_contract named and hashed in the entry. Your contract decides whether the absences are acceptable, via forbid_absent_evidence — an estate-shaped contract lists validation_contract there, so an entry that declared that away is refused, and an OSS-shaped contract pointed at an estate refuses it correctly on its own terms. Annotated worked form: kit/verify/policy.example.yaml.
If step 1 fails on the bundle format
An entry signed by an older cosign carries a legacy bundle, rejected withecdsa: Invalid IEEE_P1363 encoded bytes — a message that looks like a corrupt signature and is not one. Try:
Read before you accept
evidence_absent — kinds this release does not carry, each with a reason. break_glass — who authorised an incomplete chain, and why; a release with gaps and no break-glass record should be rejected by your verifier. The delivery receipt — which images served production traffic and which were validated in other harnesses; the claim is never rounded up.
Verification is digest- and signature-based, so it holds whichever registry served the bytes, your own mirror included. See isolated networks.
Next: The station gate · For your auditors