Skip to main content

The handoff contract

What a consumer needs to verify a DeskOS artifact without this repository, its workflows or GitHub; anything missing from this list leaves the handoff incomplete.

The contract​

PieceWhat it isWhere it livesHow it is verified
Compiler and resourcesthe commit that produced the artifactthe image's provenance (commit in resolvedDependencies)read the predicate; the commit is a public repository
Planthe canonical, deterministic Plan the image was built fromevidence index, plan.jsonsha256 from the index
Rendered contextgenerated-manifest.json, the files and layers the backend wroteevidence indexsha256 from the index
Subject digestthe OCI manifest digest of the published imageregistry, :stable or a digestcosign verify with the workflow identity
Installed SBOMthe SBOM of what is actually in the imageevidence index, referenced by the attestationthe attestation names its sha256; the index resolves it to bytes
ProvenanceSLSA v1 predicate: commit, base digest, builder, runattached to the imagecosign verify-attestation --type slsaprovenance1
Test resultsboot, session and first-boot summaries, the scan and the accepted risksevidence indexsha256 from the index
Authorizationwho moved the digest to :stable, when, against which recordsapprovals/<repository>/stable/<stamp>-<digest>.json in the evidence bucketread the record; it names the evidence index hash

The evidence index is the hub: a JSON object per digest naming every file and its sha256, served from the public bucket. Everything above except the subject digest and the signature resolves through it.

What an independent verifier does​

No GitHub account, no workflow, no access to this repository:

# 1. the digest :stable serves
skopeo inspect --format '{{.Digest}}' docker://quay.io/deskos/deskos-core-centos-stream-10:stable

# 2. who built it
cosign verify <image>@<digest> \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity 'https://github.com/deskosproject/deskos-core/.github/workflows/image-publish.yml@refs/heads/main'

# 3. what it says about itself
cosign verify-attestation --type slsaprovenance1 <image>@<digest> … | jq -r '.payload' | base64 -d

# 4. the evidence, byte for byte
curl https://evidence.deskos.org/deskos/deskos-core-centos-stream-10/sha256/<digest>/index.json

Step 4 is the one to automate: fetch the index, fetch each object, compare the hash. tests/evidence/verify.py does that and takes the index and the directory.

What is GitHub-specific, and what is not​

  • Not: the artifacts (registry), the records (bucket), the signatures (Sigstore's transparency log) and the approval records (bucket); a different CI could produce the same handoff.
  • Is: the workflow files, the certificate identity (…/image-publish.yml@refs/heads/main) and the provenance run id. A different builder signs with its own identity, which a verifier pins deliberately.

Gaps, named​

  • The evidence index is unsigned. The promotion refuses an index that does not verify, but the index carries no signature: whoever can write the bucket can rewrite an index and its objects consistently. The approval record pins its hash.
  • The approval record is unsigned. automatic (gate) is a claim by the workflow; the record is only as trustworthy as the bucket.
  • No negative-case suite. tests/evidence/verify.py and the promotion refuse missing or mismatched records, but no test proves they refuse a tampered index, a wrong digest or an empty object.
  • No independent policy evaluation yet. Whether Conforma/ec or an organization's own engine can consume these predicates has not been tried, so no compatibility is claimed.

What this contract is for​

So that "verify the image" is a list of objects and commands, not trust in a workflow someone cannot see, and a second build platform has a target.