mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Add support for security options in CNB builder container config
Closes gh-37479
This commit is contained in:
parent
4433fcd1f2
commit
7de770f6a1
@ -87,6 +87,8 @@ public class BuildRequest {
|
||||
|
||||
private final String applicationDirectory;
|
||||
|
||||
private final List<String> securityOptions;
|
||||
|
||||
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent) {
|
||||
Assert.notNull(name, "Name must not be null");
|
||||
Assert.notNull(applicationContent, "ApplicationContent must not be null");
|
||||
@ -109,13 +111,14 @@ public class BuildRequest {
|
||||
this.launchCache = null;
|
||||
this.createdDate = null;
|
||||
this.applicationDirectory = null;
|
||||
this.securityOptions = null;
|
||||
}
|
||||
|
||||
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,
|
||||
ImageReference runImage, Creator creator, Map<String, String> env, boolean cleanCache,
|
||||
boolean verboseLogging, PullPolicy pullPolicy, boolean publish, List<BuildpackReference> buildpacks,
|
||||
List<Binding> bindings, String network, List<ImageReference> tags, Cache buildWorkspace, Cache buildCache,
|
||||
Cache launchCache, Instant createdDate, String applicationDirectory) {
|
||||
Cache launchCache, Instant createdDate, String applicationDirectory, List<String> securityOptions) {
|
||||
this.name = name;
|
||||
this.applicationContent = applicationContent;
|
||||
this.builder = builder;
|
||||
@ -135,6 +138,7 @@ public class BuildRequest {
|
||||
this.launchCache = launchCache;
|
||||
this.createdDate = createdDate;
|
||||
this.applicationDirectory = applicationDirectory;
|
||||
this.securityOptions = securityOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,7 +151,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.runImage,
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,7 +163,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, runImageName.inTaggedOrDigestForm(),
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,7 +176,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,7 +193,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
|
||||
Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,7 +208,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
|
||||
Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging, this.pullPolicy,
|
||||
this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace,
|
||||
this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,7 +220,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,7 +232,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,7 +244,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,7 +256,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -277,7 +281,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,7 +306,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -315,7 +319,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,7 +342,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,7 +355,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,7 +368,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -377,7 +381,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -390,7 +394,7 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,
|
||||
parseCreatedDate(createdDate), this.applicationDirectory);
|
||||
parseCreatedDate(createdDate), this.applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
private Instant parseCreatedDate(String createdDate) {
|
||||
@ -415,7 +419,20 @@ public class BuildRequest {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
applicationDirectory);
|
||||
applicationDirectory, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an updated security options.
|
||||
* @param securityOptions the security options
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withSecurityOptions(List<String> securityOptions) {
|
||||
Assert.notNull(securityOptions, "SecurityOption must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory, securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -571,6 +588,14 @@ public class BuildRequest {
|
||||
return this.applicationDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the security options that should be used by the lifecycle.
|
||||
* @return the security options
|
||||
*/
|
||||
public List<String> getSecurityOptions() {
|
||||
return this.securityOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link BuildRequest} from a JAR file.
|
||||
* @param jarFile the source jar file
|
||||
|
@ -20,6 +20,7 @@ import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -58,6 +59,8 @@ class Lifecycle implements Closeable {
|
||||
|
||||
private static final String DOMAIN_SOCKET_PATH = "/var/run/docker.sock";
|
||||
|
||||
private static final List<String> DEFAULT_SECURITY_OPTIONS = List.of("label=disable");
|
||||
|
||||
private final BuildLog log;
|
||||
|
||||
private final DockerApi docker;
|
||||
@ -82,6 +85,8 @@ class Lifecycle implements Closeable {
|
||||
|
||||
private final String applicationDirectory;
|
||||
|
||||
private final List<String> securityOptions;
|
||||
|
||||
private boolean executed;
|
||||
|
||||
private boolean applicationVolumePopulated;
|
||||
@ -108,6 +113,7 @@ class Lifecycle implements Closeable {
|
||||
this.buildCache = getBuildCache(request);
|
||||
this.launchCache = getLaunchCache(request);
|
||||
this.applicationDirectory = getApplicationDirectory(request);
|
||||
this.securityOptions = getSecurityOptions(request);
|
||||
}
|
||||
|
||||
private Cache getBuildCache(BuildRequest request) {
|
||||
@ -128,6 +134,13 @@ class Lifecycle implements Closeable {
|
||||
return (request.getApplicationDirectory() != null) ? request.getApplicationDirectory() : Directory.APPLICATION;
|
||||
}
|
||||
|
||||
private List<String> getSecurityOptions(BuildRequest request) {
|
||||
if (request.getSecurityOptions() != null) {
|
||||
return request.getSecurityOptions();
|
||||
}
|
||||
return (Platform.isWindows()) ? Collections.emptyList() : DEFAULT_SECURITY_OPTIONS;
|
||||
}
|
||||
|
||||
private ApiVersion getPlatformVersion(BuilderMetadata.Lifecycle lifecycle) {
|
||||
if (lifecycle.getApis().getPlatform() != null) {
|
||||
String[] supportedVersions = lifecycle.getApis().getPlatform();
|
||||
@ -240,8 +253,8 @@ class Lifecycle implements Closeable {
|
||||
else {
|
||||
phase.withBinding(Binding.from(DOMAIN_SOCKET_PATH, DOMAIN_SOCKET_PATH));
|
||||
}
|
||||
if (!Platform.isWindows()) {
|
||||
phase.withSecurityOption("label=disable");
|
||||
if (this.securityOptions != null) {
|
||||
this.securityOptions.forEach(phase::withSecurityOption);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,6 +333,13 @@ class BuildRequestTests {
|
||||
assertThat(withAppDir.getApplicationDirectory()).isEqualTo("/application");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withSecurityOptionsSetsSecurityOptions() throws Exception {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
BuildRequest withAppDir = request.withSecurityOptions(List.of("label=user:USER", "label=role:ROLE"));
|
||||
assertThat(withAppDir.getSecurityOptions()).containsExactly("label=user:USER", "label=role:ROLE");
|
||||
}
|
||||
|
||||
private void hasExpectedJarContent(TarArchive archive) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
@ -23,6 +23,7 @@ import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@ -254,6 +255,17 @@ class LifecycleTests {
|
||||
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeWithSecurityOptionsExecutesPhases() throws Exception {
|
||||
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
|
||||
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
|
||||
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
|
||||
BuildRequest request = getTestRequest().withSecurityOptions(List.of("label=user:USER", "label=role:ROLE"));
|
||||
createLifecycle(request).execute();
|
||||
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-security-opts.json"));
|
||||
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeWithDockerHostAndRemoteAddressExecutesPhases() throws Exception {
|
||||
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
|
||||
|
@ -0,0 +1,40 @@
|
||||
{
|
||||
"User": "root",
|
||||
"Image": "pack.local/ephemeral-builder",
|
||||
"Cmd": [
|
||||
"/cnb/lifecycle/creator",
|
||||
"-app",
|
||||
"/workspace",
|
||||
"-platform",
|
||||
"/platform",
|
||||
"-run-image",
|
||||
"docker.io/cloudfoundry/run:latest",
|
||||
"-layers",
|
||||
"/layers",
|
||||
"-cache-dir",
|
||||
"/cache",
|
||||
"-launch-cache",
|
||||
"/launch-cache",
|
||||
"-daemon",
|
||||
"docker.io/library/my-application:latest"
|
||||
],
|
||||
"Env": [
|
||||
"CNB_PLATFORM_API=0.8"
|
||||
],
|
||||
"Labels": {
|
||||
"author": "spring-boot"
|
||||
},
|
||||
"HostConfig": {
|
||||
"Binds": [
|
||||
"/var/run/docker.sock:/var/run/docker.sock",
|
||||
"pack-layers-aaaaaaaaaa:/layers",
|
||||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"pack-cache-b35197ac41ea.build:/cache",
|
||||
"pack-cache-b35197ac41ea.launch:/launch-cache"
|
||||
],
|
||||
"SecurityOpt" : [
|
||||
"label=user:USER",
|
||||
"label=role:ROLE"
|
||||
]
|
||||
}
|
||||
}
|
@ -223,6 +223,11 @@ The value must be a string in the ISO 8601 instant format, or `now` to use the c
|
||||
Application contents will also be in this location in the generated image.
|
||||
| `/workspace`
|
||||
|
||||
| `securityOptions`
|
||||
| `--securityOptions`
|
||||
| https://docs.docker.com/engine/reference/run/#security-configuration[Security options] that will be applied to the builder container, provided as an array of string values
|
||||
| `["label=disable"]`
|
||||
|
||||
|===
|
||||
|
||||
NOTE: The plugin detects the target Java compatibility of the project using the JavaPlugin's `targetCompatibility` property.
|
||||
|
@ -302,6 +302,15 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
@Option(option = "applicationDirectory", description = "The directory containing application content in the image")
|
||||
public abstract Property<String> getApplicationDirectory();
|
||||
|
||||
/**
|
||||
* Returns the security options that will be applied to the builder container.
|
||||
* @return the security options
|
||||
*/
|
||||
@Input
|
||||
@Optional
|
||||
@Option(option = "securityOptions", description = "Security options that will be applied to the builder container")
|
||||
public abstract ListProperty<String> getSecurityOptions();
|
||||
|
||||
/**
|
||||
* Returns the Docker configuration the builder will use.
|
||||
* @return docker configuration.
|
||||
@ -349,6 +358,7 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
request = request.withNetwork(getNetwork().getOrNull());
|
||||
request = customizeCreatedDate(request);
|
||||
request = customizeApplicationDirectory(request);
|
||||
request = customizeSecurityOptions(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -450,4 +460,12 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
return request;
|
||||
}
|
||||
|
||||
private BuildRequest customizeSecurityOptions(BuildRequest request) {
|
||||
List<String> securityOptions = getSecurityOptions().getOrNull();
|
||||
if (securityOptions != null) {
|
||||
return request.withSecurityOptions(securityOptions);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -368,6 +368,19 @@ class BootBuildImageIntegrationTests {
|
||||
removeImages(projectName);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void buildsImageWithEmptySecurityOptions() throws IOException {
|
||||
writeMainClass();
|
||||
writeLongNameResource();
|
||||
BuildResult result = this.gradleBuild.build("bootBuildImage");
|
||||
String projectName = this.gradleBuild.getProjectDir().getName();
|
||||
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
assertThat(result.getOutput()).contains("docker.io/library/" + projectName);
|
||||
assertThat(result.getOutput()).contains("---> Test Info buildpack building");
|
||||
assertThat(result.getOutput()).contains("---> Test Info buildpack done");
|
||||
removeImages(projectName);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void failsWithInvalidCreatedDate() throws IOException {
|
||||
writeMainClass();
|
||||
|
@ -0,0 +1,15 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '{version}'
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
}
|
||||
|
||||
bootBuildImage {
|
||||
builder = "projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.2"
|
||||
pullPolicy = "IF_NOT_PRESENT"
|
||||
securityOptions = []
|
||||
}
|
@ -230,6 +230,10 @@ The value must be a string in the ISO 8601 instant format, or `now` to use the c
|
||||
Application contents will also be in this location in the generated image.
|
||||
| `/workspace`
|
||||
|
||||
| `securityOptions`
|
||||
| https://docs.docker.com/engine/reference/run/#security-configuration[Security options] that will be applied to the builder container, provided as an array of string values
|
||||
| `["label=disable"]`
|
||||
|
||||
|===
|
||||
|
||||
NOTE: The plugin detects the target Java compatibility of the project using the compiler's plugin configuration or the `maven.compiler.target` property.
|
||||
|
@ -480,6 +480,21 @@ class BuildImageTests extends AbstractArchiveIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void whenBuildImageIsInvokedWithEmptySecurityOptions(MavenBuild mavenBuild) {
|
||||
String testBuildId = randomString();
|
||||
mavenBuild.project("build-image-security-opts")
|
||||
.goals("package")
|
||||
.systemProperty("spring-boot.build-image.pullPolicy", "IF_NOT_PRESENT")
|
||||
.systemProperty("test-build-id", testBuildId)
|
||||
.execute((project) -> {
|
||||
assertThat(buildLog(project)).contains("Building image")
|
||||
.contains("docker.io/library/build-image-security-opts:0.0.1.BUILD-SNAPSHOT")
|
||||
.contains("Successfully built image");
|
||||
removeImage("build-image-security-opts", "0.0.1.BUILD-SNAPSHOT");
|
||||
});
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void failsWhenBuildImageIsInvokedOnMultiModuleProjectWithBuildImageGoal(MavenBuild mavenBuild) {
|
||||
mavenBuild.project("build-image-multi-module")
|
||||
|
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>build-image-security-opts</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>@java.version@</maven.compiler.source>
|
||||
<maven.compiler.target>@java.version@</maven.compiler.target>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>@project.groupId@</groupId>
|
||||
<artifactId>@project.artifactId@</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build-image-no-fork</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<image>
|
||||
<builder>projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.2</builder>
|
||||
<security-options/>
|
||||
</image>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.test;
|
||||
|
||||
public class SampleApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("Launched");
|
||||
synchronized(args) {
|
||||
args.wait(); // Prevent exit"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -79,6 +79,8 @@ public class Image {
|
||||
|
||||
String applicationDirectory;
|
||||
|
||||
List<String> securityOptions;
|
||||
|
||||
/**
|
||||
* The name of the created image.
|
||||
* @return the image name
|
||||
@ -260,6 +262,9 @@ public class Image {
|
||||
if (StringUtils.hasText(this.applicationDirectory)) {
|
||||
request = request.withApplicationDirectory(this.applicationDirectory);
|
||||
}
|
||||
if (this.securityOptions != null) {
|
||||
request = request.withSecurityOptions(this.securityOptions);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.boot.maven;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
@ -234,6 +235,22 @@ class ImageTests {
|
||||
assertThat(request.getApplicationDirectory()).isEqualTo("/application");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasSecurityOptionsUsesSecurityOptions() {
|
||||
Image image = new Image();
|
||||
image.securityOptions = List.of("label=user:USER", "label=role:ROLE");
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getSecurityOptions()).containsExactly("label=user:USER", "label=role:ROLE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasEmptySecurityOptionsUsesSecurityOptions() {
|
||||
Image image = new Image();
|
||||
image.securityOptions = Collections.emptyList();
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getSecurityOptions()).isEmpty();
|
||||
}
|
||||
|
||||
private Artifact createArtifact() {
|
||||
return new DefaultArtifact("com.example", "my-app", VersionRange.createFromVersion("0.0.1-SNAPSHOT"), "compile",
|
||||
"jar", null, new DefaultArtifactHandler());
|
||||
|
Loading…
Reference in New Issue
Block a user