From 2174cfa6e4c15d52046b7e380acb13482daccd16 Mon Sep 17 00:00:00 2001 From: Akash Manna Date: Thu, 18 Dec 2025 01:22:40 +0530 Subject: [PATCH 1/2] [JENKINS-71461] GIT_SSH_COMMAND diagnostics fail with some host key verification strategies --- .../plugins/gitclient/CliGitAPIImpl.java | 27 ++- .../GitHostKeyVerificationConfiguration.java | 25 +++ .../config.jelly | 4 + .../gitclient/CliGitAPISecurityTest.java | 176 ++++++++++++++++++ 4 files changed, 230 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 8fe922e6c8..6cf49ff3b6 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -2700,9 +2700,11 @@ Path createWindowsGitSSH(Path key, String user, Path knownHosts) throws IOExcept w.newLine(); w.write("setlocal enabledelayedexpansion"); w.newLine(); + String verboseFlag = isSshVerboseEnabled() ? " -vvv" : ""; w.write("\"" + sshexe.getAbsolutePath() + "\" -i \"!JENKINS_GIT_SSH_KEYFILE!\" -l \"!JENKINS_GIT_SSH_USERNAME!\" " - + getHostKeyFactory().forCliGit(listener).getVerifyHostKeyOption(knownHosts) + " %* "); + + getHostKeyFactory().forCliGit(listener).getVerifyHostKeyOption(knownHosts) + verboseFlag + + " %* "); w.newLine(); } ssh.toFile().setExecutable(true, true); @@ -2724,8 +2726,10 @@ Path createUnixGitSSH(Path key, String user, Path knownHosts) throws IOException w.newLine(); w.write("fi"); w.newLine(); + String verboseFlag = isSshVerboseEnabled() ? " -vvv" : ""; w.write("ssh -i \"$JENKINS_GIT_SSH_KEYFILE\" -l \"$JENKINS_GIT_SSH_USERNAME\" " - + getHostKeyFactory().forCliGit(listener).getVerifyHostKeyOption(knownHosts) + " \"$@\""); + + getHostKeyFactory().forCliGit(listener).getVerifyHostKeyOption(knownHosts) + verboseFlag + + " \"$@\""); w.newLine(); } return createNonBusyExecutable(ssh); @@ -2768,6 +2772,25 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir) throws Gi return launchCommandIn(args, workDir, environment); } + /** + * Safely check if SSH verbose mode is enabled. + * Returns false if Jenkins instance is not available (e.g., during tests). + * + * @return true if SSH verbose mode is enabled, false otherwise + */ + private boolean isSshVerboseEnabled() { + try { + jenkins.model.Jenkins instance = jenkins.model.Jenkins.getInstanceOrNull(); + if (instance != null) { + return GitHostKeyVerificationConfiguration.get().isSshVerbose(); + } + } catch (Exception e) { + // If we can't get the configuration, default to false + LOGGER.log(Level.FINE, "Unable to get SSH verbose configuration", e); + } + return false; + } + private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars env) throws GitException, InterruptedException { return launchCommandIn(args, workDir, environment, TIMEOUT); diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration.java b/src/main/java/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration.java index a3831d55a5..c22d4b481c 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration.java @@ -16,6 +16,8 @@ public class GitHostKeyVerificationConfiguration extends GlobalConfiguration imp private SshHostKeyVerificationStrategy sshHostKeyVerificationStrategy; + private boolean sshVerbose = false; + @Override public @NonNull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); @@ -35,6 +37,29 @@ public void setSshHostKeyVerificationStrategy( save(); } + /** + * Check if SSH verbose mode is enabled. + * When enabled, SSH commands will include -vvv flag for detailed diagnostic output. + * This helps troubleshoot SSH connection issues without requiring GIT_SSH_COMMAND environment variable. + * + * @return true if SSH verbose mode is enabled, false otherwise + */ + public boolean isSshVerbose() { + return sshVerbose; + } + + /** + * Set SSH verbose mode. + * When enabled, SSH commands will include -vvv flag for detailed diagnostic output. + * This helps troubleshoot SSH connection issues without requiring GIT_SSH_COMMAND environment variable. + * + * @param sshVerbose true to enable SSH verbose mode, false to disable + */ + public void setSshVerbose(boolean sshVerbose) { + this.sshVerbose = sshVerbose; + save(); + } + public static @NonNull GitHostKeyVerificationConfiguration get() { return GlobalConfiguration.all().getInstance(GitHostKeyVerificationConfiguration.class); } diff --git a/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly b/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly index 3461e5681e..8e8e35e599 100644 --- a/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly @@ -2,5 +2,9 @@ + + + \ No newline at end of file diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java index 60ade1b268..2ea1e228a3 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; /** * Security test that proves the environment variable approach prevents @@ -35,6 +36,7 @@ * * @author Mark Waite */ +@WithJenkins class CliGitAPISecurityTest { @TempDir @@ -286,4 +288,178 @@ private void executeWrapper(Path wrapper, Path keyFile) throws Exception { // That's fine - we're just checking for injection } } + + /** + * Test that SSH verbose mode is disabled by default (no -vvv flag) + */ + @Test + @Issue("JENKINS-71461") + void testSshVerboseModeDisabledByDefault() throws Exception { + workspace = new File(tempDir, "test-default"); + workspace.mkdirs(); + + Path keyFile = createMockSSHKey(workspace); + Path knownHosts = Files.createTempFile("known_hosts", ""); + + try { + // When Jenkins is not available, SSH verbose should default to false + GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) + .in(workspace) + .using("git") + .getClient(); + CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + + Path sshWrapper; + if (isWindows()) { + sshWrapper = git.createWindowsGitSSH(keyFile, "testuser", knownHosts); + } else { + sshWrapper = git.createUnixGitSSH(keyFile, "testuser", knownHosts); + } + + String wrapperContent = Files.readString(sshWrapper, StandardCharsets.UTF_8); + + // Verify -vvv flag is NOT present + assertFalse( + wrapperContent.contains("-vvv"), + "Wrapper should NOT contain -vvv flag when verbose mode is disabled"); + + } finally { + Files.deleteIfExists(knownHosts); + } + } + + /** + * Test that SSH verbose mode adds -vvv flag when enabled + */ + @Test + @Issue("JENKINS-71461") + void testSshVerboseModeEnabled() throws Exception { + // Skip if Jenkins instance is not available + if (jenkins.model.Jenkins.getInstanceOrNull() == null) { + return; + } + + workspace = new File(tempDir, "test-verbose"); + workspace.mkdirs(); + + Path keyFile = createMockSSHKey(workspace); + Path knownHosts = Files.createTempFile("known_hosts", ""); + + try { + // Enable SSH verbose mode + GitHostKeyVerificationConfiguration.get().setSshVerbose(true); + + GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) + .in(workspace) + .using("git") + .getClient(); + CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + + Path sshWrapper; + if (isWindows()) { + sshWrapper = git.createWindowsGitSSH(keyFile, "testuser", knownHosts); + } else { + sshWrapper = git.createUnixGitSSH(keyFile, "testuser", knownHosts); + } + + String wrapperContent = Files.readString(sshWrapper, StandardCharsets.UTF_8); + + // Verify -vvv flag IS present + assertTrue( + wrapperContent.contains("-vvv"), "Wrapper should contain -vvv flag when verbose mode is enabled"); + + } finally { + // Reset to default + GitHostKeyVerificationConfiguration.get().setSshVerbose(false); + Files.deleteIfExists(knownHosts); + } + } + + /** + * Test that SSH verbose mode flag is placed correctly in Unix wrapper + */ + @Test + @Issue("JENKINS-71461") + void testUnixSshVerboseFlagPlacement() throws Exception { + // Skip if Jenkins instance is not available or on Windows + if (jenkins.model.Jenkins.getInstanceOrNull() == null || isWindows()) { + return; + } + + workspace = new File(tempDir, "test-unix-verbose"); + workspace.mkdirs(); + + Path keyFile = createMockSSHKey(workspace); + Path knownHosts = Files.createTempFile("known_hosts", ""); + + try { + // Enable SSH verbose mode + GitHostKeyVerificationConfiguration.get().setSshVerbose(true); + + GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) + .in(workspace) + .using("git") + .getClient(); + CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + Path sshWrapper = git.createUnixGitSSH(keyFile, "testuser", knownHosts); + + String wrapperContent = Files.readString(sshWrapper, StandardCharsets.UTF_8); + + // Verify -vvv appears before "$@" (which represents additional args) + int vvvIndex = wrapperContent.indexOf("-vvv"); + int argsIndex = wrapperContent.indexOf("\"$@\""); + assertTrue(vvvIndex > 0, "-vvv flag should be present"); + assertTrue(argsIndex > 0, "\"$@\" should be present"); + assertTrue(vvvIndex < argsIndex, "-vvv flag should appear before \"$@\""); + + } finally { + // Reset to default + GitHostKeyVerificationConfiguration.get().setSshVerbose(false); + Files.deleteIfExists(knownHosts); + } + } + + /** + * Test that SSH verbose mode flag is placed correctly in Windows wrapper + */ + @Test + @Issue("JENKINS-71461") + void testWindowsSshVerboseFlagPlacement() throws Exception { + // Skip if Jenkins instance is not available or on Unix + if (jenkins.model.Jenkins.getInstanceOrNull() == null || !isWindows()) { + return; // Skip on Unix + } + + workspace = new File(tempDir, "test-windows-verbose"); + workspace.mkdirs(); + + Path keyFile = createMockSSHKey(workspace); + Path knownHosts = Files.createTempFile("known_hosts", ""); + + try { + // Enable SSH verbose mode + GitHostKeyVerificationConfiguration.get().setSshVerbose(true); + + GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) + .in(workspace) + .using("git") + .getClient(); + CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + Path sshWrapper = git.createWindowsGitSSH(keyFile, "testuser", knownHosts); + + String wrapperContent = Files.readString(sshWrapper, StandardCharsets.UTF_8); + + // Verify -vvv appears before %* (which represents additional args) + int vvvIndex = wrapperContent.indexOf("-vvv"); + int argsIndex = wrapperContent.indexOf("%*"); + assertTrue(vvvIndex > 0, "-vvv flag should be present"); + assertTrue(argsIndex > 0, "%* should be present"); + assertTrue(vvvIndex < argsIndex, "-vvv flag should appear before %*"); + + } finally { + // Reset to default + GitHostKeyVerificationConfiguration.get().setSshVerbose(false); + Files.deleteIfExists(knownHosts); + } + } } From 9d8b84edd0a53d9710ca0530dba2bc11a1625037 Mon Sep 17 00:00:00 2001 From: Akash Manna Date: Mon, 13 Apr 2026 12:24:03 +0530 Subject: [PATCH 2/2] Add SSH verbose mode for enhanced diagnostics --- .../plugins/gitclient/CliGitAPIImpl.java | 29 ++++++----------- .../org/jenkinsci/plugins/gitclient/Git.java | 18 +++++++++-- .../config.jelly | 3 +- .../help-sshVerbose.html | 4 +++ .../gitclient/CliGitAPISecurityTest.java | 32 ++++--------------- 5 files changed, 35 insertions(+), 51 deletions(-) create mode 100644 src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/help-sshVerbose.html diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java index 6cf49ff3b6..a499aea4c4 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java @@ -205,6 +205,8 @@ public class CliGitAPIImpl extends LegacyCompatibleGitAPIImpl { */ private Map failureClues = new TreeMap<>(); + private boolean sshVerbose; + /* git config --get-regex applies the regex to match keys, and returns all matches (including substring matches). * Thus, a config call: * git config -f .gitmodules --get-regexp "^submodule\.(.+)\.url" @@ -348,7 +350,9 @@ protected CliGitAPIImpl(String gitExe, File workspace, TaskListener listener, En /** {@inheritDoc} */ @Override public GitClient subGit(String subdir) { - return new CliGitAPIImpl(gitExe, new File(workspace, subdir), listener, environment); + CliGitAPIImpl git = new CliGitAPIImpl(gitExe, new File(workspace, subdir), listener, environment); + git.setSshVerbose(sshVerbose); + return git; } /** @@ -2700,7 +2704,7 @@ Path createWindowsGitSSH(Path key, String user, Path knownHosts) throws IOExcept w.newLine(); w.write("setlocal enabledelayedexpansion"); w.newLine(); - String verboseFlag = isSshVerboseEnabled() ? " -vvv" : ""; + String verboseFlag = sshVerbose ? " -vvv" : ""; w.write("\"" + sshexe.getAbsolutePath() + "\" -i \"!JENKINS_GIT_SSH_KEYFILE!\" -l \"!JENKINS_GIT_SSH_USERNAME!\" " + getHostKeyFactory().forCliGit(listener).getVerifyHostKeyOption(knownHosts) + verboseFlag @@ -2726,7 +2730,7 @@ Path createUnixGitSSH(Path key, String user, Path knownHosts) throws IOException w.newLine(); w.write("fi"); w.newLine(); - String verboseFlag = isSshVerboseEnabled() ? " -vvv" : ""; + String verboseFlag = sshVerbose ? " -vvv" : ""; w.write("ssh -i \"$JENKINS_GIT_SSH_KEYFILE\" -l \"$JENKINS_GIT_SSH_USERNAME\" " + getHostKeyFactory().forCliGit(listener).getVerifyHostKeyOption(knownHosts) + verboseFlag + " \"$@\""); @@ -2772,23 +2776,8 @@ private String launchCommandIn(ArgumentListBuilder args, File workDir) throws Gi return launchCommandIn(args, workDir, environment); } - /** - * Safely check if SSH verbose mode is enabled. - * Returns false if Jenkins instance is not available (e.g., during tests). - * - * @return true if SSH verbose mode is enabled, false otherwise - */ - private boolean isSshVerboseEnabled() { - try { - jenkins.model.Jenkins instance = jenkins.model.Jenkins.getInstanceOrNull(); - if (instance != null) { - return GitHostKeyVerificationConfiguration.get().isSshVerbose(); - } - } catch (Exception e) { - // If we can't get the configuration, default to false - LOGGER.log(Level.FINE, "Unable to get SSH verbose configuration", e); - } - return false; + public void setSshVerbose(boolean sshVerbose) { + this.sshVerbose = sshVerbose; } private String launchCommandIn(ArgumentListBuilder args, File workDir, EnvVars env) diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/Git.java b/src/main/java/org/jenkinsci/plugins/gitclient/Git.java index a6f485ba14..5bd0c6baa5 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/Git.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/Git.java @@ -141,7 +141,10 @@ public GitClient getClient() throws IOException, InterruptedException { .getVerifier(); } } - jenkins.MasterToSlaveFileCallable callable = new GitAPIMasterToSlaveFileCallable(hostKeyFactory); + boolean sshVerbose = Jenkins.getInstanceOrNull() != null + && GitHostKeyVerificationConfiguration.get().isSshVerbose(); + jenkins.MasterToSlaveFileCallable callable = + new GitAPIMasterToSlaveFileCallable(hostKeyFactory, sshVerbose); GitClient git = (repository != null ? repository.act(callable) : callable.invoke(null, null)); Jenkins jenkinsInstance = Jenkins.getInstanceOrNull(); if (jenkinsInstance != null && git != null) { @@ -185,8 +188,11 @@ private class GitAPIMasterToSlaveFileCallable extends jenkins.MasterToSlaveFileC private final HostKeyVerifierFactory hostKeyFactory; - public GitAPIMasterToSlaveFileCallable(HostKeyVerifierFactory hostKeyFactory) { + private final boolean sshVerbose; + + public GitAPIMasterToSlaveFileCallable(HostKeyVerifierFactory hostKeyFactory, boolean sshVerbose) { this.hostKeyFactory = hostKeyFactory; + this.sshVerbose = sshVerbose; } @Override @@ -199,7 +205,12 @@ public GitClient invoke(File f, VirtualChannel channel) throws IOException, Inte } if (Main.isUnitTest && System.getProperty(Git.class.getName() + ".mockClient") != null) { - return initMockClient(System.getProperty(Git.class.getName() + ".mockClient"), exe, env, f, listener); + GitClient mockClient = + initMockClient(System.getProperty(Git.class.getName() + ".mockClient"), exe, env, f, listener); + if (mockClient instanceof CliGitAPIImpl cliGitAPIImpl) { + cliGitAPIImpl.setSshVerbose(sshVerbose); + } + return mockClient; } if (exe == null || JGitTool.MAGIC_EXENAME.equalsIgnoreCase(exe)) { @@ -212,6 +223,7 @@ public GitClient invoke(File f, VirtualChannel channel) throws IOException, Inte // Ensure we return a backward compatible GitAPI, even API only claim to provide a GitClient GitAPI gitAPI = new GitAPI(exe, f, listener, env); gitAPI.setHostKeyFactory(hostKeyFactory); + gitAPI.setSshVerbose(sshVerbose); return gitAPI; } } diff --git a/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly b/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly index 8e8e35e599..126b807495 100644 --- a/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/config.jelly @@ -3,8 +3,7 @@ - + \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/help-sshVerbose.html b/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/help-sshVerbose.html new file mode 100644 index 0000000000..11b02beee2 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/gitclient/GitHostKeyVerificationConfiguration/help-sshVerbose.html @@ -0,0 +1,4 @@ +
+ When enabled, SSH commands generated by the Git client will include -vvv for detailed diagnostic output. + This helps troubleshoot SSH connection issues without requiring the GIT_SSH_COMMAND environment variable. +
diff --git a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java index 2ea1e228a3..8449f08d5a 100644 --- a/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java +++ b/src/test/java/org/jenkinsci/plugins/gitclient/CliGitAPISecurityTest.java @@ -302,7 +302,6 @@ void testSshVerboseModeDisabledByDefault() throws Exception { Path knownHosts = Files.createTempFile("known_hosts", ""); try { - // When Jenkins is not available, SSH verbose should default to false GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) .in(workspace) .using("git") @@ -334,11 +333,6 @@ void testSshVerboseModeDisabledByDefault() throws Exception { @Test @Issue("JENKINS-71461") void testSshVerboseModeEnabled() throws Exception { - // Skip if Jenkins instance is not available - if (jenkins.model.Jenkins.getInstanceOrNull() == null) { - return; - } - workspace = new File(tempDir, "test-verbose"); workspace.mkdirs(); @@ -346,14 +340,12 @@ void testSshVerboseModeEnabled() throws Exception { Path knownHosts = Files.createTempFile("known_hosts", ""); try { - // Enable SSH verbose mode - GitHostKeyVerificationConfiguration.get().setSshVerbose(true); - GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) .in(workspace) .using("git") .getClient(); CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + git.setSshVerbose(true); Path sshWrapper; if (isWindows()) { @@ -369,8 +361,6 @@ void testSshVerboseModeEnabled() throws Exception { wrapperContent.contains("-vvv"), "Wrapper should contain -vvv flag when verbose mode is enabled"); } finally { - // Reset to default - GitHostKeyVerificationConfiguration.get().setSshVerbose(false); Files.deleteIfExists(knownHosts); } } @@ -381,8 +371,7 @@ void testSshVerboseModeEnabled() throws Exception { @Test @Issue("JENKINS-71461") void testUnixSshVerboseFlagPlacement() throws Exception { - // Skip if Jenkins instance is not available or on Windows - if (jenkins.model.Jenkins.getInstanceOrNull() == null || isWindows()) { + if (isWindows()) { return; } @@ -393,14 +382,12 @@ void testUnixSshVerboseFlagPlacement() throws Exception { Path knownHosts = Files.createTempFile("known_hosts", ""); try { - // Enable SSH verbose mode - GitHostKeyVerificationConfiguration.get().setSshVerbose(true); - GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) .in(workspace) .using("git") .getClient(); CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + git.setSshVerbose(true); Path sshWrapper = git.createUnixGitSSH(keyFile, "testuser", knownHosts); String wrapperContent = Files.readString(sshWrapper, StandardCharsets.UTF_8); @@ -413,8 +400,6 @@ void testUnixSshVerboseFlagPlacement() throws Exception { assertTrue(vvvIndex < argsIndex, "-vvv flag should appear before \"$@\""); } finally { - // Reset to default - GitHostKeyVerificationConfiguration.get().setSshVerbose(false); Files.deleteIfExists(knownHosts); } } @@ -425,9 +410,8 @@ void testUnixSshVerboseFlagPlacement() throws Exception { @Test @Issue("JENKINS-71461") void testWindowsSshVerboseFlagPlacement() throws Exception { - // Skip if Jenkins instance is not available or on Unix - if (jenkins.model.Jenkins.getInstanceOrNull() == null || !isWindows()) { - return; // Skip on Unix + if (!isWindows()) { + return; } workspace = new File(tempDir, "test-windows-verbose"); @@ -437,14 +421,12 @@ void testWindowsSshVerboseFlagPlacement() throws Exception { Path knownHosts = Files.createTempFile("known_hosts", ""); try { - // Enable SSH verbose mode - GitHostKeyVerificationConfiguration.get().setSshVerbose(true); - GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()) .in(workspace) .using("git") .getClient(); CliGitAPIImpl git = (CliGitAPIImpl) gitClient; + git.setSshVerbose(true); Path sshWrapper = git.createWindowsGitSSH(keyFile, "testuser", knownHosts); String wrapperContent = Files.readString(sshWrapper, StandardCharsets.UTF_8); @@ -457,8 +439,6 @@ void testWindowsSshVerboseFlagPlacement() throws Exception { assertTrue(vvvIndex < argsIndex, "-vvv flag should appear before %*"); } finally { - // Reset to default - GitHostKeyVerificationConfiguration.get().setSshVerbose(false); Files.deleteIfExists(knownHosts); } }