Skip to content

0004. :latest tag remediation plan

  • Status: accepted
  • Date: 2026-04-15
  • Deciders: lusoris

Decisions recorded 2026-04-15

  1. Hotio carve-out approved — hotio *arr apps may use :release (curated stable stream). PRINCIPLES.md updated to recognise curated-stable tags as an exception to the "no mutable tags" rule, provided the exception is referenced from an ADR.
  2. Automation = Renovate — not argocd-image-updater. Covers Helm charts, Docker tags, Terraform modules in one tool. renovate.json lands alongside this ADR.
  3. Pass 1 defers to Renovate — no hand-pinning of vaultwarden / qbittorrent+gluetun / stashapp / jellyfin. Let Renovate open its first PR stream against these; review + merge as the normal cadence.

Context

CLAUDE.md / PRINCIPLES.md state: "All images and charts pinned (no latest)." Pre-commit has a no ':latest' image tags hook that enforces this — but the hook only runs on changed files, so pre-existing violations are grandfathered and invisible during normal development.

Full audit on 2026-04-15: 21 values.yaml files, 51 tag: latest occurrences. Breakdown by tag ecosystem:

Ecosystem Files Typical upstream tag convention
ghcr.io/hotio/* (arr stack) 9 (sonarr ×3 + radarr ×2 + lidarr + prowlarr + sabnzbd + seerr) :release (stable) / :testing / :nightly — rolling. Semver-specific tags exist (e.g., sonarr:5.0.4.2059) but hotio recommends :release.
linuxserver/qbittorrent 1 semver: :5.2.0-r0-ls403
stashapp/stash 1 semver: :v0.28.2
jellyfin/jellyfin 1 semver: :10.11.1
alpine (init/sidecar) 4 (jellyfin, stashapp, newsblur ×3) major.minor: :3.22
newsblur/* 4 hash-only (no semver releases). Requires image-digest pin.
curlimages/curl 1 (bandwidth-scheduler) semver: :8.11.0
quay.io/minio/{minio,mc} 4 (minio ×2, minio-home ×2) date: :RELEASE.2025-04-03T14-56-28Z
ghcr.io/dani-garcia/vaultwarden 1 semver: :1.34.1
ghcr.io/cleanuparr/cleanuparr 1 semver: :v2.0.4
ghcr.io/unpackerr/unpackerr 1 semver: :0.14.2
pcjones/umlautadaptarr 1 semver: :1.7.5
ghcr.io/raydak-labs/configarr 1 semver: :1.9.3
qmcgaw/gluetun 1 (in qbittorrent) semver: :v3.40.0
prometheus-qbittorrent-exporter 1 semver: :v1.6.0

Decision (proposed)

Remediate in three passes, prioritising by risk and by how much version drift matters.

Pass 1 — internet-facing + security-adjacent (do first)

One commit per app; smoke-test after each:

  • vaultwarden — password vault; a surprise rolling update is actively dangerous.
  • qbittorrent + gluetun — public egress via gluetun WireGuard; tunnel config changes between gluetun majors break kill-switch.
  • stashapp — login/auth stack; sensitive data.
  • jellyfin — auth + direct-play codecs; transcoder changes hit GPU passthrough.

Pass 2 — hotio/*arr stack

Script-driven: generate one PR that replaces every hotio tag: latest with :release (not semver). Rationale: :release is the upstream-curated stable stream; using semver introduces manual bump burden on 7 apps. :release is still mutable but is the hotio convention and is what our workloads have been running anyway. We explicitly accept the mutable-tag trade-off for hotio because the alternative (pinning 7 arr apps to 7 different semvers each minor update) is worse operational overhead.

Note: this still technically violates the hard rule. Two options to resolve:

  • A. Relax the rule: "no :latest; curated-stable streams like hotio :release are OK with an ADR reference."
  • B. Bite the bullet and pin to semver, manage via renovate or argocd-image-updater.

Recommend (A) for hotio specifically; (B) for everything else.

Pass 3 — everything else

Semver pins per the table above. For newsblur/* (no semver tags), pin by sha256 digest — image@sha256:… is the escape hatch.

Consequences

Positive:

  • Closes a widely-broken hard rule.
  • Surfaces real image state in values.yaml instead of relying on registry-side mutability.
  • Makes CVE response tractable (know exact version per workload).

Negative:

  • 21 individual changes to test. Over a weekend, reasonable; in one session, not.
  • Introduces manual version bumps for ~10 apps unless we land renovate/argocd-image-updater config.
  • Hotio :release exemption (if adopted) requires updating PRINCIPLES.md / pre-commit hook to recognise the carve-out.

Open questions

  1. Renovate vs argocd-image-updater: the repo already has docs/argocd-image-updater/ (upstream mirror). Did we start adopting it? If yes, finish; if no, evaluate renovate as a simpler alternative.
  2. Hotio carve-out (option A): merge to main? Or pin hotio to semver too and eat the bump overhead?
  3. Pre-commit hook strengthening: add a second hook that runs on all values.yaml files (not just changed) with --hook-type=pre-push so new violations can't sneak in even via unrelated commits.

Implementation order

  1. Write & land the renovate config (or argocd-image-updater) — blocks unless we're OK with manual bumps.
  2. Pass 1 apps (4 files).
  3. Pass 2 hotio decision — either script-pin to :release or hand off to renovate.
  4. Pass 3 — the remaining long tail; can be batched into 2–3 PRs.
  5. Add pre-push hook that rejects any tag: latest anywhere under apps/.