image pinning: eliminate :latest from all 5 unpinned templates + standing gate
bentopdf :latest -> v2.8.6; calibre-web :latest -> v4.0.6 (== running digest on demo 9201, c31a738b - pin is a no-op); papra :latest -> 26.6.1-rootless (latest was the rootless variant); recipe-importer :latest -> v0.9.11 (tag pre-existed, digest-equal, no retag needed); termix :latest -> 2.5.0. All five pins digest-identical to what :latest resolved to on 2026-07-12. New gate scripts/check-image-pins.py (catches floating tags AND untagged refs; red-proofed both shapes). Standing rule in CLAUDE.md + REUSE.md row.
This commit is contained in:
@@ -1,5 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-07-12 — image pinning sweep: `:latest` eliminated from all templates (5 pins) + standing gate
|
||||
|
||||
A catalog sweep found 5/53 templates with unpinned images. Beyond version discipline, `:latest`
|
||||
breaks restore fidelity: the controller's recovery-unit `ImagePins` pins the *tag*, so restoring a
|
||||
`:latest` app re-pulls whatever `:latest` means at restore time — potentially schema-incompatible
|
||||
with the data being restored. Rule applied: a deployed app pins to the digest it is RUNNING
|
||||
(pin ≠ upgrade); undeployed apps pin to the verified upstream stable. All five pins are
|
||||
digest-identical to what `:latest` resolved to on 2026-07-12 — a pure no-op for running apps.
|
||||
|
||||
| App | Old | New | Evidence |
|
||||
|-----|-----|-----|----------|
|
||||
| bentopdf | `ghcr.io/alam00000/bentopdf:latest` | `:v2.8.6` | digest == latest (`eaeea1e4…`); undeployed |
|
||||
| calibre-web | `crocodilestick/calibre-web-automated:latest` | `:v4.0.6` | digest == RUNNING image on demo 9201 (`c31a738b…`) |
|
||||
| papra | `ghcr.io/papra-hq/papra:latest` | `:26.6.1-rootless` | latest == the -rootless variant (`a7a42e22…`); `-root` differs — variant preserved |
|
||||
| recipe-importer | `gitea.dooplex.hu/admin/recipe-importer:latest` | `:v0.9.11` | tag pre-existed in registry, digest == latest (`f3cb617c…`) — no retag needed |
|
||||
| termix | `ghcr.io/lukegus/termix:latest` | `:2.5.0` | digest == latest == release-2.5.0 (`4d337131…`); undeployed |
|
||||
|
||||
- New rerunnable gate `scripts/check-image-pins.py`: fails on `:latest`/`dev`/`nightly`/`edge`/
|
||||
`main`/`master` AND on untagged image refs (implicit :latest); `@sha256:` digests count as pinned.
|
||||
Red-proofed both shapes (revert→exit 1→restore).
|
||||
- Standing rule added to `CLAUDE.md` (never :latest / untagged; deployed apps pin to running digest).
|
||||
- `templates.json` carries no image strings (legacy metadata only) — untouched.
|
||||
- Fleet caveat: non-deployment of bentopdf/papra/termix verified on demo 9201 only; felhotest
|
||||
unreachable + Peti's box offline at sweep time (operator approved proceeding — pins are
|
||||
digest-equal to latest, so worst case equals the status quo).
|
||||
|
||||
## 2026-07-06 — healthcheck sweep: `localhost` → `127.0.0.1` across all 48 templates
|
||||
|
||||
Escalation of the re-run vaultwarden observation
|
||||
|
||||
Reference in New Issue
Block a user