From e978c3f43b4d73cc1a6433965baab9b091ff7596 Mon Sep 17 00:00:00 2001
From: Luca Niccoli <lultimouomo@gmail.com>
Date: Wed, 4 Jan 2023 17:08:43 +0100
Subject: [PATCH] Take global core.sshCommand into consideration

---
 __test__/git-auth-helper.test.ts      | 85 ++++++++++++++++++++++++---
 __test__/git-directory-helper.test.ts |  1 +
 dist/index.js                         | 14 ++++-
 src/git-auth-helper.ts                |  4 +-
 src/git-command-manager.ts            | 10 ++++
 5 files changed, 103 insertions(+), 11 deletions(-)

diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts
index 2acec38..c2db8e6 100644
--- a/__test__/git-auth-helper.test.ts
+++ b/__test__/git-auth-helper.test.ts
@@ -297,6 +297,41 @@ describe('git-auth-helper tests', () => {
     )
   })
 
+  const configureAuth_setsSshCommandWithCustomCommand =
+    'sets SSH command preseving custom command'
+  it(configureAuth_setsSshCommandWithCustomCommand, async () => {
+    // Arrange
+    await setup(configureAuth_setsSshCommandWithCustomCommand)
+    await fs.promises.writeFile(globalGitConfigPath, 'core.sshCommand fakeSsh')
+    expect(await git.configExists('core.sshCommand', true)).toBeTruthy() // sanity check
+    expect(await git.configGet('core.sshCommand', true)).toBe('fakeSsh') // sanity check
+
+    const authHelper = gitAuthHelper.createAuthHelper(git, settings)
+
+    // Act
+    await authHelper.configureAuth()
+    expect(git.configGet).toHaveBeenCalledWith('core.sshCommand', true)
+
+    // Assert git env var
+    const actualKeyPath = await getActualSshKeyPath()
+    const actualKnownHostsPath = await getActualSshKnownHostsPath()
+    const expectedSshCommand = `"fakeSsh" -i "$RUNNER_TEMP/${path.basename(
+      actualKeyPath
+    )}" -o StrictHostKeyChecking=yes -o CheckHostIP=no -o "UserKnownHostsFile=$RUNNER_TEMP/${path.basename(
+      actualKnownHostsPath
+    )}"`
+    expect(git.setEnvironmentVariable).toHaveBeenCalledWith(
+      'GIT_SSH_COMMAND',
+      expectedSshCommand
+    )
+
+    // Asserty git config
+    expect(git.config).toHaveBeenCalledWith(
+      'core.sshCommand',
+      expectedSshCommand
+    )
+  })
+
   const configureAuth_writesExplicitKnownHosts = 'writes explicit known hosts'
   it(configureAuth_writesExplicitKnownHosts, async () => {
     if (!sshPath) {
@@ -739,15 +774,47 @@ async function setup(testName: string): Promise<void> {
     ),
     configExists: jest.fn(
       async (key: string, globalConfig?: boolean): Promise<boolean> => {
-        const configPath = globalConfig
-          ? path.join(git.env['HOME'] || tempHomedir, '.gitconfig')
-          : localGitConfigPath
-        const content = await fs.promises.readFile(configPath)
-        const lines = content
-          .toString()
-          .split('\n')
-          .filter(x => x)
-        return lines.some(x => x.startsWith(key))
+        try {
+          const configPath = globalConfig
+            ? path.join(git.env['HOME'] || tempHomedir, '.gitconfig')
+            : localGitConfigPath
+          const content = await fs.promises.readFile(configPath)
+          const lines = content
+            .toString()
+            .split('\n')
+            .filter(x => x)
+          return lines.some(x => x.startsWith(key))
+        } catch (error) {
+          if ((error as any)?.code === 'ENOENT') {
+            return false
+          }
+          throw error
+        }
+      }
+    ),
+    configGet: jest.fn(
+      async (key: string, globalConfig?: boolean): Promise<string> => {
+        try {
+          const configPath = globalConfig
+            ? path.join(git.env['HOME'] || tempHomedir, '.gitconfig')
+            : localGitConfigPath
+          const content = await fs.promises.readFile(configPath)
+          const lines = content
+            .toString()
+            .split('\n')
+            .filter(x => x)
+            .filter(x => x.startsWith(key))
+          if (lines.length) {
+            return lines[0].split(' ')[1]
+          } else {
+            return ''
+          }
+        } catch (error) {
+          if ((error as any)?.code === 'ENOENT') {
+            return ''
+          }
+          throw error
+        }
       }
     ),
     env: {},
diff --git a/__test__/git-directory-helper.test.ts b/__test__/git-directory-helper.test.ts
index 70849b5..25b1244 100644
--- a/__test__/git-directory-helper.test.ts
+++ b/__test__/git-directory-helper.test.ts
@@ -407,6 +407,7 @@ async function setup(testName: string): Promise<void> {
     checkoutDetach: jest.fn(),
     config: jest.fn(),
     configExists: jest.fn(),
+    configGet: jest.fn(),
     fetch: jest.fn(),
     getDefaultBranch: jest.fn(),
     getWorkingDirectory: jest.fn(() => repositoryPath),
diff --git a/dist/index.js b/dist/index.js
index 0a33ea1..ec21012 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -7253,7 +7253,9 @@ class GitAuthHelper {
             stateHelper.setSshKnownHostsPath(this.sshKnownHostsPath);
             yield fs.promises.writeFile(this.sshKnownHostsPath, knownHosts);
             // Configure GIT_SSH_COMMAND
-            const sshPath = yield io.which('ssh', true);
+            const sshPath = (yield this.git.configExists(SSH_COMMAND_KEY, true))
+                ? yield this.git.configGet(SSH_COMMAND_KEY, true)
+                : yield io.which('ssh', true);
             this.sshCommand = `"${sshPath}" -i "$RUNNER_TEMP/${path.basename(this.sshKeyPath)}"`;
             if (this.settings.sshStrict) {
                 this.sshCommand += ' -o StrictHostKeyChecking=yes -o CheckHostIP=no';
@@ -7533,6 +7535,16 @@ class GitCommandManager {
             return output.exitCode === 0;
         });
     }
+    configGet(configKey, globalConfig) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const output = yield this.execGit([
+                'config',
+                globalConfig ? '--global' : '--local',
+                configKey
+            ]);
+            return output.stdout.trim();
+        });
+    }
     fetch(refSpec, fetchDepth) {
         return __awaiter(this, void 0, void 0, function* () {
             const args = ['-c', 'protocol.version=2', 'fetch'];
diff --git a/src/git-auth-helper.ts b/src/git-auth-helper.ts
index 6e3ad28..484d1ff 100644
--- a/src/git-auth-helper.ts
+++ b/src/git-auth-helper.ts
@@ -253,7 +253,9 @@ class GitAuthHelper {
     await fs.promises.writeFile(this.sshKnownHostsPath, knownHosts)
 
     // Configure GIT_SSH_COMMAND
-    const sshPath = await io.which('ssh', true)
+    const sshPath = (await this.git.configExists(SSH_COMMAND_KEY, true))
+      ? await this.git.configGet(SSH_COMMAND_KEY, true)
+      : await io.which('ssh', true)
     this.sshCommand = `"${sshPath}" -i "$RUNNER_TEMP/${path.basename(
       this.sshKeyPath
     )}"`
diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts
index 01aedfe..59e6298 100644
--- a/src/git-command-manager.ts
+++ b/src/git-command-manager.ts
@@ -26,6 +26,7 @@ export interface IGitCommandManager {
   ): Promise<void>
   configExists(configKey: string, globalConfig?: boolean): Promise<boolean>
   fetch(refSpec: string[], fetchDepth?: number): Promise<void>
+  configGet(configKey: string, globalConfig?: boolean): Promise<string>
   getDefaultBranch(repositoryUrl: string): Promise<string>
   getWorkingDirectory(): string
   init(): Promise<void>
@@ -201,6 +202,15 @@ class GitCommandManager {
     return output.exitCode === 0
   }
 
+  async configGet(configKey: string, globalConfig?: boolean): Promise<string> {
+    const output = await this.execGit([
+      'config',
+      globalConfig ? '--global' : '--local',
+      configKey
+    ])
+    return output.stdout.trim()
+  }
+
   async fetch(refSpec: string[], fetchDepth?: number): Promise<void> {
     const args = ['-c', 'protocol.version=2', 'fetch']
     if (!refSpec.some(x => x === refHelper.tagsRefSpec)) {