ci: tag the trivy image so the reclaim step stops deleting it
ci / lint (push) Successful in 26s
ci / types (push) Successful in 34s
ci / unit (push) Successful in 26s
ci / security (push) Successful in 38s
ci / dockerfile (push) Successful in 5s
ci / integration (push) Successful in 42s
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / chart (push) Successful in 9s
ci / image (api) (push) Successful in 2m13s
ci / bump (push) Has been skipped

Run #68 re-pulled trivy in all three matrix legs — 178MB each, ~7s each —
because the reclaim step deletes it at the end of every leg:

  Unable to find image 'aquasec/trivy:0.72.0@sha256:cffe...' locally
  untagged: aquasec/trivy@sha256:cffe...
  Total reclaimed space: 178.6MB

The `--filter until=168h` I added for exactly this reason does not work.
That filter reads the image's CREATED timestamp, not the pull time, and
aquasec/trivy:0.72.0 was built months ago, so it matches immediately. The
comment claiming the age filter fixed this was wrong; corrected in place.

Pull by digest, tag it, run the tag. A tagged image is not dangling, which
is what actually takes it out of `docker image prune`'s scope. The digest
is still the pin — enforced at pull time.

Everything else in run #68 is clean: 76 unit (98.59% coverage), 112
integration, 18 CACHED layers per image job, zero uv hardlink warnings,
and the trivy DB volume hit on 2 of 3 legs (one download, two silent).
This commit is contained in:
Nguyen Minh Phuc
2026-07-21 15:11:20 +00:00
parent 95a894d816
commit 58ffb9c2e0
+31 -7
View File
@@ -431,11 +431,30 @@ jobs:
# comment here claimed, so the retention story matters. Trivy replaces the DB in # comment here claimed, so the retention story matters. Trivy replaces the DB in
# place rather than accumulating versions, so the volume stays at roughly one DB, # place rather than accumulating versions, so the volume stays at roughly one DB,
# and the weekly prune CronJob reclaims it at the cost of one re-download. # and the weekly prune CronJob reclaims it at the cost of one re-download.
env:
TRIVY: aquasec/trivy:0.72.0@sha256:cffe3f5161a47a6823fbd23d985795b3ed72a4c806da4c4df16266c02accdd6f
run: | run: |
# Pull by digest, then give it a local tag, and run the TAG.
#
# An image pulled by digest carries no tag, which makes it dangling the moment its
# container exits — so the reclaim step below deleted it at the end of every matrix
# leg and the next leg paid a 178MB re-pull. Three legs, three pulls, every run.
#
# The `until=168h` filter there does not save it. That filter reads the image's
# CREATED timestamp, not when it was pulled, and this image was built months ago,
# so it matches the age filter immediately. A tag is what actually takes an image
# out of `docker image prune`'s scope. Verified in run #68: "Unable to find image
# ... locally" in all three legs, and "untagged: aquasec/trivy@sha256:cffe..." in
# each prune.
#
# The digest is still the pin — it is enforced here, at pull time. `trivy:pinned`
# is a local alias for an image whose content was already verified.
docker pull "${TRIVY}"
docker tag "${TRIVY}" trivy:pinned
docker run --rm \ docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
-v svcforge-trivy-db:/root/.cache/trivy \ -v svcforge-trivy-db:/root/.cache/trivy \
aquasec/trivy:0.72.0@sha256:cffe3f5161a47a6823fbd23d985795b3ed72a4c806da4c4df16266c02accdd6f \ trivy:pinned \
image \ image \
--severity HIGH,CRITICAL \ --severity HIGH,CRITICAL \
--ignore-unfixed \ --ignore-unfixed \
@@ -482,12 +501,17 @@ jobs:
# #
# Named volumes are never pruned here: that is where the trivy vuln DB lives. # Named volumes are never pruned here: that is where the trivy vuln DB lives.
# #
# Both prunes carry an age filter, because "dangling" catches more than it looks. # "Dangling" catches more than it looks: an image pulled by digest has no tag, so it
# An image pulled by digest has no tag, so it is dangling the moment its container # is dangling as soon as its container exits. That is why the trivy scan step tags
# exits. A bare `docker image prune -f` therefore deleted the trivy image on every # its image — an age filter does NOT protect it, because `until` reads the image's
# run and bought back a 157MB pull on the next one. The act runner image survived # created time, and a released tool image is always older than any useful window.
# that only by accident: this step executes inside an act container, so the image # Run #68 proved that: trivy was untagged and deleted in all three legs despite
# is in use exactly while the prune runs. Relying on that is not a design. # `until=168h`, and re-pulled 178MB each time.
#
# The age filter stays anyway, for the buildx cache, which really does grow by age.
# The act runner image survives only because this step runs inside an act container,
# so the image is in use exactly while the prune runs. That is luck, not design; if
# it ever starts disappearing, tag it the same way.
if: always() if: always()
run: | run: |
docker image prune -f --filter until=168h docker image prune -f --filter until=168h