diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java index 9dc84712b98..01943c8b23b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java @@ -237,14 +237,14 @@ public class Builder { () -> String.format("%s '%s' must be pulled from the '%s' authenticated registry", StringUtils.capitalize(type.getDescription()), reference, this.domain)); if (this.pullPolicy == PullPolicy.ALWAYS) { - return pullImage(reference, type); + return checkPlatformMismatch(pullImage(reference, type), reference); } try { - return Builder.this.docker.image().inspect(reference); + return checkPlatformMismatch(Builder.this.docker.image().inspect(reference), reference); } catch (DockerEngineException ex) { if (this.pullPolicy == PullPolicy.IF_NOT_PRESENT && ex.getStatusCode() == 404) { - return pullImage(reference, type); + return checkPlatformMismatch(pullImage(reference, type), reference); } throw ex; } @@ -261,6 +261,26 @@ public class Builder { return image; } + private Image checkPlatformMismatch(Image image, ImageReference imageReference) { + if (this.defaultPlatform != null) { + ImagePlatform imagePlatform = ImagePlatform.from(image); + if (!imagePlatform.equals(this.defaultPlatform)) { + throw new PlatformMismatchException(imageReference, this.defaultPlatform, imagePlatform); + } + } + return image; + } + + } + + private static final class PlatformMismatchException extends RuntimeException { + + private PlatformMismatchException(ImageReference imageReference, ImagePlatform requestedPlatform, + ImagePlatform actualPlatform) { + super("Image platform mismatch detected. The configured platform '%s' is not supported by the image '%s'. Requested platform '%s' but got '%s'" + .formatted(requestedPlatform, imageReference, requestedPlatform, actualPlatform)); + } + } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java index 1d0dc3824f7..dcc6f723ba2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java @@ -513,6 +513,14 @@ class BootBuildImageIntegrationTests { assertThat(result.getOutput()).containsPattern("Each image building cache can be configured only once"); } + @TestTemplate + void failsWithIncompatiblePlatform() throws IOException { + writeMainClass(); + BuildResult result = this.gradleBuild.buildAndFail("bootBuildImage"); + assertThat(result.getOutput()).contains( + "Image platform mismatch detected. The configured platform 'invalid/platform' is not supported by the image 'ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1'. Requested platform 'invalid/platform' but got 'linux/amd64'"); + } + private void writeMainClass() throws IOException { File examplePackage = new File(this.gradleBuild.getProjectDir(), "src/main/java/example"); examplePackage.mkdirs(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithIncompatiblePlatform.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithIncompatiblePlatform.gradle new file mode 100644 index 00000000000..ab3a25f1bd0 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithIncompatiblePlatform.gradle @@ -0,0 +1,11 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '{version}' +} + +bootBuildImage { + builder = "ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1" + runImage = "paketobuildpacks/run-jammy-tiny" + buildpacks = ["ghcr.io/spring-io/spring-boot-test-info:0.0.1"] + imagePlatform = "invalid/platform" +}