ADR-0012: Frozen base image tags, SHA-tag preview deploys, and dedicated preview registries¶
Date: 2026-07-01 Status: accepted Deciders: ClearRoute platform team
Context¶
Every application release required bumping the image tag in four places — the three base/ deployment manifests and the dev + prod overlays — even though base/ is never consumed with its literal tag (dev/prod override via images.newTag; prod additionally pins base at ?ref=<sha>). The only real consumer of the base/ tag was the preview overlay, which reconstructed the CI image tag by keeping the version prefix from base/ and swapping only the SHA segment via fragile per-app delimiter: '-' / index-5/6/7 counting. This coupling forced the redundant base bump and carried a latent bug: a PR branched off an older release tag reconstructed a <newer-version>-<sha> tag that never existed in ECR. The root cause is that the ArgoCD pullRequest generator only exposes head_short_sha_7 — never a semver — so preview could only rebuild a <version>-<sha> tag if the version was hardcoded in the repo. Separately, preview (PR-built, from unmerged code) images were pushed into the dev ECR, mixing ephemeral untrusted artifacts with the dev/prod supply chain and competing with dev images for the registry's retention window.
Decision¶
Make base/ image references a frozen :latest placeholder that is never version-bumped. Have CI (constellation-core docker-publish.yaml) publish an additional commit-SHA-only tag :<short7sha> on every build, and route PR builds to dedicated <app>-<component>-preview ECRs (dev account). Preview overlays rewrite the repo to -preview via images.newName and replace the whole tag from preview-values.pr-git-sha with one uniform rule (delimiter: ':', index: 1). dev/prod overlays are unchanged — they keep a Renovate-comparable newTag (semver X.Y.Z, or 0.0.0-<sha> for continuous apps), preserving Renovate as the dev/prod bump mechanism.
Alternatives Considered¶
Keep bumping base/ every release (status quo)¶
- Pros: No change; familiar.
- Cons: Redundant edits in 3 base files per release; preview reconstruction stays fragile (branch-ancestry bug); no isolation of preview images.
- Why not: The base bump is pure dead weight for dev/prod and actively fragile for preview.
Inject a semver into the preview render (teach the AppSet a version source)¶
- Pros: Preview could keep a
<version>-<sha>tag without hardcoding it inbase/. - Cons: The
pullRequestgenerator has no semver; we'd have to encode a version in a git-tracked file or PR label and thread it through the AppSet. - Why not: Large machinery to preserve a tag shape preview doesn't need — a bare SHA is sufficient and unique.
ArgoCD Image Updater for preview/dev bumps¶
- Pros: Auto-tracks new images; no manual tag edits.
- Cons: Git write-back commits directly to a branch — no PR, bypassing the review gate; ordering of
<semver>-<sha>tags is unreliable. - Why not: The repo is review-gated GitOps; losing the PR step is a downgrade. Renovate already opens reviewable bump PRs.
Keep preview images in the dev ECR (status quo registry)¶
- Pros: No new Terraform/IAM.
- Cons: Untrusted PR artifacts share the dev/prod supply chain; preview churn evicts dev images from the retention window; no independent lifecycle.
- Why not: Isolation and a dedicated aggressive lifecycle are cheap given the
<app>-<component>-<env>naming scheme.
Consequences¶
Positive¶
- Releases become overlay-only;
base/is never touched again. - Preview pulls the exact commit image (
-preview:<short7sha>), fixing the branch-ancestry bug. - One uniform preview replacement (
:/ index 1) replaces per-app segment counting. - Preview images are isolated in dedicated registries with their own lifecycle (untagged 1d / any 14d), off the dev/prod supply chain.
- Renovate's dev/prod flow is untouched (dev/prod overlays and
renovate.jsonunchanged).
Negative¶
- More ECR repos + IAM push roles (one set per component, dev account only).
- Preview overlays carry an extra
images.newNameblock per component. - The change spans three surfaces (Terraform,
constellation-coreCI, iac overlays) with a required merge order.
Risks¶
- Merge ordering: the
-previewECRs + push roles (Terraform) and the CI:<sha>tag must exist before the iac preview changes merge, or preview builds fail to push / pull. Mitigation: documented rollout order (Terraform apply → core PR #20 → iac). - IMMUTABLE tags + rebuilds: rebuilding the same commit fails to re-push its immutable
:<sha>tag (pre-existing behaviour for:<version>-<sha>); acceptable. - Deferred CD-model change: routing
main → dev(<semver>-<sha>) /tag → prod(<semver>) with a sortable timestamp suffix so Renovate can still order dev tags is not included here; it will be its own ADR/PR.