From 94f58e91874f10036059d64a597b9c717f8e4f26 Mon Sep 17 00:00:00 2001 From: Kayokoi <113896798+wozhenbang2004@users.noreply.github.com> Date: Thu, 5 Nov 2026 11:00:40 +0800 Subject: [PATCH 1/3] Reject repeated image digests --- .../org/testcontainers/utility/DockerImageName.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/DockerImageName.java b/core/src/main/java/org/testcontainers/utility/DockerImageName.java index b3babc29c91..ef361b982e6 100644 --- a/core/src/main/java/org/testcontainers/utility/DockerImageName.java +++ b/core/src/main/java/org/testcontainers/utility/DockerImageName.java @@ -87,14 +87,19 @@ public DockerImageName(String fullImageName) { } if (remoteName.contains("@sha256:")) { - String beforeDigest = remoteName.split("@sha256:")[0]; + String[] nameAndDigest = remoteName.split("@sha256:", 3); + if (nameAndDigest.length != 2 || nameAndDigest[1].isEmpty()) { + throw new IllegalArgumentException("Invalid SHA-256 digest in Docker image name: " + fullImageName); + } + String beforeDigest = nameAndDigest[0]; + String digest = nameAndDigest[1]; if (beforeDigest.contains(":")) { repository = beforeDigest.split(":")[0]; String tag = beforeDigest.split(":", 2)[1]; - versioning = new Sha256Versioning(remoteName.split("@sha256:")[1], tag); + versioning = new Sha256Versioning(digest, tag); } else { repository = beforeDigest; - versioning = new Sha256Versioning(remoteName.split("@sha256:")[1]); + versioning = new Sha256Versioning(digest); } } else if (remoteName.contains(":")) { repository = remoteName.split(":")[0]; From 0872613e370eb093793c1972530caeb0082e9932 Mon Sep 17 00:00:00 2001 From: Kayokoi <113896798+wozhenbang2004@users.noreply.github.com> Date: Thu, 5 Nov 2026 11:01:19 +0800 Subject: [PATCH 2/3] Cover repeated digest image references --- .../org/testcontainers/utility/DockerImageNameTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index 5b42322d678..4122c741ec2 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -60,6 +60,15 @@ void testInvalidNameRejected(String imageName) { assertThatThrownBy(() -> DockerImageName.parse(imageName).assertValid()) .isInstanceOf(IllegalArgumentException.class); } + + @Test + void rejectsRepeatedDigestWhenParsing() { + String digest = "1234abcd1234abcd1234abcd1234abcd"; + assertThatThrownBy(() -> DockerImageName.parse("myname@sha256:" + digest + "@sha256:" + digest)) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> DockerImageName.parse("myname:latest@sha256:" + digest + "@sha256:" + digest)) + .isInstanceOf(IllegalArgumentException.class); + } } @Nested From b9d639da525f78eb63d3c6f14e92323d59c67ffa Mon Sep 17 00:00:00 2001 From: Kayokoi <113896798+wozhenbang2004@users.noreply.github.com> Date: Thu, 5 Nov 2026 11:11:34 +0800 Subject: [PATCH 3/3] Cover trailing image digest delimiters --- .../testcontainers/utility/DockerImageNameTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java index 4122c741ec2..55605e767c0 100644 --- a/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java +++ b/core/src/test/java/org/testcontainers/utility/DockerImageNameTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import java.util.stream.Stream; @@ -61,12 +62,13 @@ void testInvalidNameRejected(String imageName) { .isInstanceOf(IllegalArgumentException.class); } - @Test - void rejectsRepeatedDigestWhenParsing() { - String digest = "1234abcd1234abcd1234abcd1234abcd"; - assertThatThrownBy(() -> DockerImageName.parse("myname@sha256:" + digest + "@sha256:" + digest)) + @ParameterizedTest + @ValueSource(strings = { "", "1234abcd1234abcd1234abcd1234abcd" }) + void rejectsRepeatedDigestWhenParsing(String secondDigest) { + String digestSuffix = "@sha256:1234abcd1234abcd1234abcd1234abcd@sha256:" + secondDigest; + assertThatThrownBy(() -> DockerImageName.parse("myname" + digestSuffix)) .isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> DockerImageName.parse("myname:latest@sha256:" + digest + "@sha256:" + digest)) + assertThatThrownBy(() -> DockerImageName.parse("myname:latest" + digestSuffix)) .isInstanceOf(IllegalArgumentException.class); } }