Skip to content

Index images by RepoDigests in LocalImagesCache, not just RepoTags#11948

Open
itsmehotpants wants to merge 1 commit into
testcontainers:mainfrom
itsmehotpants:fix/1406-image-cache-repodigests
Open

Index images by RepoDigests in LocalImagesCache, not just RepoTags#11948
itsmehotpants wants to merge 1 commit into
testcontainers:mainfrom
itsmehotpants:fix/1406-image-cache-repodigests

Conversation

@itsmehotpants

Copy link
Copy Markdown

Fixes #1406.

LocalImagesCache.populateFromList() only indexed local images by their RepoTags. An image reachable only by digest (e.g. docker pull image@sha256:...) - or a tagged image where Docker reports RepoTags as null/["<none>:<none>"] after certain rebuild/retag sequences, while RepoDigests remains populated (see moby/moby#29157 for a concrete real-world case of this) - was never added to the cache. Testcontainers would then treat the image as absent locally and re-pull it every time, even though it was already present, defeating both the configured ImagePullPolicy and any lookup of an image by digest.

Change: populateFromList() now also reads Image::getRepoDigests() and indexes those digest-qualified names into the same cache, alongside RepoTags. An image with neither field populated is still skipped, as before (just with an updated log message reflecting the new condition).

Tests: added LocalImagesCacheTest covering a digest-only image, an image with both a tag and a digest, and the neither-present case. Uses the same ObjectMapper#convertValue(Map, Class) pattern already used in ReusabilityUnitTests for constructing docker-java model objects in tests, and the existing (previously unused) LocalImagesCacheAccessor test helper for cache isolation between tests.

Scope note: I did not additionally add Image ID-based lookup (mentioned in the issue's 2020 edit) since DockerImageName parsing doesn't cleanly represent a bare image ID (e.g. sha256:abcdef... without a repository) today - that would need its own design discussion, so I've kept this PR focused on the RepoDigests fix. Happy to look at Image ID support separately if maintainers want it.

LocalImagesCache.populateFromList() only indexed local images by their
RepoTags. An image referenced only by digest (e.g. after 'docker pull
image@sha256:...', or when Docker reports RepoTags as null/<none> for an
otherwise-tagged image, which happens after certain rebuild/retag
sequences) was never added to the cache. Testcontainers would then treat
the image as absent locally and re-pull it every time, even though it was
already present, defeating both the image pull policy and Ryuk/reaper
image lookups by digest.

populateFromList() now also reads Image::getRepoDigests() and indexes
those digest-qualified names into the same cache, alongside RepoTags. An
image with neither populated is still skipped, as before.

Added LocalImagesCacheTest covering: digest-only images, images with both
a tag and a digest, and the neither-present case. Uses the same
ObjectMapper#convertValue(Map, Class) pattern already used in
ReusabilityUnitTests for constructing docker-java model objects in tests,
and the existing (previously unused) LocalImagesCacheAccessor for cache
isolation between tests.

Fixes testcontainers#1406
@itsmehotpants
itsmehotpants requested a review from a team as a code owner July 26, 2026 17:47
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.

Image cache lookup should support SHA256 digests and Image IDs

1 participant