Keep the tag of image references pinned by tag and digest - #1469
Merged
Merged
Conversation
ImageName.fromString split name:tag@digest at the @ first, leaving the tag inside the image name and exposing the digest as the tag. Modules that read the version from imageName.tag then misbehaved: MongoDB fell back to the legacy mongo shell and never became healthy, and Kafka threw in its constructor. Split off the digest first, read the tag from what precedes it, and expose the digest via a new optional digest field.
✅ Deploy Preview for testcontainers-node ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
cristianrgreco
commented
Sep 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ImageName.fromStringsplitname:tag@digestreferences at the@first. Formongo:8@sha256:…that gaveimage = "mongo:8"andtag = "sha256:…": the tag stayed inside the image name and.tagheld the digest..stringstill round-tripped, so pulling and running worked, but modules that read the version fromimageName.tagmisbehaved:isV5OrLater()returnedfalse, so the health check used the legacymongoshell.mongo:5+images don't ship it, so the container never became healthy (the behaviour reported in ImageName.fromString drops the tag of a name:tag@sha256:<digest> reference, so MongoDBContainer picks the legacy mongo shell and never becomes healthy #1468).satisfies("sha256:…", ">=8.0.0")threwInvalid argument not valid semverin theKafkaContainerconstructor.This PR:
digestconstructor argument and public field onImageName. It is set whenever the reference has a digest, including digest-only references (image@sha256:…). For those,tagstill holds the digest, as before.stringasname:tag@digestwhen both are present.digestinequals.This follows the Java fix for the same bug (testcontainers/testcontainers-java#11629), where
getVersionPart()returns the tag and a newgetDigest()returns the digest. Unlike Java, no change to pulling is needed, because Node passes the fullimageName.stringtodockerode.pull.Verification
Test results
Red-green: I ran each test against the pre-fix implementation, then again after the fix.
image-name.test.ts: 4 new cases, plusdigestchecks on existing onesexpected 'image:tag' to be 'image'During development I also reproduced the module symptoms and confirmed the fix. These tests are not kept in the PR, so CI doesn't pull an extra image:
new KafkaContainer("confluentinc/cp-kafka:6.2.14@sha256:…").withKraft()threwInvalid argument not valid semverbefore the fix. After it, the error correctly reports version6.2.14.mongo:8.2.12@sha256:e0ce8c…failed withHealth check not healthy after 120000msbefore the fix and started after it.format,lintandcheck-compilesare clean.Why this is not breaking
.string, the only value used to pull and inspect images, is unchanged for every reference that already parsed correctly:image,image:tag,image@sha256:…, and references with a registry and port. Forname:tag@digestit was alreadyname:tag@digestand still is.tagstill returnssha256:….new ImageName(registry, image, tag)calls still compile and behave the same.ImageNametests pass unchanged.equalsnow also comparesdigest. For names built without a digest, the digest is derived from the tag, so existing comparisons give the same result.Closes #1468