Merge pull request #45291 from nosan
* pr/45291: Polish Closes gh-45291
This commit is contained in:
commit
05ee9b387d
|
@ -40,7 +40,7 @@ class Credential extends MappedObject {
|
||||||
|
|
||||||
private final String secret;
|
private final String secret;
|
||||||
|
|
||||||
private String serverUrl;
|
private final String serverUrl;
|
||||||
|
|
||||||
Credential(JsonNode node) {
|
Credential(JsonNode node) {
|
||||||
super(node, MethodHandles.lookup());
|
super(node, MethodHandles.lookup());
|
||||||
|
|
|
@ -39,7 +39,7 @@ class CredentialHelper {
|
||||||
|
|
||||||
private static final String USR_LOCAL_BIN = "/usr/local/bin/";
|
private static final String USR_LOCAL_BIN = "/usr/local/bin/";
|
||||||
|
|
||||||
Set<String> CREDENTIAL_NOT_FOUND_MESSAGES = Set.of("credentials not found in native keychain",
|
private static final Set<String> CREDENTIAL_NOT_FOUND_MESSAGES = Set.of("credentials not found in native keychain",
|
||||||
"no credentials server URL", "no credentials username");
|
"no credentials server URL", "no credentials username");
|
||||||
|
|
||||||
private final String executable;
|
private final String executable;
|
||||||
|
@ -73,12 +73,12 @@ class CredentialHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProcessBuilder processBuilder(String string) {
|
private ProcessBuilder processBuilder(String action) {
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder().redirectErrorStream(true);
|
ProcessBuilder processBuilder = new ProcessBuilder().redirectErrorStream(true);
|
||||||
if (Platform.isWindows()) {
|
if (Platform.isWindows()) {
|
||||||
processBuilder.command("cmd", "/c");
|
processBuilder.command("cmd", "/c");
|
||||||
}
|
}
|
||||||
processBuilder.command(this.executable, string);
|
processBuilder.command(this.executable, action);
|
||||||
return processBuilder;
|
return processBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,14 +90,21 @@ class CredentialHelper {
|
||||||
if (!Platform.isMac()) {
|
if (!Platform.isMac()) {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
List<String> command = new ArrayList<>(processBuilder.command());
|
try {
|
||||||
command.set(0, USR_LOCAL_BIN + command.get(0));
|
List<String> command = new ArrayList<>(processBuilder.command());
|
||||||
return processBuilder.command(command).start();
|
command.set(0, USR_LOCAL_BIN + command.get(0));
|
||||||
|
return processBuilder.command(command).start();
|
||||||
|
}
|
||||||
|
catch (Exception suppressed) {
|
||||||
|
// Suppresses the exception and rethrows the original exception
|
||||||
|
ex.addSuppressed(suppressed);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCredentialsNotFoundError(String message) {
|
private static boolean isCredentialsNotFoundError(String message) {
|
||||||
return this.CREDENTIAL_NOT_FOUND_MESSAGES.contains(message.trim());
|
return CREDENTIAL_NOT_FOUND_MESSAGES.contains(message.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.HexFormat;
|
import java.util.HexFormat;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
@ -36,6 +37,7 @@ import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||||
import org.springframework.boot.buildpack.platform.system.Environment;
|
import org.springframework.boot.buildpack.platform.system.Environment;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.util.function.SingletonSupplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Docker configuration stored in metadata files managed by the Docker CLI.
|
* Docker configuration stored in metadata files managed by the Docker CLI.
|
||||||
|
@ -63,7 +65,8 @@ final class DockerConfigurationMetadata {
|
||||||
|
|
||||||
private static final String CONTEXT_FILE_NAME = "meta.json";
|
private static final String CONTEXT_FILE_NAME = "meta.json";
|
||||||
|
|
||||||
private static volatile DockerConfigurationMetadata systemEnvironmentConfigurationMetadata;
|
private static final Supplier<DockerConfigurationMetadata> systemEnvironmentConfigurationMetadata = SingletonSupplier
|
||||||
|
.of(() -> DockerConfigurationMetadata.create(Environment.SYSTEM));
|
||||||
|
|
||||||
private final String configLocation;
|
private final String configLocation;
|
||||||
|
|
||||||
|
@ -90,20 +93,18 @@ final class DockerConfigurationMetadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
static DockerConfigurationMetadata from(Environment environment) {
|
static DockerConfigurationMetadata from(Environment environment) {
|
||||||
DockerConfigurationMetadata dockerConfigurationMetadata = (environment == Environment.SYSTEM)
|
if (environment == Environment.SYSTEM) {
|
||||||
? DockerConfigurationMetadata.systemEnvironmentConfigurationMetadata : null;
|
return systemEnvironmentConfigurationMetadata.get();
|
||||||
if (dockerConfigurationMetadata != null) {
|
|
||||||
return dockerConfigurationMetadata;
|
|
||||||
}
|
}
|
||||||
|
return create(environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DockerConfigurationMetadata create(Environment environment) {
|
||||||
String configLocation = environment.get(DOCKER_CONFIG);
|
String configLocation = environment.get(DOCKER_CONFIG);
|
||||||
configLocation = (configLocation != null) ? configLocation : getUserHomeConfigLocation();
|
configLocation = (configLocation != null) ? configLocation : getUserHomeConfigLocation();
|
||||||
DockerConfig dockerConfig = createDockerConfig(configLocation);
|
DockerConfig dockerConfig = createDockerConfig(configLocation);
|
||||||
DockerContext dockerContext = createDockerContext(configLocation, dockerConfig.getCurrentContext());
|
DockerContext dockerContext = createDockerContext(configLocation, dockerConfig.getCurrentContext());
|
||||||
dockerConfigurationMetadata = new DockerConfigurationMetadata(configLocation, dockerConfig, dockerContext);
|
return new DockerConfigurationMetadata(configLocation, dockerConfig, dockerContext);
|
||||||
if (environment == Environment.SYSTEM) {
|
|
||||||
DockerConfigurationMetadata.systemEnvironmentConfigurationMetadata = dockerConfigurationMetadata;
|
|
||||||
}
|
|
||||||
return dockerConfigurationMetadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getUserHomeConfigLocation() {
|
private static String getUserHomeConfigLocation() {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.buildpack.platform.docker.configuration;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
|
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Docker registry authentication configuration.
|
* Docker registry authentication configuration.
|
||||||
|
@ -83,7 +84,8 @@ public interface DockerRegistryAuthentication {
|
||||||
* Factory method that returns a new {@link DockerRegistryAuthentication} instance
|
* Factory method that returns a new {@link DockerRegistryAuthentication} instance
|
||||||
* that uses the standard docker JSON config (including support for credential
|
* that uses the standard docker JSON config (including support for credential
|
||||||
* helpers) to generate auth headers.
|
* helpers) to generate auth headers.
|
||||||
* @param fallback the fallback authentication to use if no suitable config is found
|
* @param fallback the fallback authentication to use if no suitable config is found,
|
||||||
|
* may be null {@code}
|
||||||
* @return a new {@link DockerRegistryAuthentication} instance
|
* @return a new {@link DockerRegistryAuthentication} instance
|
||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
* @see #configuration(DockerRegistryAuthentication, BiConsumer)
|
* @see #configuration(DockerRegistryAuthentication, BiConsumer)
|
||||||
|
@ -96,15 +98,17 @@ public interface DockerRegistryAuthentication {
|
||||||
* Factory method that returns a new {@link DockerRegistryAuthentication} instance
|
* Factory method that returns a new {@link DockerRegistryAuthentication} instance
|
||||||
* that uses the standard docker JSON config (including support for credential
|
* that uses the standard docker JSON config (including support for credential
|
||||||
* helpers) to generate auth headers.
|
* helpers) to generate auth headers.
|
||||||
* @param fallback the fallback authentication to use if no suitable config is found
|
* @param fallback the fallback authentication to use if no suitable config is found,
|
||||||
|
* may be {@code null}
|
||||||
* @param credentialHelperExceptionHandler callback that should handle credential
|
* @param credentialHelperExceptionHandler callback that should handle credential
|
||||||
* helper exceptions
|
* helper exceptions, never {@code null}
|
||||||
* @return a new {@link DockerRegistryAuthentication} instance
|
* @return a new {@link DockerRegistryAuthentication} instance
|
||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
* @see #configuration(DockerRegistryAuthentication, BiConsumer)
|
* @see #configuration(DockerRegistryAuthentication, BiConsumer)
|
||||||
*/
|
*/
|
||||||
static DockerRegistryAuthentication configuration(DockerRegistryAuthentication fallback,
|
static DockerRegistryAuthentication configuration(DockerRegistryAuthentication fallback,
|
||||||
BiConsumer<String, Exception> credentialHelperExceptionHandler) {
|
BiConsumer<String, Exception> credentialHelperExceptionHandler) {
|
||||||
|
Assert.notNull(credentialHelperExceptionHandler, () -> "'credentialHelperExceptionHandler' must not be null");
|
||||||
return new DockerRegistryConfigAuthentication(fallback, credentialHelperExceptionHandler);
|
return new DockerRegistryConfigAuthentication(fallback, credentialHelperExceptionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,10 +89,17 @@ class CredentialHelperTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getWhenCommandDoesNotExistErrorThrowsException() {
|
void getWhenExecutableDoesNotExistErrorThrowsException() {
|
||||||
String name = "docker-credential-%s".formatted(UUID.randomUUID().toString());
|
String executable = "docker-credential-%s".formatted(UUID.randomUUID().toString());
|
||||||
assertThatIOException().isThrownBy(() -> new CredentialHelper(name).get("invalid.example.com"))
|
assertThatIOException().isThrownBy(() -> new CredentialHelper(executable).get("invalid.example.com"))
|
||||||
.withMessageContaining(name);
|
.withMessageContaining(executable)
|
||||||
|
.satisfies((ex) -> {
|
||||||
|
if (Platform.isMac()) {
|
||||||
|
assertThat(ex.getMessage()).doesNotContain("/usr/local/bin/");
|
||||||
|
assertThat(ex.getSuppressed()).allSatisfy((suppressed) -> assertThat(suppressed)
|
||||||
|
.hasMessageContaining("/usr/local/bin/" + executable));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*
|
*
|
||||||
* @author Dmytro Nosan
|
* @author Dmytro Nosan
|
||||||
*/
|
*/
|
||||||
class CredentialsTests {
|
class CredentialTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithResource(name = "credentials.json", content = """
|
@WithResource(name = "credentials.json", content = """
|
Loading…
Reference in New Issue