-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Fix DockerImageName compatibility check when digest is present #11629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
6c576a5
6da85e7
a63de7c
3651ae9
61997ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,8 +87,15 @@ public DockerImageName(String fullImageName) { | |
| } | ||
|
|
||
| if (remoteName.contains("@sha256:")) { | ||
| repository = remoteName.split("@sha256:")[0]; | ||
| versioning = new Sha256Versioning(remoteName.split("@sha256:")[1]); | ||
| String beforeDigest = remoteName.split("@sha256:")[0]; | ||
| if (beforeDigest.contains(":")) { | ||
| repository = beforeDigest.split(":")[0]; | ||
| String tag = beforeDigest.split(":")[1]; | ||
| versioning = new Sha256Versioning(remoteName.split("@sha256:")[1], tag); | ||
| } else { | ||
| repository = beforeDigest; | ||
| versioning = new Sha256Versioning(remoteName.split("@sha256:")[1]); | ||
| } | ||
| } else if (remoteName.contains(":")) { | ||
| repository = remoteName.split(":")[0]; | ||
| versioning = new TagVersioning(remoteName.split(":")[1]); | ||
|
|
@@ -155,16 +162,40 @@ public String getUnversionedPart() { | |
| } | ||
|
|
||
| /** | ||
| * @return the versioned part of this name (tag or sha256) | ||
| * @return the versioned part of this name (tag or sha256). When both tag and digest are present, | ||
| * the tag is returned. | ||
|
Comment on lines
+165
to
+166
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean that the tag has a higher priority than the digest? If yes, I think that is not a good idea, because version tags are mutable and can suddenly point to another build. In contrast, digests are immutable and will always point to the exact same build. In light of recent supply chain attacks, preferring digests over tags is of particular importance.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @burneyy , great point on supply chain security — and you're right that tags are mutable while digests are immutable. However, getVersionPart() returning the tag is intentional here. It's used exclusively for version-based compatibility checks in modules like KafkaContainer, ElasticsearchContainer, Neo4jContainer, etc., where a human-readable version string (e.g. 7.3.0) is needed for version comparisons. The actual image pulling in RemoteDockerImage already prefers the digest: String pullTag = imageName.getDigest() != null ? imageName.getDigest() : imageName.getVersionPart(); So when both tag and digest are present, the image is always pulled by its immutable digest — the tag is never used for pulling. The security concern is therefore already handled. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @konstantinosGkilas, |
||
| */ | ||
| public String getVersionPart() { | ||
| if (versioning instanceof Sha256Versioning) { | ||
| String tag = ((Sha256Versioning) versioning).getTag(); | ||
| if (tag != null) { | ||
| return tag; | ||
| } | ||
| } | ||
| return versioning.toString(); | ||
| } | ||
|
|
||
| /** | ||
| * @return the sha256 digest if present, or null | ||
| */ | ||
| @Nullable | ||
| public String getDigest() { | ||
| if (versioning instanceof Sha256Versioning) { | ||
| return versioning.toString(); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * @return canonical name for the image | ||
| */ | ||
| public String asCanonicalNameString() { | ||
| if (versioning instanceof Sha256Versioning) { | ||
| String tag = ((Sha256Versioning) versioning).getTag(); | ||
| if (tag != null) { | ||
| return getUnversionedPart() + ":" + tag + "@" + versioning; | ||
| } | ||
| } | ||
| return getUnversionedPart() + versioning.getSeparator() + getVersionPart(); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,8 +79,20 @@ class Sha256Versioning implements Versioning { | |
|
|
||
| private final String hash; | ||
|
|
||
| @EqualsAndHashCode.Exclude | ||
| private final String tag; | ||
|
|
||
| Sha256Versioning(String hash) { | ||
| this(hash, null); | ||
| } | ||
|
|
||
| Sha256Versioning(String hash, String tag) { | ||
| this.hash = hash; | ||
| this.tag = tag; | ||
| } | ||
|
Comment on lines
+88
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
After introducing the optional Useful? React with 👍 / 👎. |
||
|
|
||
| String getTag() { | ||
| return tag; | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch assumes
beforeDigest.split(":")[1]always exists, but Java drops trailing empty segments, so an input likerepo:@sha256:...throwsArrayIndexOutOfBoundsExceptionduring parse instead of being rejected cleanly byassertValid(). That turns a user-facing validation error into an unexpected runtime crash path for malformed image names.Useful? React with 👍 / 👎.