Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXXIV · Environment PromotionPromotion models

Promotion by artifact — the same digest moves through environments

Advanced⏱ ~23 mingit

What you'll learn

  • Define promotion by artifact as moving the same digest across environments
  • Trace the digest from CI build through every environment manifest
  • Recognise that the environment repo pins the digest, not the tag
  • Use argocd app set and argocd app sync with --revision to pin and reconcile by digest

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Promotion by artifact is the cleanest promotion model in a GitOps design. The CI pipeline builds the artifact once at the commit, resolves the immutable digest, and every environment’s deployment manifest pins that same digest. The artifact is the unit of release; the manifest is a description of where the artifact runs. When the regulator asks “what exact bytes were running in production at 14:00 on Tuesday?”, the answer is a SHA-256, and that same SHA-256 is in the staging audit log with a timestamp that records the promotion order.

The promotion shape

The diagram captures the model. One build, one digest, many environments. The CI pipeline pushes the image by tag, resolves the manifest digest, and writes the digest into the environment repository. The dev overlay pins digest 9a3f. The staging overlay pins digest 9a3f. The production overlay pins digest 9a3f. The Argo CD Applications in each cluster reconcile against the environment repo, read the pinned digest, and pull the same bytes.

flowchart LR
    A["CI build at commit"] --> IM["Image: sha256:9a3f...e21b"]
    IM --> ER["Environment repo: digest written"]
    ER --> D["dev: digest 9a3f"]
    ER --> S["staging: digest 9a3f"]
    ER --> P["prod: digest 9a3f"]
    D --> AD["Argo CD reconcile"]
    S --> AS["Argo CD reconcile"]
    P --> AP["Argo CD reconcile"]

The order of events is the promotion. The first reconcile applies the digest to dev. The second applies it to staging. The third applies it to production. The timestamps of those reconciles are the audit trail; the digest is the unit.

Pinning and reconciling by digest

The environment repo’s manifest references the digest, not the tag. The tag is incidental; it exists for human readability and for build-time linkage, but it does not determine what the cluster pulls. Once the digest is written, every reconcile pulls the same bytes regardless of what the registry’s tag points at.

DIGEST="sha256:9a3f1c7e8b2a4f6d0e5b9c7a1d3f8e6b2c4a5d7e9f1b3c5a7d9e1f3b5c7a9d1e"
argocd app set payment-api --revision "$DIGEST"
argocd app sync payment-api --revision "$DIGEST"

The --revision argument accepts either a Git ref or an image digest. When the Application’s source is an OCI image or a Helm chart from a registry, the revision is the digest. The set command updates the desired revision; the sync command forces an immediate reconcile against that revision. Both commands operate on the same digest; the result is a cluster pulling the bytes the digest identifies, not the bytes a mutable tag currently points at.

The audit shape

The audit record is a single SHA-256 per release. The CI build log records the commit, the digest, and the signing identity. The environment repo’s commit history records every digest write per environment. The cluster’s reconcile events record when each digest was applied. A regulator’s question — “what was running in production on Tuesday?” — is answered by joining the production reconcile event to the digest to the CI build log, three joins that all resolve to the same identifier.

Production discipline

The production rules for promotion by artifact:

  1. Build once, record the digest, pin everywhere. The CI pipeline produces a single artifact and writes the digest to every environment manifest. No environment manifest pins a tag.
  2. Sign the artifact once. Cosign signs the digest at build time. Every controller verifies the signature against the same public key. The signature is the trust anchor.
  3. The roll-forward is a digest change. A new release produces a new digest; the same pipeline writes it to every manifest. The roll-back is the previous digest, written to the same manifest.

Cross-course references

  • Git, CI/CD & GitOps — Part LXXVI-05 (Promotion models) establishes the two-model taxonomy this lesson deepens.
  • Git, CI/CD & GitOps — Part XLV-03 (Promotion across environments) covers the build-once-deploy-many discipline.
  • Kubernetes for Production Sysadmins — Part XX (Supply Chain) covers the cosign signature verification that anchors the digest at promotion time.

Quiz

Knowledge check · 4 questions

  1. Q1. In the promotion-by-artifact model, what is the audit unit that links production to the commit that produced the artifact?

  2. Q2. Promotion by artifact requires that every environment manifest reference the container by digest rather than by tag.

  3. Q3. Name the two commands used to pin and reconcile an Argo CD Application to a specific artifact digest, and identify the flag that selects the revision.

  4. Q4. Diagnose why production is running bytes the staging tests never covered, and recommend the fix.

    Team T uses promotion by artifact in principle: the CI pipeline builds once and resolves the digest. The dev and staging manifests pin the digest correctly. The production manifest was edited by an operator under pressure to 'fix a typo' and the digest line was replaced with the tag. The production cluster now pulls whatever the tag currently points at. Two days later, the registry's tag was repointed to a hotfix image, and the production bytes diverged from the staging bytes without any commit to either environment repo.

Passing score: 75%. Answers are checked in this browser.