From 311be208456f83f66990d6248bff9f0e10602eca Mon Sep 17 00:00:00 2001 From: somiljain2006 Date: Sun, 1 Feb 2026 11:13:31 +0530 Subject: [PATCH 1/3] Fix recursive decodeBase64 resolution for SSH credentials in JCasC --- .../plugins/casc/SSHCredentialsTest.java | 11 ++++++++ .../casc/SSHCredentialsTest_Recursive_Key.yml | 14 ++++++++++ .../plugins/casc/SecretSourceResolver.java | 27 ++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml diff --git a/integrations/src/test/java/io/jenkins/plugins/casc/SSHCredentialsTest.java b/integrations/src/test/java/io/jenkins/plugins/casc/SSHCredentialsTest.java index 7b70897e3d..b4c8686865 100644 --- a/integrations/src/test/java/io/jenkins/plugins/casc/SSHCredentialsTest.java +++ b/integrations/src/test/java/io/jenkins/plugins/casc/SSHCredentialsTest.java @@ -118,4 +118,15 @@ public Optional reveal(String secret) { return Optional.empty(); } } + + @Test + @ConfiguredWithCode("SSHCredentialsTest_Recursive_Key.yml") + @Issue("https://github.com/jenkinsci/configuration-as-code-plugin/issues/2488") + void shouldSupportRecursiveBase64Certificates(JenkinsConfiguredWithCodeRule j) { + BasicSSHUserPrivateKey certKey = getCredentials(BasicSSHUserPrivateKey.class); + assertThat( + "Private key roundtrip failed", + certKey.getPrivateKeys().get(0).trim().replace("\r\n", "\n"), + equalTo(MySSHKeySecretSource.PRIVATE_SSH_KEY)); + } } diff --git a/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml b/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml new file mode 100644 index 0000000000..e778218e04 --- /dev/null +++ b/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml @@ -0,0 +1,14 @@ +jenkins: + systemMessage: Jenkins with SSH Credentials for JCasC test + +credentials: + system: + domainCredentials: + - credentials: + - basicSSHUserPrivateKey: + scope: SYSTEM + id: "userid_recursive" + username: "recursive-user" + privateKeySource: + directEntry: + privateKey: ${decodeBase64:${SSH_AGENT_PRIVATE_KEY_BASE64}} \ No newline at end of file diff --git a/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java b/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java index fe9ead784a..e267323008 100644 --- a/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java +++ b/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java @@ -201,7 +201,32 @@ static class DecodeBase64Lookup implements StringLookup { @Override public String lookup(@NonNull final String key) { - return new String(Base64.getDecoder().decode(key.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); + if (StringUtils.isBlank(key)) { + return ""; + } + + final String value = key.trim(); + + if (value.startsWith("-----BEGIN ")) { + return value; + } + + String compact = value.replaceAll("\\s+", ""); + + try { + return new String(Base64.getDecoder().decode(compact), StandardCharsets.UTF_8); + } catch (IllegalArgumentException e) { + try { + return new String(Base64.getUrlDecoder().decode(compact), StandardCharsets.UTF_8); + } catch (IllegalArgumentException e2) { + LOGGER.log( + Level.WARNING, + "Configuration import: Failed to decode base64 secret. " + + "The value might not be resolved yet or is invalid base64. Defaulting to empty string.", + e2); + return ""; + } + } } } From 15f1c7e96db39e49f4334e2eef46403f610a8b51 Mon Sep 17 00:00:00 2001 From: somiljain2006 Date: Sun, 1 Feb 2026 12:03:09 +0530 Subject: [PATCH 2/3] Fixed newline error --- .../jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml b/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml index e778218e04..f62feff0fe 100644 --- a/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml +++ b/integrations/src/test/resources/io/jenkins/plugins/casc/SSHCredentialsTest_Recursive_Key.yml @@ -11,4 +11,4 @@ credentials: username: "recursive-user" privateKeySource: directEntry: - privateKey: ${decodeBase64:${SSH_AGENT_PRIVATE_KEY_BASE64}} \ No newline at end of file + privateKey: ${decodeBase64:${SSH_AGENT_PRIVATE_KEY_BASE64}} From 2af2f6c764726753f1a9255df5016ec540483854 Mon Sep 17 00:00:00 2001 From: somiljain2006 Date: Mon, 2 Feb 2026 00:25:45 +0530 Subject: [PATCH 3/3] Fixed some sematics issues --- .../jenkins/plugins/casc/SecretSourceResolver.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java b/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java index e267323008..6112e60fbc 100644 --- a/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java +++ b/plugin/src/main/java/io/jenkins/plugins/casc/SecretSourceResolver.java @@ -201,23 +201,18 @@ static class DecodeBase64Lookup implements StringLookup { @Override public String lookup(@NonNull final String key) { - if (StringUtils.isBlank(key)) { - return ""; - } final String value = key.trim(); - if (value.startsWith("-----BEGIN ")) { - return value; + if (value.isEmpty()) { + return ""; } - String compact = value.replaceAll("\\s+", ""); - try { - return new String(Base64.getDecoder().decode(compact), StandardCharsets.UTF_8); + return new String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8); } catch (IllegalArgumentException e) { try { - return new String(Base64.getUrlDecoder().decode(compact), StandardCharsets.UTF_8); + return new String(Base64.getUrlDecoder().decode(value), StandardCharsets.UTF_8); } catch (IllegalArgumentException e2) { LOGGER.log( Level.WARNING,