mirror of https://github.com/actions/checkout.git
Merge 8461cead75 into 0c366fd6a8
This commit is contained in:
commit
c400e00279
|
|
@ -238,6 +238,85 @@ describe('git-auth-helper tests', () => {
|
|||
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 =
|
||||
'sets SSH command env var when persist-credentials false'
|
||||
it(setsSshCommandEnvVarWhenPersistCredentialsFalse, async () => {
|
||||
|
|
|
|||
|
|
@ -406,9 +406,19 @@ class GitAuthHelper {
|
|||
);
|
||||
}
|
||||
else {
|
||||
// Host git directory
|
||||
let gitDir = path.join(this.git.getWorkingDirectory(), '.git');
|
||||
gitDir = gitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
||||
// Host git directory - resolve symlinks so includeIf gitdir matching works
|
||||
// on self-hosted runners where _work is a symlink to an external volume.
|
||||
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
|
||||
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`;
|
||||
yield this.git.config(hostIncludeKey, credentialsConfigPath);
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import * as path from 'path'
|
|||
import * as regexpHelper from './regexp-helper'
|
||||
import * as stateHelper from './state-helper'
|
||||
import * as urlHelper from './url-helper'
|
||||
import {v4 as uuid} from 'uuid'
|
||||
import {IGitCommandManager} from './git-command-manager'
|
||||
import {IGitSourceSettings} from './git-source-settings'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { IGitCommandManager } from './git-command-manager'
|
||||
import { IGitSourceSettings } from './git-source-settings'
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32'
|
||||
const SSH_COMMAND_KEY = 'core.sshCommand'
|
||||
|
|
@ -92,7 +92,7 @@ class GitAuthHelper {
|
|||
assert.ok(runnerTemp, 'RUNNER_TEMP is not defined')
|
||||
const uniqueId = uuid()
|
||||
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
|
||||
const gitConfigPath = path.join(
|
||||
|
|
@ -258,11 +258,11 @@ class GitAuthHelper {
|
|||
const uniqueId = uuid()
|
||||
this.sshKeyPath = path.join(runnerTemp, uniqueId)
|
||||
stateHelper.setSshKeyPath(this.sshKeyPath)
|
||||
await fs.promises.mkdir(runnerTemp, {recursive: true})
|
||||
await fs.promises.mkdir(runnerTemp, { recursive: true })
|
||||
await fs.promises.writeFile(
|
||||
this.sshKeyPath,
|
||||
this.settings.sshKey.trim() + '\n',
|
||||
{mode: 0o600}
|
||||
{ mode: 0o600 }
|
||||
)
|
||||
|
||||
// Remove inherited permissions on Windows
|
||||
|
|
@ -366,9 +366,18 @@ class GitAuthHelper {
|
|||
true // globalConfig?
|
||||
)
|
||||
} else {
|
||||
// Host git directory
|
||||
let gitDir = path.join(this.git.getWorkingDirectory(), '.git')
|
||||
gitDir = gitDir.replace(/\\/g, '/') // Use forward slashes, even on Windows
|
||||
// Host git directory - resolve symlinks so includeIf gitdir matching works
|
||||
// on self-hosted runners where _work is a symlink to an external volume.
|
||||
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
|
||||
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`
|
||||
|
|
|
|||
Loading…
Reference in New Issue