mirror of
https://github.com/actions/checkout.git
synced 2026-03-27 15:50:05 +00:00
Merge 8461cead75 into 0c366fd6a8
This commit is contained in:
commit
c400e00279
@ -238,6 +238,85 @@ describe('git-auth-helper tests', () => {
|
|||||||
expect(setSecretSpy).toHaveBeenCalledWith(expectedSecret)
|
expect(setSecretSpy).toHaveBeenCalledWith(expectedSecret)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const configureAuth_resolvesSymlinksInIncludeIfGitdir =
|
||||||
|
'configureAuth resolves symlinks in includeIf gitdir'
|
||||||
|
it(configureAuth_resolvesSymlinksInIncludeIfGitdir, async () => {
|
||||||
|
if (isWindows) {
|
||||||
|
process.stdout.write(
|
||||||
|
`Skipped test "${configureAuth_resolvesSymlinksInIncludeIfGitdir}". Symlink creation requires admin privileges on Windows.\n`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
await setup(configureAuth_resolvesSymlinksInIncludeIfGitdir)
|
||||||
|
|
||||||
|
const symlinkPath = path.join(path.dirname(workspace), 'workspace-symlink')
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ensure no pre-existing symlink or file remains at this path
|
||||||
|
await fs.promises.rm(symlinkPath, {force: true})
|
||||||
|
|
||||||
|
// Create a symlink pointing to the real workspace directory
|
||||||
|
await fs.promises.symlink(workspace, symlinkPath)
|
||||||
|
|
||||||
|
// Make git appear to be operating from the symlink path
|
||||||
|
;(git.getWorkingDirectory as jest.Mock).mockReturnValue(symlinkPath)
|
||||||
|
process.env['GITHUB_WORKSPACE'] = symlinkPath
|
||||||
|
|
||||||
|
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authHelper.configureAuth()
|
||||||
|
|
||||||
|
// Assert the host includeIf uses the real resolved path, not the symlink path
|
||||||
|
const localConfigContent = (
|
||||||
|
await fs.promises.readFile(localGitConfigPath)
|
||||||
|
).toString()
|
||||||
|
const realGitDir = (
|
||||||
|
await fs.promises.realpath(path.join(symlinkPath, '.git'))
|
||||||
|
).replace(/\\/g, '/')
|
||||||
|
const symlinkGitDir = path.join(symlinkPath, '.git').replace(/\\/g, '/')
|
||||||
|
|
||||||
|
expect(realGitDir).not.toBe(symlinkGitDir) // sanity check: paths differ
|
||||||
|
expect(
|
||||||
|
localConfigContent.indexOf(`includeIf.gitdir:${realGitDir}.path`)
|
||||||
|
).toBeGreaterThanOrEqual(0)
|
||||||
|
expect(localConfigContent.indexOf(symlinkGitDir)).toBeLessThan(0)
|
||||||
|
} finally {
|
||||||
|
// Clean up symlink (or any file) at the symlink path
|
||||||
|
await fs.promises.rm(symlinkPath, {force: true})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const configureAuth_fallsBackWhenRealpathSyncFails =
|
||||||
|
'configureAuth falls back to constructed path when realpathSync fails'
|
||||||
|
it(configureAuth_fallsBackWhenRealpathSyncFails, async () => {
|
||||||
|
// Arrange
|
||||||
|
await setup(configureAuth_fallsBackWhenRealpathSyncFails)
|
||||||
|
|
||||||
|
// Use a non-existent path so realpathSync throws ENOENT naturally,
|
||||||
|
// exercising the catch fallback in configureToken()
|
||||||
|
const nonexistentPath = path.join(runnerTemp, 'does-not-exist')
|
||||||
|
;(git.getWorkingDirectory as jest.Mock).mockReturnValue(nonexistentPath)
|
||||||
|
|
||||||
|
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
|
||||||
|
|
||||||
|
// Act - should not throw despite realpathSync failure
|
||||||
|
await authHelper.configureAuth()
|
||||||
|
|
||||||
|
// Assert the fallback constructed path is used in the includeIf entry
|
||||||
|
const localConfigContent = (
|
||||||
|
await fs.promises.readFile(localGitConfigPath)
|
||||||
|
).toString()
|
||||||
|
const fallbackGitDir = path
|
||||||
|
.join(nonexistentPath, '.git')
|
||||||
|
.replace(/\\/g, '/')
|
||||||
|
expect(
|
||||||
|
localConfigContent.indexOf(`includeIf.gitdir:${fallbackGitDir}.path`)
|
||||||
|
).toBeGreaterThanOrEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
const setsSshCommandEnvVarWhenPersistCredentialsFalse =
|
const setsSshCommandEnvVarWhenPersistCredentialsFalse =
|
||||||
'sets SSH command env var when persist-credentials false'
|
'sets SSH command env var when persist-credentials false'
|
||||||
it(setsSshCommandEnvVarWhenPersistCredentialsFalse, async () => {
|
it(setsSshCommandEnvVarWhenPersistCredentialsFalse, async () => {
|
||||||
|
|||||||
16
dist/index.js
vendored
16
dist/index.js
vendored
@ -406,9 +406,19 @@ class GitAuthHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Host git directory
|
// Host git directory - resolve symlinks so includeIf gitdir matching works
|
||||||
let gitDir = path.join(this.git.getWorkingDirectory(), '.git');
|
// on self-hosted runners where _work is a symlink to an external volume.
|
||||||
gitDir = gitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
let gitDir;
|
||||||
|
try {
|
||||||
|
const constructed = path.join(this.git.getWorkingDirectory(), '.git');
|
||||||
|
const resolved = yield fs.promises.realpath(constructed);
|
||||||
|
gitDir = resolved.replace(/\\/g, '/');
|
||||||
|
}
|
||||||
|
catch (_a) {
|
||||||
|
// Fall back to constructed path if realpath fails
|
||||||
|
gitDir = path.join(this.git.getWorkingDirectory(), '.git');
|
||||||
|
gitDir = gitDir.replace(/\\/g, '/');
|
||||||
|
}
|
||||||
// Configure host includeIf
|
// Configure host includeIf
|
||||||
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`;
|
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`;
|
||||||
yield this.git.config(hostIncludeKey, credentialsConfigPath);
|
yield this.git.config(hostIncludeKey, credentialsConfigPath);
|
||||||
|
|||||||
@ -8,9 +8,9 @@ import * as path from 'path'
|
|||||||
import * as regexpHelper from './regexp-helper'
|
import * as regexpHelper from './regexp-helper'
|
||||||
import * as stateHelper from './state-helper'
|
import * as stateHelper from './state-helper'
|
||||||
import * as urlHelper from './url-helper'
|
import * as urlHelper from './url-helper'
|
||||||
import {v4 as uuid} from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import {IGitCommandManager} from './git-command-manager'
|
import { IGitCommandManager } from './git-command-manager'
|
||||||
import {IGitSourceSettings} from './git-source-settings'
|
import { IGitSourceSettings } from './git-source-settings'
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
const SSH_COMMAND_KEY = 'core.sshCommand'
|
const SSH_COMMAND_KEY = 'core.sshCommand'
|
||||||
@ -92,7 +92,7 @@ class GitAuthHelper {
|
|||||||
assert.ok(runnerTemp, 'RUNNER_TEMP is not defined')
|
assert.ok(runnerTemp, 'RUNNER_TEMP is not defined')
|
||||||
const uniqueId = uuid()
|
const uniqueId = uuid()
|
||||||
this.temporaryHomePath = path.join(runnerTemp, uniqueId)
|
this.temporaryHomePath = path.join(runnerTemp, uniqueId)
|
||||||
await fs.promises.mkdir(this.temporaryHomePath, {recursive: true})
|
await fs.promises.mkdir(this.temporaryHomePath, { recursive: true })
|
||||||
|
|
||||||
// Copy the global git config
|
// Copy the global git config
|
||||||
const gitConfigPath = path.join(
|
const gitConfigPath = path.join(
|
||||||
@ -258,11 +258,11 @@ class GitAuthHelper {
|
|||||||
const uniqueId = uuid()
|
const uniqueId = uuid()
|
||||||
this.sshKeyPath = path.join(runnerTemp, uniqueId)
|
this.sshKeyPath = path.join(runnerTemp, uniqueId)
|
||||||
stateHelper.setSshKeyPath(this.sshKeyPath)
|
stateHelper.setSshKeyPath(this.sshKeyPath)
|
||||||
await fs.promises.mkdir(runnerTemp, {recursive: true})
|
await fs.promises.mkdir(runnerTemp, { recursive: true })
|
||||||
await fs.promises.writeFile(
|
await fs.promises.writeFile(
|
||||||
this.sshKeyPath,
|
this.sshKeyPath,
|
||||||
this.settings.sshKey.trim() + '\n',
|
this.settings.sshKey.trim() + '\n',
|
||||||
{mode: 0o600}
|
{ mode: 0o600 }
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remove inherited permissions on Windows
|
// Remove inherited permissions on Windows
|
||||||
@ -366,9 +366,18 @@ class GitAuthHelper {
|
|||||||
true // globalConfig?
|
true // globalConfig?
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Host git directory
|
// Host git directory - resolve symlinks so includeIf gitdir matching works
|
||||||
let gitDir = path.join(this.git.getWorkingDirectory(), '.git')
|
// on self-hosted runners where _work is a symlink to an external volume.
|
||||||
gitDir = gitDir.replace(/\\/g, '/') // Use forward slashes, even on Windows
|
let gitDir: string
|
||||||
|
try {
|
||||||
|
const constructed = path.join(this.git.getWorkingDirectory(), '.git')
|
||||||
|
const resolved = await fs.promises.realpath(constructed)
|
||||||
|
gitDir = resolved.replace(/\\/g, '/')
|
||||||
|
} catch {
|
||||||
|
// Fall back to constructed path if realpath fails
|
||||||
|
gitDir = path.join(this.git.getWorkingDirectory(), '.git')
|
||||||
|
gitDir = gitDir.replace(/\\/g, '/')
|
||||||
|
}
|
||||||
|
|
||||||
// Configure host includeIf
|
// Configure host includeIf
|
||||||
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`
|
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user