Skip to content

Pin container images to digest and automate updates - #884

Draft
masa213f wants to merge 13 commits into
mainfrom
image-digest
Draft

Pin container images to digest and automate updates#884
masa213f wants to merge 13 commits into
mainfrom
image-digest

Conversation

@masa213f

Copy link
Copy Markdown
Contributor

Change container image references from repo:tag to repo:tag@sha256:...
to prevent supply chain attacks via tag mutation. Also automate digest
fetching to reduce maintenance overhead.

Image definitions are split out of images.go into a new images_gen.go.
images.go retains the Image type definition and AllImages() function,
while individual image constants are managed in images_gen.go, which is
written by the generator.

The generator (pkg/update-images/main.go) calls the GitHub Packages API
via the gh CLI to fetch the latest tag and digest for each image and
overwrites images_gen.go. Running it requires gh auth login with the
read:packages scope.

The PullImage implementation is updated. Previously it listed images via
docker image list and matched by tag, which does not work with
digest-pinned references. It now checks existence using docker image
inspect with the full reference (repo:tag@sha256:...). Error output from
inspect and pull failures is also included in returned errors.

@masa213f
masa213f force-pushed the image-digest branch 2 times, most recently from 211207c to 44ed338 Compare May 28, 2026 08:37
masa213f added 2 commits June 11, 2026 18:35
Change container image references from repo:tag to repo:tag@sha256:...
to prevent supply chain attacks via tag mutation. Also automate digest
fetching to reduce maintenance overhead.

Image definitions are split out of images.go into a new images_gen.go.
images.go retains the Image type definition and AllImages() function,
while individual image constants are managed in images_gen.go, which is
written by the generator.

The generator (pkg/update-images/main.go) calls the GitHub Packages API
via the gh CLI to fetch the latest tag and digest for each image and
overwrites images_gen.go. Running it requires gh auth login with the
read:packages scope.

The PullImage implementation is updated. Previously it listed images via
docker image list and matched by tag, which does not work with
digest-pinned references. It now checks existence using docker image
inspect with the full reference (repo:tag@sha256:...). Error output from
inspect and pull failures is also included in returned errors.
masa213f and others added 11 commits June 18, 2026 13:48
Images loaded via docker load from a tar archive have a tag but no
RepoDigest, causing the digest-only check to fail and falling through
to a pull that also fails in air-gapped environments.

Add Image.Tag() and fall back to tag-based matching so tar-loaded
images are recognised as already present without attempting a pull.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ility

docker run with a digest reference fails for images loaded via docker load
because tar-loaded images have no RepoDigest. Since PullImage already
verifies image presence (by digest or tag), docker run can safely use
repo:tag with --pull=never to prevent unintended pulls.

Add Image.TagRef() and Image.DigestRef() helpers and use them throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace `type Image string` with a struct holding fullRef, tagRef, and
digestRef as precomputed fields, eliminating repeated string parsing and
concatenation on every call.

Add newImage(repository, tag, digest) constructor used by generated code.
Rename Name() to FullRef() and align TagRef()/DigestRef() as the complete
set of reference accessors.

Update all call sites: ServiceStatus.Image comparisons use TagRef() to
match the tag-based docker run, resource image annotations use FullRef()
for digest-pinned references.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Change docker image list format to FullRef style (repo:tag@digest) so
each output line can be compared directly against img.FullRef() or
img.TagRef()+"@<none>", removing the need to split lines into fields.

This also correctly rejects images where the tag matches but the digest
differs — the previous field-based approach would have accepted them.

Remove DigestRef() method and digestRef field from Image as they are no
longer used anywhere.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pulling by FullRef (repo:tag@sha256:...) causes Docker to store the image
with a <none> tag, making docker run by TagRef fail. Add a docker image tag
step after pull to assign the tag.

Prefix error messages with the failing command and its arguments so pull
and tag failures can be distinguished in logs.

Update image-pull.md to document the two-step pull+tag behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…code, verify pull/tag events in mtest

- Add DigestRef() (repo@sha256:digest) to Image type for digest-only pulls
- Use DigestRef in PullImage instead of FullRef so docker pull does not set a tag
- Move AllImages from images.go to images_gen.go as a var, auto-generated by update-images
- mtest: split image check into two By() blocks; verify pull events use known DigestRef,
  tag events map each digest to the expected TagRef, and running containers use TagRef format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Running containers use TagRef (repo:tag, no digest) due to --pull=never,
consistent with operators_test.go.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@masa213f
masa213f marked this pull request as draft July 3, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants