diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java index bd9d34ddc6..76bedefd10 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java @@ -45,9 +45,20 @@ import org.springframework.util.Assert; */ public class BuildRequest { - static final String DEFAULT_BUILDER_IMAGE_NAME = "paketobuildpacks/builder-jammy-tiny:latest"; + static final String DEFAULT_BUILDER_IMAGE_NAME = "paketobuildpacks/builder-jammy-tiny"; - private static final ImageReference DEFAULT_BUILDER = ImageReference.of(DEFAULT_BUILDER_IMAGE_NAME); + static final String DEFAULT_BUILDER_IMAGE_REF = DEFAULT_BUILDER_IMAGE_NAME + ":latest"; + + static final List KNOWN_TRUSTED_BUILDERS = List.of( + ImageReference.of("paketobuildpacks/builder-jammy-tiny"), + ImageReference.of("paketobuildpacks/builder-jammy-base"), + ImageReference.of("paketobuildpacks/builder-jammy-full"), + ImageReference.of("paketobuildpacks/builder-jammy-buildpackless-tiny"), + ImageReference.of("paketobuildpacks/builder-jammy-buildpackless-base"), + ImageReference.of("paketobuildpacks/builder-jammy-buildpackless-full"), + ImageReference.of("gcr.io/buildpacks/builder"), ImageReference.of("heroku/builder")); + + private static final ImageReference DEFAULT_BUILDER = ImageReference.of(DEFAULT_BUILDER_IMAGE_REF); private final ImageReference name; @@ -55,6 +66,8 @@ public class BuildRequest { private final ImageReference builder; + private final Boolean trustBuilder; + private final ImageReference runImage; private final Creator creator; @@ -95,6 +108,7 @@ public class BuildRequest { this.name = name.inTaggedForm(); this.applicationContent = applicationContent; this.builder = DEFAULT_BUILDER; + this.trustBuilder = null; this.runImage = null; this.env = Collections.emptyMap(); this.cleanCache = false; @@ -118,7 +132,8 @@ public class BuildRequest { ImageReference runImage, Creator creator, Map env, boolean cleanCache, boolean verboseLogging, PullPolicy pullPolicy, boolean publish, List buildpacks, List bindings, String network, List tags, Cache buildWorkspace, Cache buildCache, - Cache launchCache, Instant createdDate, String applicationDirectory, List securityOptions) { + Cache launchCache, Instant createdDate, String applicationDirectory, List securityOptions, + Boolean trustBuilder) { this.name = name; this.applicationContent = applicationContent; this.builder = builder; @@ -139,6 +154,7 @@ public class BuildRequest { this.createdDate = createdDate; this.applicationDirectory = applicationDirectory; this.securityOptions = securityOptions; + this.trustBuilder = trustBuilder; } /** @@ -151,7 +167,20 @@ 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.securityOptions); + this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.trustBuilder); + } + + /** + * Return a new {@link BuildRequest} with an updated trust builder setting. + * @param trustBuilder {@code true} if the builder should be treated as trusted, + * {@code false} otherwise + * @return an updated build request + */ + public BuildRequest withTrustBuilder(boolean trustBuilder) { + 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, this.securityOptions, trustBuilder); } /** @@ -163,7 +192,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.securityOptions); + this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -176,7 +205,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -193,7 +222,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.securityOptions); + this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -208,7 +237,8 @@ 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.securityOptions); + this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, + this.trustBuilder); } /** @@ -220,7 +250,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -232,7 +262,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -244,7 +274,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -256,7 +286,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -281,7 +311,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -306,7 +336,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -319,7 +349,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -342,7 +372,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -356,7 +386,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -369,7 +399,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -382,7 +412,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.securityOptions); + this.applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -395,7 +425,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, this.securityOptions); + parseCreatedDate(createdDate), this.applicationDirectory, this.securityOptions, this.trustBuilder); } private Instant parseCreatedDate(String createdDate) { @@ -420,7 +450,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, this.createdDate, - applicationDirectory, this.securityOptions); + applicationDirectory, this.securityOptions, this.trustBuilder); } /** @@ -434,7 +464,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, this.createdDate, - this.applicationDirectory, securityOptions); + this.applicationDirectory, securityOptions, this.trustBuilder); } /** @@ -464,6 +494,19 @@ public class BuildRequest { return this.builder; } + /** + * Return whether the builder should be treated as trusted. + * @return the trust builder flag + * @since 3.4.0 + */ + public boolean isTrustBuilder() { + return (this.trustBuilder != null) ? this.trustBuilder : isBuilderKnownAndTrusted(); + } + + private boolean isBuilderKnownAndTrusted() { + return KNOWN_TRUSTED_BUILDERS.stream().anyMatch((builder) -> builder.getName().equals(this.builder.getName())); + } + /** * Return the run image that should be used, if provided. * @return the run image diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java index 3a68b6d99d..98c58ae984 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java @@ -161,43 +161,104 @@ class Lifecycle implements Closeable { if (this.request.isCleanCache()) { deleteCache(this.buildCache); } - run(createPhase()); + if (this.request.isTrustBuilder()) { + run(createPhase()); + } + else { + run(analyzePhase()); + run(detectPhase()); + if (!this.request.isCleanCache()) { + run(restorePhase()); + } + else { + this.log.skippingPhase("restorer", "because 'cleanCache' is enabled"); + } + run(buildPhase()); + run(exportPhase()); + } this.log.executedLifecycle(this.request); } private Phase createPhase() { Phase phase = new Phase("creator", isVerboseLogging()); - phase.withDaemonAccess(); + phase.withApp(this.applicationDirectory, + Binding.from(getCacheBindingSource(this.application), this.applicationDirectory)); + phase.withPlatform(Directory.PLATFORM); + phase.withRunImage(this.request.getRunImage()); + phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); + phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + phase.withLaunchCache(Directory.LAUNCH_CACHE, + Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); configureDaemonAccess(phase); - phase.withLogLevelArg(); - phase.withArgs("-app", this.applicationDirectory); - phase.withArgs("-platform", Directory.PLATFORM); - phase.withArgs("-run-image", this.request.getRunImage()); - phase.withArgs("-layers", Directory.LAYERS); - phase.withArgs("-cache-dir", Directory.CACHE); - phase.withArgs("-launch-cache", Directory.LAUNCH_CACHE); - phase.withArgs("-daemon"); if (this.request.isCleanCache()) { - phase.withArgs("-skip-restore"); + phase.withSkipRestore(); } if (requiresProcessTypeDefault()) { - phase.withArgs("-process-type=web"); + phase.withProcessType("web"); } - phase.withArgs(this.request.getName()); - phase.withBinding(Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); - phase.withBinding(Binding.from(getCacheBindingSource(this.application), this.applicationDirectory)); - phase.withBinding(Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); - phase.withBinding(Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); - if (this.request.getBindings() != null) { - this.request.getBindings().forEach(phase::withBinding); - } - phase.withEnv(PLATFORM_API_VERSION_KEY, this.platformVersion.toString()); - if (this.request.getNetwork() != null) { - phase.withNetworkMode(this.request.getNetwork()); - } - if (this.request.getCreatedDate() != null) { - phase.withEnv(SOURCE_DATE_EPOCH_KEY, Long.toString(this.request.getCreatedDate().getEpochSecond())); + phase.withImageName(this.request.getName()); + configureOptions(phase); + configureCreatedDate(phase); + return phase; + + } + + private Phase analyzePhase() { + Phase phase = new Phase("analyzer", isVerboseLogging()); + configureDaemonAccess(phase); + phase.withLaunchCache(Directory.LAUNCH_CACHE, + Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); + phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); + phase.withRunImage(this.request.getRunImage()); + phase.withImageName(this.request.getName()); + configureOptions(phase); + return phase; + } + + private Phase detectPhase() { + Phase phase = new Phase("detector", isVerboseLogging()); + phase.withApp(this.applicationDirectory, + Binding.from(getCacheBindingSource(this.application), this.applicationDirectory)); + phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); + phase.withPlatform(Directory.PLATFORM); + configureOptions(phase); + return phase; + } + + private Phase restorePhase() { + Phase phase = new Phase("restorer", isVerboseLogging()); + configureDaemonAccess(phase); + phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); + configureOptions(phase); + return phase; + } + + private Phase buildPhase() { + Phase phase = new Phase("builder", isVerboseLogging()); + phase.withApp(this.applicationDirectory, + Binding.from(getCacheBindingSource(this.application), this.applicationDirectory)); + phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); + phase.withPlatform(Directory.PLATFORM); + configureOptions(phase); + return phase; + } + + private Phase exportPhase() { + Phase phase = new Phase("exporter", isVerboseLogging()); + configureDaemonAccess(phase); + phase.withApp(this.applicationDirectory, + Binding.from(getCacheBindingSource(this.application), this.applicationDirectory)); + phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + phase.withLaunchCache(Directory.LAUNCH_CACHE, + Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); + phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); + if (requiresProcessTypeDefault()) { + phase.withProcessType("web"); } + phase.withImageName(this.request.getName()); + configureOptions(phase); + configureCreatedDate(phase); return phase; } @@ -238,6 +299,7 @@ class Lifecycle implements Closeable { } private void configureDaemonAccess(Phase phase) { + phase.withDaemonAccess(); if (this.dockerHost != null) { if (this.dockerHost.isRemote()) { phase.withEnv("DOCKER_HOST", this.dockerHost.getAddress()); @@ -258,6 +320,22 @@ class Lifecycle implements Closeable { } } + private void configureCreatedDate(Phase phase) { + if (this.request.getCreatedDate() != null) { + phase.withEnv(SOURCE_DATE_EPOCH_KEY, Long.toString(this.request.getCreatedDate().getEpochSecond())); + } + } + + private void configureOptions(Phase phase) { + if (this.request.getBindings() != null) { + this.request.getBindings().forEach(phase::withBinding); + } + if (this.request.getNetwork() != null) { + phase.withNetworkMode(this.request.getNetwork()); + } + phase.withEnv(PLATFORM_API_VERSION_KEY, this.platformVersion.toString()); + } + private boolean isVerboseLogging() { return this.request.isVerboseLogging() && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION); } @@ -269,7 +347,7 @@ class Lifecycle implements Closeable { private void run(Phase phase) throws IOException { Consumer logConsumer = this.log.runningPhase(this.request, phase.getName()); ContainerConfig containerConfig = ContainerConfig.of(this.builder.getName(), phase::apply); - ContainerReference reference = createContainer(containerConfig); + ContainerReference reference = createContainer(containerConfig, phase.requiresApp()); try { this.docker.container().start(reference); this.docker.container().logs(reference, logConsumer::accept); @@ -283,8 +361,8 @@ class Lifecycle implements Closeable { } } - private ContainerReference createContainer(ContainerConfig config) throws IOException { - if (this.applicationVolumePopulated) { + private ContainerReference createContainer(ContainerConfig config, boolean requiresAppUpload) throws IOException { + if (!requiresAppUpload || this.applicationVolumePopulated) { return this.docker.container().create(config); } try { @@ -339,8 +417,7 @@ class Lifecycle implements Closeable { *

* Maps to the {@code } concept in the * buildpack - * specification and the {@code -layers} argument from the reference lifecycle - * implementation. + * specification and the {@code -layers} argument to lifecycle phases. */ static final String LAYERS = "/layers"; @@ -367,8 +444,7 @@ class Lifecycle implements Closeable { *

* Maps to the {@code /env} and {@code /#} concepts in the * buildpack - * specification and the {@code -platform} argument from the reference - * lifecycle implementation. + * specification and the {@code -platform} argument to lifecycle phases. */ static final String PLATFORM = "/platform"; @@ -377,8 +453,7 @@ class Lifecycle implements Closeable { * image {@link BuildRequest#getName() name} being built, and is persistent across * invocations even if the application content has changed. *

- * Maps to the {@code -path} argument from the reference lifecycle implementation - * cache and restore phases + * Maps to the {@code -path} argument to lifecycle phases. */ static final String CACHE = "/cache"; @@ -387,8 +462,7 @@ class Lifecycle implements Closeable { * based on the image {@link BuildRequest#getName() name} being built, and is * persistent across invocations even if the application content has changed. *

- * Maps to the {@code -launch-cache} argument from the reference lifecycle - * implementation export phase + * Maps to the {@code -launch-cache} argument to lifecycle phases. */ static final String LAUNCH_CACHE = "/launch-cache"; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java index 80bacfad48..439511409d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -24,6 +24,7 @@ import java.util.Map; import org.springframework.boot.buildpack.platform.docker.type.Binding; import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig; +import org.springframework.boot.buildpack.platform.docker.type.ImageReference; import org.springframework.util.StringUtils; /** @@ -37,8 +38,6 @@ class Phase { private final String name; - private final boolean verboseLogging; - private boolean daemonAccess = false; private final List args = new ArrayList<>(); @@ -51,6 +50,8 @@ class Phase { private String networkMode; + private boolean requiresApp = false; + /** * Create a new {@link Phase} instance. * @param name the name of the phase @@ -58,22 +59,65 @@ class Phase { */ Phase(String name, boolean verboseLogging) { this.name = name; - this.verboseLogging = verboseLogging; + withLogLevelArg(verboseLogging); + } + + void withApp(String path, Binding binding) { + withArgs("-app", path); + withBinding(binding); + this.requiresApp = true; + } + + void withBuildCache(String path, Binding binding) { + withArgs("-cache-dir", path); + withBinding(binding); } /** * Update this phase with Docker daemon access. */ void withDaemonAccess() { + this.withArgs("-daemon"); this.daemonAccess = true; } + void withImageName(ImageReference imageName) { + withArgs(imageName); + } + + void withLaunchCache(String path, Binding binding) { + withArgs("-launch-cache", path); + withBinding(binding); + } + + void withLayers(String path, Binding binding) { + withArgs("-layers", path); + withBinding(binding); + } + + void withPlatform(String path) { + withArgs("-platform", path); + } + + void withProcessType(String type) { + withArgs("-process-type", type); + } + + void withRunImage(ImageReference runImage) { + withArgs("-run-image", runImage); + } + + void withSkipRestore() { + withArgs("-skip-restore"); + } + /** * Update this phase with a debug log level arguments if verbose logging has been * requested. + * @param verboseLogging if verbose logging is requested */ - void withLogLevelArg() { - if (this.verboseLogging) { + private void withLogLevelArg(boolean verboseLogging) { + if (verboseLogging) { this.args.add("-log-level"); this.args.add("debug"); } @@ -128,6 +172,10 @@ class Phase { return this.name; } + boolean requiresApp() { + return this.requiresApp; + } + @Override public String toString() { return this.name; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java index 6e6fce7f50..d0eae13b3d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -27,14 +27,18 @@ import java.time.ZoneId; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.boot.buildpack.platform.docker.type.Binding; +import org.springframework.boot.buildpack.platform.docker.type.ImageName; import org.springframework.boot.buildpack.platform.docker.type.ImageReference; import org.springframework.boot.buildpack.platform.io.Owner; import org.springframework.boot.buildpack.platform.io.TarArchive; @@ -64,7 +68,7 @@ class BuildRequestTests { writeTestJarFile(jarFile); BuildRequest request = BuildRequest.forJarFile(jarFile); assertThat(request.getName()).hasToString("docker.io/library/my-app:0.0.1"); - assertThat(request.getBuilder()).hasToString("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME); + assertThat(request.getBuilder()).hasToString("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_REF); assertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent); assertThat(request.getEnv()).isEmpty(); } @@ -75,7 +79,7 @@ class BuildRequestTests { writeTestJarFile(jarFile); BuildRequest request = BuildRequest.forJarFile(ImageReference.of("test-app"), jarFile); assertThat(request.getName()).hasToString("docker.io/library/test-app:latest"); - assertThat(request.getBuilder()).hasToString("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME); + assertThat(request.getBuilder()).hasToString("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_REF); assertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent); assertThat(request.getEnv()).isEmpty(); } @@ -104,6 +108,7 @@ class BuildRequestTests { BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")) .withBuilder(ImageReference.of("spring/builder")); assertThat(request.getBuilder()).hasToString("docker.io/spring/builder:latest"); + assertThat(request.isTrustBuilder()).isFalse(); } @Test @@ -113,6 +118,53 @@ class BuildRequestTests { .of("spring/builder@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d")); assertThat(request.getBuilder()).hasToString( "docker.io/spring/builder@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + assertThat(request.isTrustBuilder()).isFalse(); + } + + @Test + void withoutBuilderTrustsDefaultBuilder() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")); + assertThat(request.isTrustBuilder()).isTrue(); + } + + @Test + void withoutBuilderTrustsDefaultBuilderWithDifferentTag() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")) + .withBuilder(ImageReference.of(ImageName.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME), "other")); + assertThat(request.isTrustBuilder()).isTrue(); + } + + @Test + void withoutBuilderTrustsDefaultBuilderWithDigest() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")) + .withBuilder(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF) + .withDigest("sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d")); + assertThat(request.isTrustBuilder()).isTrue(); + } + + @ParameterizedTest + @MethodSource("trustedBuilders") + void withKnownTrustedBuilderTrustsBuilder(ImageReference builder) throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")).withBuilder(builder); + assertThat(request.isTrustBuilder()).isTrue(); + } + + static Stream trustedBuilders() { + return BuildRequest.KNOWN_TRUSTED_BUILDERS.stream(); + } + + @Test + void withoutTrustBuilderAndDefaultBuilderUpdatesTrustsBuilder() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")).withTrustBuilder(false); + assertThat(request.isTrustBuilder()).isFalse(); + } + + @Test + void withTrustBuilderAndBuilderUpdatesTrustBuilder() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")) + .withBuilder(ImageReference.of("spring/builder")) + .withTrustBuilder(true); + assertThat(request.isTrustBuilder()).isTrue(); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java index 357c0a50f6..b6e9553dfd 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java @@ -86,7 +86,7 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); @@ -97,7 +97,7 @@ class BuilderTests { assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); ArgumentCaptor archive = ArgumentCaptor.forClass(ImageArchive.class); then(docker.image()).should() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull()); + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull()); then(docker.image()).should() .pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull()); then(docker.image()).should().load(archive.capture(), any()); @@ -115,7 +115,7 @@ class BuilderTests { .withBuilderRegistryTokenAuthentication("builder token") .withPublishRegistryTokenAuthentication("publish token"); given(docker.image() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader()))) .willAnswer(withPulledImage(builderImage)); given(docker.image() @@ -129,7 +129,7 @@ class BuilderTests { assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); ArgumentCaptor archive = ArgumentCaptor.forClass(ImageArchive.class); then(docker.image()).should() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader())); then(docker.image()).should() .pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), @@ -168,7 +168,7 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image-with-run-image-digest.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image() .pull(eq(ImageReference @@ -211,7 +211,7 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("example.com/custom/run:latest")), any(), isNull())) .willAnswer(withPulledImage(runImage)); @@ -231,11 +231,11 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); - given(docker.image().inspect(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)))) + given(docker.image().inspect(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)))) .willReturn(builderImage); given(docker.image().inspect(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")))) .willReturn(runImage); @@ -257,11 +257,11 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); - given(docker.image().inspect(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)))) + given(docker.image().inspect(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)))) .willReturn(builderImage); given(docker.image().inspect(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")))) .willReturn(runImage); @@ -283,11 +283,11 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); - given(docker.image().inspect(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)))) + given(docker.image().inspect(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)))) .willThrow( new DockerEngineException("docker://localhost/", new URI("example"), 404, "NOT FOUND", null, null)) .willReturn(builderImage); @@ -313,7 +313,7 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); @@ -339,7 +339,7 @@ class BuilderTests { .withBuilderRegistryTokenAuthentication("builder token") .withPublishRegistryTokenAuthentication("publish token"); given(docker.image() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader()))) .willAnswer(withPulledImage(builderImage)); given(docker.image() @@ -354,7 +354,7 @@ class BuilderTests { assertThat(out.toString()).contains("Successfully created image tag 'docker.io/library/my-application:1.2.3'"); then(docker.image()).should() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader())); then(docker.image()).should() .pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), @@ -378,7 +378,7 @@ class BuilderTests { DockerApi docker = mockDockerApi(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image-with-bad-stack.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); @@ -395,7 +395,7 @@ class BuilderTests { DockerApi docker = mockDockerApiLifecycleError(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); @@ -413,7 +413,7 @@ class BuilderTests { DockerConfiguration dockerConfiguration = new DockerConfiguration() .withBuilderRegistryTokenAuthentication("builder token"); given(docker.image() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader()))) .willAnswer(withPulledImage(builderImage)); Builder builder = new Builder(BuildLog.to(out), docker, dockerConfiguration); @@ -431,7 +431,7 @@ class BuilderTests { DockerConfiguration dockerConfiguration = new DockerConfiguration() .withBuilderRegistryTokenAuthentication("builder token"); given(docker.image() - .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), + .pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), eq(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader()))) .willAnswer(withPulledImage(builderImage)); Builder builder = new Builder(BuildLog.to(out), docker, dockerConfiguration); @@ -447,7 +447,7 @@ class BuilderTests { DockerApi docker = mockDockerApiLifecycleError(); Image builderImage = loadImage("image.json"); Image runImage = loadImage("run-image.json"); - given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any(), isNull())) + given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)), any(), isNull())) .willAnswer(withPulledImage(builderImage)); given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull())) .willAnswer(withPulledImage(runImage)); @@ -490,7 +490,7 @@ class BuilderTests { private BuildRequest getTestRequest() { TarArchive content = mock(TarArchive.class); ImageReference name = ImageReference.of("my-application"); - return BuildRequest.of(name, (owner) -> content); + return BuildRequest.of(name, (owner) -> content).withTrustBuilder(true); } private Image loadImage(String name) throws IOException { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java index 6f898d1a98..83eabfdf98 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -34,6 +34,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; import org.mockito.stubbing.Answer; import org.skyscreamer.jsonassert.JSONAssert; @@ -53,6 +54,7 @@ import org.springframework.boot.buildpack.platform.docker.type.VolumeName; import org.springframework.boot.buildpack.platform.io.IOConsumer; import org.springframework.boot.buildpack.platform.io.TarArchive; import org.springframework.boot.buildpack.platform.json.SharedObjectMapper; +import org.springframework.boot.testsupport.junit.BooleanValueSource; import org.springframework.util.FileCopyUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -87,13 +89,23 @@ class LifecycleTests { this.docker = mockDockerApi(); } - @Test - void executeExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeExecutesPhases(boolean trustBuilder) 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)); - createLifecycle().execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator.json")); + createLifecycle(trustBuilder).execute(); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } @@ -102,7 +114,7 @@ class LifecycleTests { 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().withBindings(Binding.of("/host/src/path:/container/dest/path:ro"), + BuildRequest request = getTestRequest(true).withBindings(Binding.of("/host/src/path:/container/dest/path:ro"), Binding.of("volume-name:/container/volume/path:rw")); createLifecycle(request).execute(); assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-bindings.json")); @@ -114,48 +126,62 @@ class LifecycleTests { 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)); - createLifecycle("builder-metadata-platform-api-0.3.json").execute(); + createLifecycle(true, "builder-metadata-platform-api-0.3.json").execute(); assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-platform-api-0.3.json")); assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeOnlyUploadsContentOnce() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeOnlyUploadsContentOnce(boolean trustBuilder) 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)); - createLifecycle().execute(); + createLifecycle(trustBuilder).execute(); assertThat(this.content).hasSize(1); } - @Test - void executeWhenAlreadyRunThrowsException() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWhenAlreadyRunThrowsException(boolean trustBuilder) 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)); - Lifecycle lifecycle = createLifecycle(); + Lifecycle lifecycle = createLifecycle(trustBuilder); lifecycle.execute(); assertThatIllegalStateException().isThrownBy(lifecycle::execute) .withMessage("Lifecycle has already been executed"); } - @Test - void executeWhenBuilderReturnsErrorThrowsException() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWhenBuilderReturnsErrorThrowsException(boolean trustBuilder) 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(9, null)); - assertThatExceptionOfType(BuilderException.class).isThrownBy(() -> createLifecycle().execute()) - .withMessage("Builder lifecycle 'creator' failed with status code 9"); + assertThatExceptionOfType(BuilderException.class).isThrownBy(() -> createLifecycle(trustBuilder).execute()) + .withMessage( + "Builder lifecycle '" + ((trustBuilder) ? "creator" : "analyzer") + "' failed with status code 9"); } - @Test - void executeWhenCleanCacheClearsCache() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWhenCleanCacheClearsCache(boolean trustBuilder) 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().withCleanCache(true); + BuildRequest request = getTestRequest(trustBuilder).withCleanCache(true); createLifecycle(request).execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-clean-cache.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-clean-cache.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json")); + assertThat(this.out.toString()).contains("Skipping restorer because 'cleanCache' is enabled"); + } VolumeName name = VolumeName.of("pack-cache-b35197ac41ea.build"); then(this.docker.volume()).should().delete(name, true); } @@ -166,7 +192,7 @@ class LifecycleTests { given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); assertThatIllegalStateException() - .isThrownBy(() -> createLifecycle("builder-metadata-unsupported-api.json").execute()) + .isThrownBy(() -> createLifecycle(true, "builder-metadata-unsupported-api.json").execute()) .withMessageContaining("Detected platform API versions '0.2' are not included in supported versions"); } @@ -176,22 +202,32 @@ class LifecycleTests { given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); assertThatIllegalStateException() - .isThrownBy(() -> createLifecycle("builder-metadata-unsupported-apis.json").execute()) + .isThrownBy(() -> createLifecycle(true, "builder-metadata-unsupported-apis.json").execute()) .withMessageContaining("Detected platform API versions '0.1,0.2' are not included in supported versions"); } - @Test - void executeWhenMultiplePlatformApisSupportedExecutesPhase() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWhenMultiplePlatformApisSupportedExecutesPhase(boolean trustBuilder) 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)); - createLifecycle("builder-metadata-supported-apis.json").execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator.json")); + createLifecycle(trustBuilder, "builder-metadata-supported-apis.json").execute(); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json")); + } } @Test void closeClearsVolumes() throws Exception { - createLifecycle().close(); + createLifecycle(true).close(); then(this.docker.volume()).should().delete(VolumeName.of("pack-layers-aaaaaaaaaa"), true); then(this.docker.volume()).should().delete(VolumeName.of("pack-app-aaaaaaaaaa"), true); } @@ -201,92 +237,163 @@ class LifecycleTests { 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().withNetwork("test"); + BuildRequest request = getTestRequest(true).withNetwork("test"); createLifecycle(request).execute(); assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-network.json")); assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithCacheVolumeNamesExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithCacheVolumeNamesExecutesPhases(boolean trustBuilder) 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().withBuildWorkspace(Cache.volume("work-volume")) + BuildRequest request = getTestRequest(trustBuilder).withBuildWorkspace(Cache.volume("work-volume")) .withBuildCache(Cache.volume("build-volume")) .withLaunchCache(Cache.volume("launch-volume")); createLifecycle(request).execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-cache-volumes.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-cache-volumes.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-cache-volumes.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector-cache-volumes.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-cache-volumes.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder-cache-volumes.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-cache-volumes.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithCacheBindMountsExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithCacheBindMountsExecutesPhases(boolean trustBuilder) 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().withBuildWorkspace(Cache.bind("/tmp/work")) + BuildRequest request = getTestRequest(trustBuilder).withBuildWorkspace(Cache.bind("/tmp/work")) .withBuildCache(Cache.bind("/tmp/build-cache")) .withLaunchCache(Cache.bind("/tmp/launch-cache")); createLifecycle(request).execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-cache-bind-mounts.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-cache-bind-mounts.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-cache-bind-mounts.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector-cache-bind-mounts.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-cache-bind-mounts.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder-cache-bind-mounts.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-cache-bind-mounts.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithCreatedDateExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithCreatedDateExecutesPhases(boolean trustBuilder) 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().withCreatedDate("2020-07-01T12:34:56Z"); + BuildRequest request = getTestRequest(trustBuilder).withCreatedDate("2020-07-01T12:34:56Z"); createLifecycle(request).execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-created-date.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-created-date.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-created-date.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithApplicationDirectoryExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithApplicationDirectoryExecutesPhases(boolean trustBuilder) 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().withApplicationDirectory("/application"); + BuildRequest request = getTestRequest(trustBuilder).withApplicationDirectory("/application"); createLifecycle(request).execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-app-dir.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-app-dir.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector-app-dir.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder-app-dir.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-app-dir.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithSecurityOptionsExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithSecurityOptionsExecutesPhases(boolean trustBuilder) 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")); + BuildRequest request = getTestRequest(trustBuilder) + .withSecurityOptions(List.of("label=user:USER", "label=role:ROLE")); createLifecycle(request).execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-security-opts.json", true)); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-security-opts.json", true)); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-security-opts.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-security-opts.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-security-opts.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithDockerHostAndRemoteAddressExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithDockerHostAndRemoteAddressExecutesPhases(boolean trustBuilder) 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(); + BuildRequest request = getTestRequest(trustBuilder); createLifecycle(request, ResolvedDockerHost.from(DockerHostConfiguration.forAddress("tcp://192.168.1.2:2376"))) .execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-inherit-remote.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-inherit-remote.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-inherit-remote.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-inherit-remote.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-inherit-remote.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } - @Test - void executeWithDockerHostAndLocalAddressExecutesPhases() throws Exception { + @ParameterizedTest + @BooleanValueSource + void executeWithDockerHostAndLocalAddressExecutesPhases(boolean trustBuilder) 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(); + BuildRequest request = getTestRequest(trustBuilder); createLifecycle(request, ResolvedDockerHost.from(DockerHostConfiguration.forAddress("/var/alt.sock"))) .execute(); - assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-inherit-local.json")); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-inherit-local.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-inherit-local.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-inherit-local.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-inherit-local.json")); + } assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } @@ -301,14 +408,16 @@ class LifecycleTests { return docker; } - private BuildRequest getTestRequest() { + private BuildRequest getTestRequest(boolean trustBuilder) { TarArchive content = mock(TarArchive.class); ImageReference name = ImageReference.of("my-application"); - return BuildRequest.of(name, (owner) -> content).withRunImage(ImageReference.of("cloudfoundry/run")); + return BuildRequest.of(name, (owner) -> content) + .withRunImage(ImageReference.of("cloudfoundry/run")) + .withTrustBuilder(trustBuilder); } - private Lifecycle createLifecycle() throws IOException { - return createLifecycle(getTestRequest()); + private Lifecycle createLifecycle(boolean trustBuilder) throws IOException { + return createLifecycle(getTestRequest(trustBuilder)); } private Lifecycle createLifecycle(BuildRequest request) throws IOException { @@ -316,9 +425,9 @@ class LifecycleTests { return createLifecycle(request, builder); } - private Lifecycle createLifecycle(String builderMetadata) throws IOException { + private Lifecycle createLifecycle(boolean trustBuilder, String builderMetadata) throws IOException { EphemeralBuilder builder = mockEphemeralBuilder(builderMetadata); - return createLifecycle(getTestRequest(), builder); + return createLifecycle(getTestRequest(trustBuilder), builder); } private Lifecycle createLifecycle(BuildRequest request, ResolvedDockerHost dockerHost) throws IOException { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java index 7d5cd88cb0..cb7d69285e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -66,7 +66,7 @@ class PhaseTests { Update update = mock(Update.class); phase.apply(update); then(update).should().withUser("root"); - then(update).should().withCommand("/cnb/lifecycle/test", NO_ARGS); + then(update).should().withCommand("/cnb/lifecycle/test", "-daemon"); then(update).should().withLabel("author", "spring-boot"); then(update).shouldHaveNoMoreInteractions(); } @@ -74,7 +74,6 @@ class PhaseTests { @Test void applyWhenWithLogLevelArgAndVerboseLoggingUpdatesConfigurationWithLogLevel() { Phase phase = new Phase("test", true); - phase.withLogLevelArg(); Update update = mock(Update.class); phase.apply(update); then(update).should().withCommand("/cnb/lifecycle/test", "-log-level", "debug"); @@ -85,7 +84,6 @@ class PhaseTests { @Test void applyWhenWithLogLevelArgAndNonVerboseLoggingDoesNotUpdateLogLevel() { Phase phase = new Phase("test", false); - phase.withLogLevelArg(); Update update = mock(Update.class); phase.apply(update); then(update).should().withCommand("/cnb/lifecycle/test"); @@ -133,7 +131,7 @@ class PhaseTests { @Test void applyWhenWithNetworkModeUpdatesConfigurationWithNetworkMode() { - Phase phase = new Phase("test", true); + Phase phase = new Phase("test", false); phase.withNetworkMode("test"); Update update = mock(Update.class); phase.apply(update); @@ -145,7 +143,7 @@ class PhaseTests { @Test void applyWhenWithSecurityOptionsUpdatesConfigurationWithSecurityOptions() { - Phase phase = new Phase("test", true); + Phase phase = new Phase("test", false); phase.withSecurityOption("option1=value1"); phase.withSecurityOption("option2=value2"); Update update = mock(Update.class); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-bind-mounts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-bind-mounts.json new file mode 100644 index 0000000000..2656dde2f0 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-bind-mounts.json @@ -0,0 +1,31 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "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", + "/tmp/launch-cache:/launch-cache", + "/tmp/work-layers:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-volumes.json new file mode 100644 index 0000000000..285d666b0d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-volumes.json @@ -0,0 +1,31 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "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", + "launch-volume:/launch-cache", + "work-volume-layers:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-local.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-local.json new file mode 100644 index 0000000000..915034d958 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-local.json @@ -0,0 +1,31 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "docker.io/library/my-application:latest" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/alt.sock:/var/run/docker.sock", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-remote.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-remote.json new file mode 100644 index 0000000000..a2fffb5f6b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-remote.json @@ -0,0 +1,31 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "docker.io/library/my-application:latest" + ], + "Env": [ + "DOCKER_HOST=tcp://192.168.1.2:2376", + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-security-opts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-security-opts.json new file mode 100644 index 0000000000..96049f5c6f --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-security-opts.json @@ -0,0 +1,32 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "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-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=user:USER", + "label=role:ROLE" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json new file mode 100644 index 0000000000..bb678a0f9b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json @@ -0,0 +1,31 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "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-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-app-dir.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-app-dir.json new file mode 100644 index 0000000000..f3554898cb --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-app-dir.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/builder", + "-app", + "/application", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-app-aaaaaaaaaa:/application", + "pack-layers-aaaaaaaaaa:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-bind-mounts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-bind-mounts.json new file mode 100644 index 0000000000..2cd60a23bd --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-bind-mounts.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/builder", + "-app", + "/workspace", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/tmp/work-app:/workspace", + "/tmp/work-layers:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-volumes.json new file mode 100644 index 0000000000..82870ca9de --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-volumes.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/builder", + "-app", + "/workspace", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "work-volume-app:/workspace", + "work-volume-layers:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder.json new file mode 100644 index 0000000000..98fd56c216 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/builder", + "-app", + "/workspace", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-app-dir.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-app-dir.json index 6acd7a12ea..8daba81021 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-app-dir.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-app-dir.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/application", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json index 85ac90ce4d..c5fa498748 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock", "/host/src/path:/container/dest/path:ro", "volume-name:/container/volume/path:rw" ], diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-bind-mounts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-bind-mounts.json index 7259fc11af..7c7c285d58 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-bind-mounts.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-bind-mounts.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "/tmp/work-layers:/layers", "/tmp/work-app:/workspace", + "/tmp/work-layers:/layers", "/tmp/build-cache:/cache", - "/tmp/launch-cache:/launch-cache" + "/tmp/launch-cache:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json index 0f611d5d05..4cd1fe314f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "work-volume-layers:/layers", "work-volume-app:/workspace", + "work-volume-layers:/layers", "build-volume:/cache", - "launch-volume:/launch-cache" + "launch-volume:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json index 1239aaa2f2..0b2472c5ad 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json @@ -27,11 +27,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-created-date.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-created-date.json index a316d9633a..1b2907a93a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-created-date.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-created-date.json @@ -27,11 +27,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json index 15ea893ce9..e0f7fa8cb9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/alt.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/alt.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json index 55a7958b8b..af703b95a2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json @@ -27,8 +27,8 @@ }, "HostConfig": { "Binds": [ - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ], diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json index 32169341c2..7eef5bf795 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json @@ -27,11 +27,11 @@ "HostConfig": { "NetworkMode": "test", "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json index 38e6df2075..96cd67316c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json @@ -7,7 +7,13 @@ "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" ], + "Binds" : [ + "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" + ], "SecurityOpt" : [ "label=disable" ] diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-security-opts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-security-opts.json index c47bd7f9ff..4f1a1e75fb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-security-opts.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-security-opts.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=user:USER", diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json index 5c85d04b8f..7cda92d899 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json @@ -26,11 +26,11 @@ }, "HostConfig": { "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", "pack-cache-b35197ac41ea.build:/cache", - "pack-cache-b35197ac41ea.launch:/launch-cache" + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" ], "SecurityOpt" : [ "label=disable" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-app-dir.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-app-dir.json new file mode 100644 index 0000000000..7eb3173afb --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-app-dir.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/detector", + "-app", + "/application", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-app-aaaaaaaaaa:/application", + "pack-layers-aaaaaaaaaa:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-bind-mounts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-bind-mounts.json new file mode 100644 index 0000000000..706239cb5d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-bind-mounts.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/detector", + "-app", + "/workspace", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/tmp/work-app:/workspace", + "/tmp/work-layers:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-volumes.json new file mode 100644 index 0000000000..729600142f --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-volumes.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/detector", + "-app", + "/workspace", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "work-volume-app:/workspace", + "work-volume-layers:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector.json new file mode 100644 index 0000000000..d5a9eb922e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector.json @@ -0,0 +1,24 @@ +{ + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/detector", + "-app", + "/workspace", + "-layers", + "/layers", + "-platform", + "/platform" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-app-dir.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-app-dir.json new file mode 100644 index 0000000000..91b436b568 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-app-dir.json @@ -0,0 +1,35 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/application", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "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-app-aaaaaaaaaa:/application", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-bind-mounts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-bind-mounts.json new file mode 100644 index 0000000000..c27c53ebd9 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-bind-mounts.json @@ -0,0 +1,35 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "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", + "/tmp/work-app:/workspace", + "/tmp/build-cache:/cache", + "/tmp/launch-cache:/launch-cache", + "/tmp/work-layers:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-volumes.json new file mode 100644 index 0000000000..413a988923 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-volumes.json @@ -0,0 +1,35 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "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", + "work-volume-app:/workspace", + "build-volume:/cache", + "launch-volume:/launch-cache", + "work-volume-layers:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-created-date.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-created-date.json new file mode 100644 index 0000000000..1de4797405 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-created-date.json @@ -0,0 +1,36 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "docker.io/library/my-application:latest" + ], + "Env": [ + "CNB_PLATFORM_API=0.8", + "SOURCE_DATE_EPOCH=1593606896" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "pack-app-aaaaaaaaaa:/workspace", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-local.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-local.json new file mode 100644 index 0000000000..b70d66133d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-local.json @@ -0,0 +1,35 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "docker.io/library/my-application:latest" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/alt.sock:/var/run/docker.sock", + "pack-app-aaaaaaaaaa:/workspace", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-remote.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-remote.json new file mode 100644 index 0000000000..28f3083b17 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-remote.json @@ -0,0 +1,35 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "docker.io/library/my-application:latest" + ], + "Env": [ + "DOCKER_HOST=tcp://192.168.1.2:2376", + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-app-aaaaaaaaaa:/workspace", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-security-opts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-security-opts.json new file mode 100644 index 0000000000..ee7f41d87e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-security-opts.json @@ -0,0 +1,36 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "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-app-aaaaaaaaaa:/workspace", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=user:USER", + "label=role:ROLE" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json new file mode 100644 index 0000000000..56893e385e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json @@ -0,0 +1,35 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-dir", + "/cache", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "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-app-aaaaaaaaaa:/workspace", + "pack-cache-b35197ac41ea.build:/cache", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-bind-mounts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-bind-mounts.json new file mode 100644 index 0000000000..78f51a68aa --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-bind-mounts.json @@ -0,0 +1,28 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-dir", + "/cache", + "-layers", + "/layers" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "/tmp/build-cache:/cache", + "/tmp/work-layers:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-volumes.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-volumes.json new file mode 100644 index 0000000000..9408724c8f --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-volumes.json @@ -0,0 +1,28 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-dir", + "/cache", + "-layers", + "/layers" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "build-volume:/cache", + "work-volume-layers:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-local.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-local.json new file mode 100644 index 0000000000..a5a54b5a4d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-local.json @@ -0,0 +1,28 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-dir", + "/cache", + "-layers", + "/layers" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/alt.sock:/var/run/docker.sock", + "pack-cache-b35197ac41ea.build:/cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-remote.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-remote.json new file mode 100644 index 0000000000..b8af6eea09 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-remote.json @@ -0,0 +1,28 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-dir", + "/cache", + "-layers", + "/layers" + ], + "Env": [ + "DOCKER_HOST=tcp://192.168.1.2:2376", + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-cache-b35197ac41ea.build:/cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-security-opts.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-security-opts.json new file mode 100644 index 0000000000..b43f8428b0 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-security-opts.json @@ -0,0 +1,29 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-dir", + "/cache", + "-layers", + "/layers" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "pack-cache-b35197ac41ea.build:/cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=user:USER", + "label=role:ROLE" + ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json new file mode 100644 index 0000000000..ccbc314463 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json @@ -0,0 +1,28 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-dir", + "/cache", + "-layers", + "/layers" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "pack-cache-b35197ac41ea.build:/cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} \ No newline at end of file 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 48536e5367..f34eff25a4 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 @@ -78,6 +78,23 @@ class BootBuildImageIntegrationTests { 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("Running detector"); + assertThat(result.getOutput()).contains("Running builder"); + assertThat(result.getOutput()).contains("---> Test Info buildpack building"); + assertThat(result.getOutput()).contains("Network status: HTTP/2 200"); + assertThat(result.getOutput()).contains("---> Test Info buildpack done"); + removeImages(projectName); + } + + @TestTemplate + void buildsImageWithTrustBuilder() 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("Running creator"); assertThat(result.getOutput()).contains("---> Test Info buildpack building"); assertThat(result.getOutput()).contains("Network status: HTTP/2 200"); assertThat(result.getOutput()).contains("---> Test Info buildpack done"); @@ -146,10 +163,11 @@ class BootBuildImageIntegrationTests { writeLongNameResource(); BuildResult result = this.gradleBuild.build("bootBuildImage", "--pullPolicy=IF_NOT_PRESENT", "--imageName=example/test-image-cmd", "--builder=ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1", - "--runImage=paketobuildpacks/run-jammy-tiny", "--createdDate=2020-07-01T12:34:56Z", + "--trustBuilder", "--runImage=paketobuildpacks/run-jammy-tiny", "--createdDate=2020-07-01T12:34:56Z", "--applicationDirectory=/application"); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); assertThat(result.getOutput()).contains("example/test-image-cmd"); + assertThat(result.getOutput()).contains("Running creator"); assertThat(result.getOutput()).contains("---> Test Info buildpack building"); assertThat(result.getOutput()).contains("---> Test Info buildpack done"); Image image = new DockerApi().image().inspect(ImageReference.of("example/test-image-cmd")); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithTrustBuilder.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithTrustBuilder.gradle new file mode 100644 index 0000000000..27136227b0 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithTrustBuilder.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '{version}' +} + +if (project.hasProperty('applyWarPlugin')) { + apply plugin: 'war' +} + +bootBuildImage { + builder = "ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1" + trustBuilder = true + pullPolicy = "IF_NOT_PRESENT" +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc index 928a1126c3..0738112f8b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc @@ -118,9 +118,14 @@ The following table summarizes the available properties and their default values | `builder` | `--builder` -| Name of the Builder image to use. +| Name of the builder image to use. | `paketobuildpacks/builder-jammy-tiny:latest` +| `trustBuilder` +| `--trustBuilder` +| Whether to treat the builder as https://buildpacks.io/docs/for-platform-operators/how-to/integrate-ci/pack/concepts/trusted_builders/#what-is-a-trusted-builder[trusted]. +| `true` if the builder is one of `paketobuildpacks/builder-jammy-tiny`, `paketobuildpacks/builder-jammy-base`, `paketobuildpacks/builder-jammy-full`, `paketobuildpacks/builder-jammy-buildpackless-tiny`, `paketobuildpacks/builder-jammy-buildpackless-base`, `paketobuildpacks/builder-jammy-buildpackless-full`, `gcr.io/buildpacks/builder`, `heroku/builder`; false otherwise. + | `runImage` | `--runImage` | Name of the run image to use. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java index f0a2751b88..ce11a93a4a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java @@ -91,6 +91,7 @@ public abstract class BootBuildImage extends DefaultTask { } return ImageReference.of(imageName, projectVersion.get()).toString(); })); + getTrustBuilder().convention((Boolean) null); getCleanCache().convention(false); getVerboseLogging().convention(false); getPublish().convention(false); @@ -131,6 +132,16 @@ public abstract class BootBuildImage extends DefaultTask { @Option(option = "builder", description = "The name of the builder image to use") public abstract Property getBuilder(); + /** + * Whether to treat the builder as trusted. + * @return whether to trust the builder + * @since 3.4.0 + */ + @Input + @Optional + @Option(option = "trustBuilder", description = "Consider the builder trusted") + public abstract Property getTrustBuilder(); + /** * Returns the run image that will be included in the built image. When {@code null}, * the run image bundled with the builder will be used. @@ -348,13 +359,16 @@ public abstract class BootBuildImage extends DefaultTask { private BuildRequest customize(BuildRequest request) { request = customizeBuilder(request); + if (getTrustBuilder().isPresent()) { + request = request.withTrustBuilder(getTrustBuilder().get()); + } request = customizeRunImage(request); request = customizeEnvironment(request); request = customizeCreator(request); request = request.withCleanCache(getCleanCache().get()); request = request.withVerboseLogging(getVerboseLogging().get()); request = customizePullPolicy(request); - request = customizePublish(request); + request = request.withPublish(getPublish().get()); request = customizeBuildpacks(request); request = customizeBindings(request); request = customizeTags(request); @@ -406,11 +420,6 @@ public abstract class BootBuildImage extends DefaultTask { return request; } - private BuildRequest customizePublish(BuildRequest request) { - request = request.withPublish(getPublish().get()); - return request; - } - private BuildRequest customizeBuildpacks(BuildRequest request) { List buildpacks = getBuildpacks().getOrNull(); if (!CollectionUtils.isEmpty(buildpacks)) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java index 101fb09c92..348af9d7a2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java @@ -172,14 +172,24 @@ class BootBuildImageTests { @Test void whenNoBuilderIsConfiguredThenRequestHasDefaultBuilder() { - assertThat(this.buildImage.createRequest().getBuilder().getName()) - .isEqualTo("paketobuildpacks/builder-jammy-tiny"); + BuildRequest request = this.buildImage.createRequest(); + assertThat(request.getBuilder().getName()).isEqualTo("paketobuildpacks/builder-jammy-tiny"); + assertThat(request.isTrustBuilder()).isTrue(); } @Test void whenBuilderIsConfiguredThenRequestUsesSpecifiedBuilder() { this.buildImage.getBuilder().set("example.com/test/builder:1.2"); - assertThat(this.buildImage.createRequest().getBuilder().getName()).isEqualTo("test/builder"); + BuildRequest request = this.buildImage.createRequest(); + assertThat(request.getBuilder().getName()).isEqualTo("test/builder"); + assertThat(request.isTrustBuilder()).isFalse(); + } + + @Test + void whenTrustBuilderIsEnabledThenRequestHasTrustBuilderEnabled() { + this.buildImage.getBuilder().set("example.com/test/builder:1.2"); + this.buildImage.getTrustBuilder().set(true); + assertThat(this.buildImage.createRequest().isTrustBuilder()).isTrue(); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/java/org/springframework/boot/maven/BuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/java/org/springframework/boot/maven/BuildImageTests.java index ea58f5598d..a618bf525d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/java/org/springframework/boot/maven/BuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/java/org/springframework/boot/maven/BuildImageTests.java @@ -68,6 +68,8 @@ class BuildImageTests extends AbstractArchiveIntegrationTests { assertThat(original).doesNotExist(); assertThat(buildLog(project)).contains("Building image") .contains("docker.io/library/build-image:0.0.1.BUILD-SNAPSHOT") + .contains("Running detector") + .contains("Running builder") .contains("---> Test Info buildpack building") .contains("---> Test Info buildpack done") .contains("Successfully built image"); @@ -88,6 +90,8 @@ class BuildImageTests extends AbstractArchiveIntegrationTests { assertThat(original).doesNotExist(); assertThat(buildLog(project)).contains("Building image") .contains("docker.io/library/build-image-cmd-line:0.0.1.BUILD-SNAPSHOT") + .contains("Running detector") + .contains("Running builder") .contains("---> Test Info buildpack building") .contains("---> Test Info buildpack done") .contains("Successfully built image"); @@ -248,12 +252,14 @@ class BuildImageTests extends AbstractArchiveIntegrationTests { .systemProperty("spring-boot.build-image.pullPolicy", "IF_NOT_PRESENT") .systemProperty("spring-boot.build-image.imageName", "example.com/test/cmd-property-name:v1") .systemProperty("spring-boot.build-image.builder", "ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1") + .systemProperty("spring-boot.build-image.trustBuilder", "true") .systemProperty("spring-boot.build-image.runImage", "paketobuildpacks/run-jammy-tiny") .systemProperty("spring-boot.build-image.createdDate", "2020-07-01T12:34:56Z") .systemProperty("spring-boot.build-image.applicationDirectory", "/application") .execute((project) -> { assertThat(buildLog(project)).contains("Building image") .contains("example.com/test/cmd-property-name:v1") + .contains("Running creator") .contains("---> Test Info buildpack building") .contains("---> Test Info buildpack done") .contains("Successfully built image"); @@ -279,6 +285,22 @@ class BuildImageTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void whenBuildImageIsInvokedWithTrustBuilder(MavenBuild mavenBuild) { + mavenBuild.project("dockerTest", "build-image-trust-builder") + .goals("package") + .systemProperty("spring-boot.build-image.pullPolicy", "IF_NOT_PRESENT") + .execute((project) -> { + assertThat(buildLog(project)).contains("Building image") + .contains("docker.io/library/build-image-v2-trust-builder:0.0.1.BUILD-SNAPSHOT") + .contains("Running creator") + .contains("---> Test Info buildpack building") + .contains("---> Test Info buildpack done") + .contains("Successfully built image"); + removeImage("docker.io/library/build-image-v2-trust-builder", "0.0.1.BUILD-SNAPSHOT"); + }); + } + @TestTemplate void whenBuildImageIsInvokedWithEmptyEnvEntry(MavenBuild mavenBuild) { mavenBuild.project("dockerTest", "build-image-empty-env-entry") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/pom.xml new file mode 100644 index 0000000000..dd847d1a34 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-v2-trust-builder + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build-image-no-fork + + + + ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1 + true + + + + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..922c0107e8 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2024 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 + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc index 6ea66cb111..c0772e5465 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc @@ -134,9 +134,14 @@ The following table summarizes the available parameters and their default values | `builder` + (`spring-boot.build-image.builder`) -| Name of the Builder image to use. +| Name of the builder image to use. | `paketobuildpacks/builder-jammy-tiny:latest` +| `trustBuilder` + +(`spring-boot.build-image.trustBuilder`) +| Whether to treat the builder as https://buildpacks.io/docs/for-platform-operators/how-to/integrate-ci/pack/concepts/trusted_builders/#what-is-a-trusted-builder[trusted]. +| `true` if the builder is one of `paketobuildpacks/builder-jammy-tiny`, `paketobuildpacks/builder-jammy-base`, `paketobuildpacks/builder-jammy-full`, `paketobuildpacks/builder-jammy-buildpackless-tiny`, `paketobuildpacks/builder-jammy-buildpackless-base`, `paketobuildpacks/builder-jammy-buildpackless-full`, `gcr.io/buildpacks/builder`, `heroku/builder`; false otherwise. + | `runImage` + (`spring-boot.build-image.runImage`) | Name of the run image to use. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java index 79b62bf530..01f2102b50 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -118,6 +118,13 @@ public abstract class BuildImageMojo extends AbstractPackagerMojo { @Parameter(property = "spring-boot.build-image.builder", readonly = true) String imageBuilder; + /** + * Alias for {@link Image#trustBuilder} to support configuration through command-line + * property. + */ + @Parameter(property = "spring-boot.build-image.trustBuilder", readonly = true) + Boolean trustBuilder; + /** * Alias for {@link Image#runImage} to support configuration through command-line * property. @@ -267,6 +274,9 @@ public abstract class BuildImageMojo extends AbstractPackagerMojo { if (image.builder == null && this.imageBuilder != null) { image.setBuilder(this.imageBuilder); } + if (image.trustBuilder == null && this.trustBuilder != null) { + image.setTrustBuilder(this.trustBuilder); + } if (image.runImage == null && this.runImage != null) { image.setRunImage(this.runImage); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java index c19ac62465..0256127d75 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -49,6 +49,8 @@ public class Image { String builder; + Boolean trustBuilder; + String runImage; Map env; @@ -105,6 +107,18 @@ public class Image { this.builder = builder; } + /** + * If the builder should be treated as trusted. + * @return {@code true} if the builder should be treated as trusted + */ + public Boolean getTrustBuilder() { + return this.trustBuilder; + } + + void setTrustBuilder(Boolean trustBuilder) { + this.trustBuilder = trustBuilder; + } + /** * The name of the run image to use to create the image. * @return the builder image name @@ -221,6 +235,9 @@ public class Image { if (StringUtils.hasText(this.builder)) { request = request.withBuilder(ImageReference.of(this.builder)); } + if (this.trustBuilder != null) { + request = request.withTrustBuilder(this.trustBuilder); + } if (StringUtils.hasText(this.runImage)) { request = request.withRunImage(ImageReference.of(this.runImage)); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java index 5dde373d74..5cdd1cf4b1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java @@ -70,11 +70,13 @@ class ImageTests { BuildRequest request = new Image().getBuildRequest(createArtifact(), mockApplicationContent()); assertThat(request.getName()).hasToString("docker.io/library/my-app:0.0.1-SNAPSHOT"); assertThat(request.getBuilder().toString()).contains("paketobuildpacks/builder-jammy-tiny"); + assertThat(request.isTrustBuilder()).isTrue(); assertThat(request.getRunImage()).isNull(); assertThat(request.getEnv()).isEmpty(); assertThat(request.isCleanCache()).isFalse(); assertThat(request.isVerboseLogging()).isFalse(); assertThat(request.getPullPolicy()).isEqualTo(PullPolicy.ALWAYS); + assertThat(request.isPublish()).isFalse(); assertThat(request.getBuildpacks()).isEmpty(); assertThat(request.getBindings()).isEmpty(); assertThat(request.getNetwork()).isNull(); @@ -86,6 +88,26 @@ class ImageTests { image.builder = "springboot/builder:2.2.x"; BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent()); assertThat(request.getBuilder()).hasToString("docker.io/springboot/builder:2.2.x"); + assertThat(request.isTrustBuilder()).isFalse(); + } + + @Test + void getBuildRequestWhenHasBuilderAndTrustBuilderUsesBuilderAndTrustBuilder() { + Image image = new Image(); + image.builder = "springboot/builder:2.2.x"; + image.trustBuilder = true; + BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent()); + assertThat(request.getBuilder()).hasToString("docker.io/springboot/builder:2.2.x"); + assertThat(request.isTrustBuilder()).isTrue(); + } + + @Test + void getBuildRequestWhenHasDefaultBuilderAndTrustBuilderUsesTrustBuilder() { + Image image = new Image(); + image.trustBuilder = false; + BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent()); + assertThat(request.getBuilder().toString()).contains("paketobuildpacks/builder-jammy-tiny"); + assertThat(request.isTrustBuilder()).isFalse(); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanArgumentsProvider.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanArgumentsProvider.java new file mode 100644 index 0000000000..8be839ec39 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanArgumentsProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2024 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.springframework.boot.testsupport.junit; + +import java.lang.reflect.Method; +import java.util.stream.Stream; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.platform.commons.util.Preconditions; + +/** + * An {@link ArgumentsProvider} that provides {@code true} and {@code false} values. + * + * @author Scott Frederick + */ +class BooleanArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext context) { + Method testMethod = context.getRequiredTestMethod(); + Preconditions.condition(testMethod.getParameterCount() > 0, () -> String.format( + "@BooleanValueSource cannot provide arguments to method [%s]: the method does not declare any formal parameters.", + testMethod.toGenericString())); + + return Stream.of(Arguments.arguments(false), Arguments.arguments(true)); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanValueSource.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanValueSource.java new file mode 100644 index 0000000000..1b34d78044 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanValueSource.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2024 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.springframework.boot.testsupport.junit; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.params.provider.ArgumentsSource; + +/** + * {@code @BooleanValueSource} is an {@link ArgumentsSource} which provides {@code true} + * and {@code false} values to the annotated {@code @ParameterizedTest} method. + * + * @author Scott Frederick + */ +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@ArgumentsSource(BooleanArgumentsProvider.class) +public @interface BooleanValueSource { + +} diff --git a/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java b/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java index 7dae13f8a7..23da800e0c 100644 --- a/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java +++ b/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java @@ -48,7 +48,6 @@ import org.springframework.boot.image.junit.GradleBuildInjectionExtension; import org.springframework.boot.testsupport.gradle.testkit.GradleBuild; import org.springframework.boot.testsupport.gradle.testkit.GradleBuildExtension; import org.springframework.boot.testsupport.gradle.testkit.GradleVersions; -import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; @@ -85,6 +84,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -116,6 +116,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withCommand("--server.port=9090"); container.withExposedPorts(9090); @@ -133,6 +134,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -159,6 +161,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName, "assemble", "bootDistZip"); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -195,6 +198,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName, "assemble", "bootDistZip"); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -232,6 +236,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -264,6 +269,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -310,6 +316,7 @@ class PaketoBuilderTests { ImageReference imageReference = ImageReference.of(ImageName.of(imageName)); BuildResult result = buildImage(imageName); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("Running creator"); try (GenericContainer container = new GenericContainer<>(imageName)) { container.withExposedPorts(8080); container.waitingFor(Wait.forHttp("/test")).start(); @@ -333,9 +340,11 @@ class PaketoBuilderTests { } private BuildResult buildImage(String imageName, String... arguments) { - String[] buildImageArgs = { "bootBuildImage", "--imageName=" + imageName, "--pullPolicy=IF_NOT_PRESENT" }; - String[] args = StringUtils.concatenateStringArrays(arguments, buildImageArgs); - return this.gradleBuild.build(args); + List args = new ArrayList<>(List.of(arguments)); + args.add("bootBuildImage"); + args.add("--imageName=" + imageName); + args.add("--pullPolicy=IF_NOT_PRESENT"); + return this.gradleBuild.build(args.toArray(new String[0])); } private void writeMainClass() throws IOException {