Repository navigation
backups: redisBackupClientImage is committed as a bare tag, against the tag+digest rule #4264
Description
Describe the bug
packages/system/backupstrategy-controller/values.yaml:57 commits a first-party image reference with a tag and no digest:
redisBackupClientImage: "ghcr.io/cozystack/cozystack/redis-backup:v1.6.0"docs/agents/image-refs.md:45 rules that out in as many words: "Every first-party reference is tag+digest. A bare tag with no digest is not reproducible and must not be committed."
Environment
- Cozystack:
main
To Reproduce
$ git show origin/main:packages/system/backupstrategy-controller/values.yaml | grep -n redisBackupClientImage
57: redisBackupClientImage: "ghcr.io/cozystack/cozystack/redis-backup:v1.6.0"
Expected behaviour
The committed value carries the digest the build stamps, as its two siblings in the same file do (chBackupClientImage, rabbitmqBackupClientImage).
Actual behaviour
Tag only. The pin is not reproducible: whatever v1.6.0 resolves to at pull time is what runs.
Additional context
This is not a missing producer. packages/system/backupstrategy-controller/Makefile:32-33 stamps the key with a digest on every build:
IMAGE="$(REGISTRY)/redis-backup:$(IMAGE_TAG)@$$(yq e '."containerimage.digest"' images/redis-backup.json -o json -r)" \
yq -i '.backupStrategyController.redisBackupClientImage = strenv(IMAGE)' values.yaml
So the build writes tag@sha256:… and the committed copy carries only the tag. It arrived that way in b0eb10427 (2026-08-28, the Redis driver) and has stayed.
Worth fixing beyond the rule itself: this exact line is what made the whole file drift in the image overlay, because the classifier recognised its siblings only through their @sha256: and had no branch for a suffixed key. #4261 fixes the classifier, so the overlay no longer depends on the digest being there — but the reference is still not reproducible, and the next reader has no way to tell which build v1.6.0 meant.
Checklist
- I have checked the documentation
- I have searched for similar issues
- I have included all required information
- I have provided clear steps to reproduce
- I have included relevant logs
Activity
IvanHunters commentedon Sep 15, 2026
Two things this issue understates.
The tag does not exist.
redis-backuppublishes nightly tags and nothing else, so the committed reference does not merely lack a digest, it resolves to nothing:The control matters: the method finds a released first-party tag when there is one, so the empty answer for
redis-backupis a fact about the registry rather than about the query.This changes what the fix is. Writing a digest beside the tag is not possible while nothing is published under it; the image needs a release tag first, and only then can the reference be pinned. Until that happens, any lane falling back to the committed reference cannot pull it at all.
A second reference has the same shape, one step worse.
packages/system/migration-controller/values.yaml:2:A floating tag is not merely unreproducible: it is a reference whose bytes change under a cluster that never asked for a new version. Anonymous pull of that repository is refused (HTTP 403 on the token endpoint) while
cozystack-apiis public, so it is either private or absent, and the committed fallback is unusable for the same reason as the one above.Both keys DO have a producer, which is worth stating because the sibling comment in
packages/core/platform/Makefiledescribes a key that had none and froze at v1.4.0-rc.2.redisBackupClientImageis stamped bypackages/system/backupstrategy-controller/MakefileandmigrationController.imagebypackages/system/migration-controller/Makefile. So the stamp is fine and the committed value is the fallback used by every lane that does not rebuild the package, which is exactly where an unpublished or floating tag does its damage.Related: the bare-tag spelling of
redisBackupClientImageis also what costbackupstrategy-controllerits image overlay in e2e (#4257), because a key ending inImagewith no digest read as a config change. That half is fixed in #4261; the pin itself is this issue.ci(e2e): surface overlay drift and remove both causes of it (#4261)