Artifacts & Registries — Digests, Provenance & Immutability
Digests vs tags, SLSA/provenance, registry immutability, and digest-handoff patterns for staging→prod.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
Production is about to pull an image
Prefer
Pull by digest
The deploy reference is repo@sha256:…. Tags may alias that digest for humans. The registry refuses to move a release tag.
- Rollback redeploys a prior digest.
- Attestations hang off the digest as OCI referrers.
- Staging and production resolve the same bytes.
Alternative
Pull app:latest
Every main build moves the tag. Environments drift, and yesterday's tag is gone.
- A rollback redeploys hope.
- Incident response cannot say what ran.
- A second push of the same tag rewrites history.
Build once, then hand the digest forward
If any later job rebuilds, that output is a new artifact and it re-enters staging.
- 1
Resolve inputs
Build from a commit SHA and a lockfile, on a pinned toolchain. - 2
Publish the digest
The push returns a content digest. Record it as a job output. - 3
Attach evidence
SBOM and signature reference that digest, stored as referrers. - 4
Promote the reference
Staging deploys only that digest. Production copies the reference. Rollback uses an older digest.
Overview
The unit of deployment is not a branch name. It is an immutable artifact identified by digest, preferably with provenance: who built it, from which commit, with which materials. Registries store the bytes. Promotion policy moves trust. A tag that might still point somewhere sane is not a policy.
The anatomy page orders the jobs. This page is the identity of the thing those jobs pass around.
Why digests beat tags
| Reference | Mutable? | Good for | Risk |
|---|---|---|---|
app:latest | Yes | Local demos | Silent retarget. Rollback lies |
app:v1.4.0 | Maybe | Humans and release notes | Re-push poisons history unless the registry enforces immutability |
app@sha256:… | No | Production deploy and audits | Verbose. You need a map from release to digest |
| OCI content-addressed blob | No | Supply chain | Tooling has to speak digests |
Tags are aliases for humans. Digests are contracts for machines. Two tags may point at the same digest. The dangerous case is one tag pointing at different digests over time.
Deploy the image field as repo@sha256:…, or as a tag that cannot move. Admission rejects a floating tag. Controllers then pull that exact content. Replica strategy, probes, and autoscaling stay in the Kubernetes Workloads cluster. The traffic controller, once the digest is eligible, is Rolling, Blue-Green and Canary.
Provenance and SLSA
SLSA describes increasing guarantees about an artifact. You do not need level 4 tomorrow. You do need a yes to this question: can we prove this production digest came from this commit via this pipeline?
- Build provenance is signed metadata linking the artifact digest to a source commit and a builder identity.
- Higher levels want hardened, isolated builders and provenance a developer laptop cannot forge.
- A signature proves integrity and authenticity of a payload. Provenance is a specific attestation of how, where, and from what the artifact was built. Ship both.
Flow
- 1
1. Start from the commit SHA
- next2. Name the CI builder
- 2
2. Name the CI builder
- next3. Publish the digest
- 3
3. Publish the digest
- next4. Attach provenance
- 4
4. Attach provenance
- next5. Attach SBOM and signature
- 5
5. Attach SBOM and signature
- next6. Store referrers in registry
- 6
6. Store referrers in registry
- next7. Deploy that digest only
- 7
7. Deploy that digest only
Lesson map
Artifacts & Registries — Digests, Provenance & Immutability
Digests vs tags, SLSA/provenance, registry immutability, and digest-handoff patterns for staging→prod.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB a["1. Start from the commit SHA"] b["2. Name the CI builder"] c["3. Publish the digest"] d["4. Attach provenance"] a -->|1. Start from the commit SHA| b b -->|2. Name the CI builder| c c -->|3. Publish the digest| d
Generate the SBOM at build time from the resolved dependency graph or the image layers, then attach it to the digest. An SBOM rebuilt from package.json weeks later is a fantasy inventory. The lockfile is the graph.
Registry practices
- Immutability. Deny overwrite of release tags. Allow new tags and new digests.
- Retention. Keep digests long enough for rollback and forensics. Garbage-collect with that window in mind. Seven days is often too short for a production service.
- Separation. A scratch repository and a production-promote repository get different write policies.
- Referrers. Store signatures and SBOMs beside the image (OCI referrers or attachments).
- Mirrors. Pin and verify. A blind pull-through mirror amplifies a bad publish.
Multi-arch images are an index (a manifest list). Promote the index digest, and check that attestations cover the platforms you run. A single-arch digest promoted by accident is a different artifact.
Internal Artifactory often wins on retention and policy. Public GHCR or ECR often wins on IAM and OIDC ergonomics. Either one has to enforce immutability on the release path.
Language package provenance
| Ecosystem | Mechanism | CI tip |
|---|---|---|
| npm | Provenance / publish attestations | npm publish --provenance from OIDC-enabled CI |
| PyPI | Trusted publishing (OIDC) | Prefer that over long-lived tokens |
| Maven / Gradle | sigstore experiments, plus traditional signing | Pin plugin versions |
| Containers | cosign plus an attached SBOM | Sign the digest. Verify at admit or deploy |
npm provenance shows that a version was published from a specific public CI workflow. It does not show that the code is safe. Review and scanning still apply. The supply-chain page is the threat model.
Mutable registries
Mutability makes "just push latest" easy, and it is a smaller mental model for a first demo.
It breaks reproducibility, rollback, and forensics. It also enables tag-squatting inside your own org: a later push of the same tag replaces the bytes everyone already deployed. Prefer immutability on every path that can reach production. Keep a clearly non-prod alias such as dev-local for laptops, and never admit that alias to the production cluster.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Deploy main:latest | The tag moves under you | Pin the digest |
| Rebuild in the prod job with a prod ARG | Different bits than staging | Runtime config, or a separate config artifact |
docker tag from a laptop | No audit, no provenance | Pipeline-only publish |
| Delete digests after 7 days | No rollback, no forensics | Retain by environment criticality |
SBOM from package.json, not the lockfile | Fantasy inventory | Use the resolved graph |
Tags still earn a place after immutability exists. Human release notes (v1.4.0) point at a digest that cannot change. A moving channel such as stable is an alias update with an audit event, not a silent overwrite.
Digest handoff between jobs
jobs:
build:
outputs:
image_digest: ${{ steps.build.outputs.digest }}
steps:
- id: build
run: |
DIGEST=$(crane digest ghcr.io/acme/api:sha-$GITHUB_SHA)
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
deploy_staging:
needs: build
steps:
- run: echo "Deploy ghcr.io/acme/api@${{ needs.build.outputs.image_digest }}"Hermetic builds
Hermetic means the inputs are declared: sources, toolchains, and the environment that can affect the bytes. A non-hermetic build picks whatever is on the runner: apt versions, a floating base image, a warm global cache.
A digest of a non-hermetic build is still an immutable blob. Rebuilding the same commit may yield a different digest, so provenance of "this commit" is weaker than it looks. Pin base-image digests and toolchain versions so a rebuild is meaningful. Cache correctness for those inputs is the next page.
Helpers you can run
Press Run. Snippets must be self-contained — no network, files, or native modules.
Press Run. Snippets must be self-contained — no network, files, or native modules.
Interview Q&A
How do you deploy by digest in Kubernetes without turning this into a Deployment lecture?
Answer
Set the image to repo@sha256:…, or to a tag that cannot move. Admission rejects floating tags. The controller pulls that content. Surge, probes, and autoscaling are the Kubernetes Workloads pages. Eligibility versus traffic split is Rolling, Blue-Green and Canary.
What is provenance versus a signature?
Answer
A signature proves the payload was not swapped and names a signer. Provenance is the attestation of how, where, and from what the artifact was built. You want both on the digest you deploy.
Can two tags point at the same digest?
Answer
Yes. Those are aliases. The failure mode is one tag moving to a different digest later.
How do you handle multi-arch images?
Answer
Promote the manifest-list digest, and check that attestations cover the platforms you run. Promoting one platform's digest by accident ships a different artifact.
Where should SBOMs be generated?
Answer
At build time, from the resolved graph or the image layers, then attached to the digest. Generating one later from an unresolved manifest loses fidelity.
Internal Artifactory versus public GHCR or ECR?
Answer
Internal registries often win on retention and promotion policy. Cloud registries often win on IAM and OIDC. The release path on either one has to be immutable.
What breaks if CI pushes latest from every main build?
Answer
Environments drift. Rollback becomes a guess. Incident response cannot answer what ran.
Why pin the base image if the output digest is already immutable?
Answer
The output blob will not change after publish. A second build of the same commit can still produce a different blob if the base or the toolchain floated. Hermetic inputs make the provenance claim about the commit believable.
Pitfalls
- Copying a tag between environments and calling it promotion.
- Signing a tag that can still move, then verifying the tag name.
- An SBOM that lists direct dependencies and skips the lockfile.
- Garbage-collecting the previous production digest before the incident review.
- A scratch registry whose write role can also push to the production repository.
Take a service you deploy. Write the exact image reference staging used, and the reference production should use. If they differ by anything other than the environment around the process, you rebuilt.