Throw exception if pulled image platform doesn't match the requested platform

Closes gh-44059
This commit is contained in:
Moritz Halbritter 2025-03-07 09:28:17 +01:00
parent 282571ae1e
commit d93f4f5554
3 changed files with 44 additions and 5 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2024 the original author or authors. * Copyright 2012-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -236,14 +236,14 @@ public class Builder {
() -> String.format("%s '%s' must be pulled from the '%s' authenticated registry", () -> String.format("%s '%s' must be pulled from the '%s' authenticated registry",
StringUtils.capitalize(type.getDescription()), reference, this.domain)); StringUtils.capitalize(type.getDescription()), reference, this.domain));
if (this.pullPolicy == PullPolicy.ALWAYS) { if (this.pullPolicy == PullPolicy.ALWAYS) {
return pullImage(reference, type); return checkPlatformMismatch(pullImage(reference, type), reference);
} }
try { try {
return Builder.this.docker.image().inspect(reference); return checkPlatformMismatch(Builder.this.docker.image().inspect(reference), reference);
} }
catch (DockerEngineException ex) { catch (DockerEngineException ex) {
if (this.pullPolicy == PullPolicy.IF_NOT_PRESENT && ex.getStatusCode() == 404) { if (this.pullPolicy == PullPolicy.IF_NOT_PRESENT && ex.getStatusCode() == 404) {
return pullImage(reference, type); return checkPlatformMismatch(pullImage(reference, type), reference);
} }
throw ex; throw ex;
} }
@ -260,6 +260,26 @@ public class Builder {
return image; 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));
}
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2024 the original author or authors. * Copyright 2012-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -513,6 +513,14 @@ class BootBuildImageIntegrationTests {
assertThat(result.getOutput()).containsPattern("Each image building cache can be configured only once"); 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 { private void writeMainClass() throws IOException {
File examplePackage = new File(this.gradleBuild.getProjectDir(), "src/main/java/example"); File examplePackage = new File(this.gradleBuild.getProjectDir(), "src/main/java/example");
examplePackage.mkdirs(); examplePackage.mkdirs();

View File

@ -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"
}