From d2b03dcc6b69776ed00d574edd97dd49c2da434b Mon Sep 17 00:00:00 2001 From: Philipp Homann <3265572+PhilippHomann@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:14:30 +0200 Subject: [PATCH] Reuse existing docker config from environment --- .../impl/RegistryKeyMaterialFactory.java | 36 +++++--- .../impl/RegistryKeyMaterialFactoryTest.java | 91 ++++++++++++------- 2 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactory.java b/src/main/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactory.java index e7cff3b..3a94d85 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactory.java +++ b/src/main/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactory.java @@ -75,26 +75,40 @@ public RegistryKeyMaterialFactory(@NonNull String username, @NonNull String pass this.dockerExecutable = dockerExecutable; } + private void generateConfig(String configJson, FilePath destination, Boolean ignoreBlacklist) throws IOException, InterruptedException { + JSONObject json = JSONObject.fromObject(configJson); + if(!ignoreBlacklist) { + for (String property : BLACKLISTED_PROPERTIES) { + Object value = json.remove(property); + if (value != null) { + launcher.getListener().getLogger().println("Removing blacklisted property: " + property); + } + } + } + + destination.write(json.toString(), StandardCharsets.UTF_8.name()); + } + @Override public KeyMaterial2 materialize2() throws IOException, InterruptedException { FilePath dockerConfig = createSecretsDirectory(); - // read the existing docker config file, which might hold some important settings (e.b. proxies) + String envConfig = this.env.get("DOCKER_CONFIG", null); FilePath configJsonPath = FilePath.getHomeDirectory(this.launcher.getChannel()).child(".docker").child(DOCKER_CONFIG_FILENAME); + Boolean isHomeConfig = true; + if (envConfig != null) { + launcher.getListener().getLogger().println("Using the existing docker config file from environment."); + configJsonPath = new FilePath(this.launcher.getChannel(), envConfig).child(DOCKER_CONFIG_FILENAME); + isHomeConfig = false; + } + if (configJsonPath.exists()) { String configJson = configJsonPath.readToString(); if (StringUtils.isNotBlank(configJson)) { - launcher.getListener().getLogger().println("Using the existing docker config file."); - - JSONObject json = JSONObject.fromObject(configJson); - for (String property : BLACKLISTED_PROPERTIES) { - Object value = json.remove(property); - if (value != null) { - launcher.getListener().getLogger().println("Removing blacklisted property: " + property); - } + if (isHomeConfig) { + launcher.getListener().getLogger().println("Using the existing docker config file from home directory."); } - - dockerConfig.child(DOCKER_CONFIG_FILENAME).write(json.toString(), StandardCharsets.UTF_8.name()); + this.generateConfig(configJson, dockerConfig.child(DOCKER_CONFIG_FILENAME), !isHomeConfig); } } diff --git a/src/test/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactoryTest.java b/src/test/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactoryTest.java index 06256a1..06416cf 100644 --- a/src/test/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/docker/commons/impl/RegistryKeyMaterialFactoryTest.java @@ -69,41 +69,41 @@ public class RegistryKeyMaterialFactoryTest { private KeyMaterialFactory factory; - @Before - public void setup() throws Exception { - // fake launcher for the docker login invocation - FakeLauncher faker = new FakeLauncher() { - @Override - public Proc onLaunch(final ProcStarter p) throws IOException { - return new FinishedProc(0); - } - }; - - PretendSlave slave = j.createPretendSlave(faker); - // VirtualChannel channel = slave.getChannel(); - // FreeStyleProject project = j.createFreeStyleProject(); - - TaskListener listener = TaskListener.NULL; - Launcher launcher = slave.createLauncher(listener); - launcher = new Launcher.DecoratedLauncher(launcher) { - @Override - public VirtualChannel getChannel() { - return new LocalChannel(null) { - @Override - public V call(final Callable callable) throws T { - // ugly as hell, but we need a way to mock fetching the home directory - return (V) new FilePath(tempFolder.getRoot()); - } + private KeyMaterialFactory getFactory(EnvVars env) throws Exception { + // fake launcher for the docker login invocation + FakeLauncher faker = new FakeLauncher() { + @Override + public Proc onLaunch(final ProcStarter p) throws IOException { + return new FinishedProc(0); + } }; - } - }; - URL endpoint = new DockerRegistryEndpoint(null, null).getEffectiveUrl(); - EnvVars env = new EnvVars(); - String dockerExecutable = DockerTool.getExecutable(null, null, listener, env); + PretendSlave slave = j.createPretendSlave(faker); + TaskListener listener = TaskListener.NULL; + Launcher launcher = slave.createLauncher(listener); + launcher = new Launcher.DecoratedLauncher(launcher) { + @Override + public VirtualChannel getChannel() { + return new LocalChannel(null) { + @Override + public V call(final Callable callable) throws T { + // ugly as hell, but we need a way to mock fetching the home directory + return (V) new FilePath(tempFolder.getRoot()); + } + }; + } + }; + + URL endpoint = new DockerRegistryEndpoint(null, null).getEffectiveUrl(); + String dockerExecutable = DockerTool.getExecutable(null, null, listener, env); + + return new RegistryKeyMaterialFactory("username", "password", endpoint, launcher, env, listener, + dockerExecutable).contextualize(new KeyMaterialContext(new FilePath(tempFolder.newFolder()))); + } - factory = new RegistryKeyMaterialFactory("username", "password", endpoint, launcher, env, listener, - dockerExecutable).contextualize(new KeyMaterialContext(new FilePath(tempFolder.newFolder()))); + @Before + public void setup() throws Exception { + factory = getFactory(new EnvVars()); } @Test @@ -233,4 +233,31 @@ public void materialize_userConfigFileWithCredStoreAndHttpHeaders_createdWithHea assertEquals("{\"HttpHeaders\":{\"User-Agent\":\"Docker-Client\"}}", FileUtils.readFileToString(jsonFile, Charset.defaultCharset())); } + @Test + public void materialize_envConfigFile() throws Exception { + EnvVars env = new EnvVars(); + env.put("DOCKER_CONFIG", new File(tempFolder.getRoot(), ".custom-docker").getPath()); + factory = getFactory(env); + + // arrange + File cfgFile = new File(new File(tempFolder.getRoot(), ".custom-docker"), "config.json"); + FileUtils.write(cfgFile, "{\"auths\": { \"localhost:5001\": { \"auth\": \"whatever\", \"email\": \"\"} }}", Charset.defaultCharset()); + + // act + KeyMaterial2 material = factory.materialize2(); + + // assert + String dockerCfgFolderPath = material.env().get("DOCKER_CONFIG"); + assertNotNull(dockerCfgFolderPath); + + File dockerCfgFolder = new File(dockerCfgFolderPath); + assertTrue(dockerCfgFolder.exists()); + + String[] files = dockerCfgFolder.list(); + assertThat(files, arrayContaining("config.json")); + + File jsonFile = new File(dockerCfgFolder, "config.json"); + assertEquals("{\"auths\":{\"localhost:5001\":{\"auth\":\"whatever\",\"email\":\"\"}}}", FileUtils.readFileToString(jsonFile, Charset.defaultCharset())); + } + }