diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java index a33c89eb43..8c73e4b7eb 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/JGitAPIImpl.java @@ -42,6 +42,9 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Arrays; @@ -203,10 +206,22 @@ public class JGitAPIImpl extends LegacyCompatibleGitAPIImpl { public SshdSessionFactory buildSshdSessionFactory(@NonNull final HostKeyVerifierFactory hostKeyVerifierFactory) { if (Files.notExists(hostKeyVerifierFactory.getKnownHostsFile().toPath())) { try { - Files.createDirectories(hostKeyVerifierFactory - .getKnownHostsFile() - .getParentFile() - .toPath()); + if (isWindows()) { + Files.createDirectories(hostKeyVerifierFactory + .getKnownHostsFile() + .getParentFile() + .toPath()); + } else { + Set ownerOnly = PosixFilePermissions.fromString("rwx------"); + FileAttribute> fileAttribute = + PosixFilePermissions.asFileAttribute(ownerOnly); + Files.createDirectories( + hostKeyVerifierFactory + .getKnownHostsFile() + .getParentFile() + .toPath(), + fileAttribute); + } Files.createFile(hostKeyVerifierFactory.getKnownHostsFile().toPath()); } catch (IOException e) { LOGGER.log(Level.SEVERE, "could not create known hosts file", e); @@ -3262,4 +3277,9 @@ public void close() { } } } + + /** inline ${@link hudson.Functions#isWindows()} to prevent a transient remote classloader issue */ + private static boolean isWindows() { + return File.pathSeparatorChar == ';'; + } } diff --git a/src/main/java/org/jenkinsci/plugins/gitclient/verifier/KnownHostsFileVerifier.java b/src/main/java/org/jenkinsci/plugins/gitclient/verifier/KnownHostsFileVerifier.java index aaa5b17fe5..11cdb8762e 100644 --- a/src/main/java/org/jenkinsci/plugins/gitclient/verifier/KnownHostsFileVerifier.java +++ b/src/main/java/org/jenkinsci/plugins/gitclient/verifier/KnownHostsFileVerifier.java @@ -6,6 +6,10 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.jgit.transport.sshd.ServerKeyDatabase; @@ -29,19 +33,28 @@ public AbstractCliGitHostKeyVerifier forCliGit(TaskListener listener) { }; } + private void createKnownHostsFile(Path knowHostPath) throws IOException { + Path parent = knowHostPath.getParent(); + if (parent == null) { + throw new IllegalArgumentException("knowHostPath parent cannot be null"); + } + if (isWindows()) { + Files.createDirectories(parent); + } else { + Set ownerOnly = PosixFilePermissions.fromString("rwx------"); + FileAttribute> fileAttribute = PosixFilePermissions.asFileAttribute(ownerOnly); + Files.createDirectories(parent, fileAttribute); + } + Files.createFile(knowHostPath); + } + @Override public AbstractJGitHostKeyVerifier forJGit(TaskListener listener) { Path knowHostPath = getKnownHostsFile().toPath(); if (Files.notExists(knowHostPath)) { try { logHint(listener); - Path parent = knowHostPath.getParent(); - if (parent != null) { - Files.createDirectories(parent); - Files.createFile(knowHostPath); - } else { - throw new IllegalArgumentException("knowHostPath parent cannot be null"); - } + createKnownHostsFile(knowHostPath); } catch (IOException e) { LOGGER.log(Level.WARNING, e, () -> "Could not load known hosts."); } @@ -79,4 +92,9 @@ private void logHint(TaskListener listener) { "Known hosts file {0} not found, but verifying host keys with known hosts file", new Object[] {SshHostKeyVerificationStrategy.KNOWN_HOSTS_DEFAULT}); } + + /** inline ${@link hudson.Functions#isWindows()} to prevent a transient remote classloader issue */ + private static boolean isWindows() { + return File.pathSeparatorChar == ';'; + } }