Read-only mirror — the public repositories of the Forgejo instance, refreshed every 10 minutes. The live instance (fg.dieschoenewolke.de) is reachable only over the VPN; clone here with https://git.dieschoenewolke.de/git/<owner>/<repo>.git.
summaryrefslogtreecommitdiff
path: root/__test__/git-auth-helper.test.ts
diff options
context:
space:
mode:
authoreric sciple <ericsciple@users.noreply.github.com>2025-11-13 17:20:02 -0600
committerGitHub <noreply@github.com>2025-11-13 17:20:02 -0600
commit65c48109f791f32b21b183a75cea8fc23cf659e6 (patch)
treeaea96b3e80c21c26a319652e510e7b0429d019a8 /__test__/git-auth-helper.test.ts
parent8a1e468c248961a649547d7e37c1d549f21c9235 (diff)
Cleanup actions/checkout@v6 auth style (#2305)v4.3.1
Diffstat (limited to '__test__/git-auth-helper.test.ts')
-rw-r--r--__test__/git-auth-helper.test.ts289
1 files changed, 289 insertions, 0 deletions
diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts
index 7633704..9acba54 100644
--- a/__test__/git-auth-helper.test.ts
+++ b/__test__/git-auth-helper.test.ts
@@ -675,6 +675,283 @@ describe('git-auth-helper tests', () => {
expect(gitConfigContent.indexOf('http.')).toBeLessThan(0)
})
+ const removeAuth_removesV6StyleCredentials =
+ 'removeAuth removes v6 style credentials'
+ it(removeAuth_removesV6StyleCredentials, async () => {
+ // Arrange
+ await setup(removeAuth_removesV6StyleCredentials)
+ const authHelper = gitAuthHelper.createAuthHelper(git, settings)
+ await authHelper.configureAuth()
+
+ // Manually create v6-style credentials that would be left by v6
+ const credentialsFileName =
+ 'git-credentials-12345678-1234-1234-1234-123456789abc.config'
+ const credentialsFilePath = path.join(runnerTemp, credentialsFileName)
+ const basicCredential = Buffer.from(
+ `x-access-token:${settings.authToken}`,
+ 'utf8'
+ ).toString('base64')
+ const credentialsContent = `[http "https://github.com/"]\n\textraheader = AUTHORIZATION: basic ${basicCredential}\n`
+ await fs.promises.writeFile(credentialsFilePath, credentialsContent)
+
+ // Add includeIf entries to local git config (simulating v6 configuration)
+ const hostGitDir = path.join(workspace, '.git').replace(/\\/g, '/')
+ await fs.promises.appendFile(
+ localGitConfigPath,
+ `[includeIf "gitdir:${hostGitDir}/"]\n\tpath = ${credentialsFilePath}\n`
+ )
+ await fs.promises.appendFile(
+ localGitConfigPath,
+ `[includeIf "gitdir:/github/workspace/.git/"]\n\tpath = /github/runner_temp/${credentialsFileName}\n`
+ )
+
+ // Verify v6 style config exists
+ let gitConfigContent = (
+ await fs.promises.readFile(localGitConfigPath)
+ ).toString()
+ expect(gitConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(0)
+ expect(
+ gitConfigContent.indexOf(credentialsFilePath)
+ ).toBeGreaterThanOrEqual(0)
+ await fs.promises.stat(credentialsFilePath) // Verify file exists
+
+ // Mock the git methods to handle v6 cleanup
+ const mockTryGetConfigKeys = git.tryGetConfigKeys as jest.Mock<any, any>
+ mockTryGetConfigKeys.mockResolvedValue([
+ `includeIf.gitdir:${hostGitDir}/.path`,
+ 'includeIf.gitdir:/github/workspace/.git/.path'
+ ])
+
+ const mockTryGetConfigValues = git.tryGetConfigValues as jest.Mock<any, any>
+ mockTryGetConfigValues.mockImplementation(async (key: string) => {
+ if (key === `includeIf.gitdir:${hostGitDir}/.path`) {
+ return [credentialsFilePath]
+ }
+ if (key === 'includeIf.gitdir:/github/workspace/.git/.path') {
+ return [`/github/runner_temp/${credentialsFileName}`]
+ }
+ return []
+ })
+
+ const mockTryConfigUnsetValue = git.tryConfigUnsetValue as jest.Mock<
+ any,
+ any
+ >
+ mockTryConfigUnsetValue.mockImplementation(
+ async (
+ key: string,
+ value: string,
+ globalConfig?: boolean,
+ configPath?: string
+ ) => {
+ const targetPath = configPath || localGitConfigPath
+ let content = await fs.promises.readFile(targetPath, 'utf8')
+ // Remove the includeIf section
+ const lines = content
+ .split('\n')
+ .filter(line => !line.includes('includeIf') && !line.includes(value))
+ await fs.promises.writeFile(targetPath, lines.join('\n'))
+ return true
+ }
+ )
+
+ // Act
+ await authHelper.removeAuth()
+
+ // Assert includeIf entries removed from local git config
+ gitConfigContent = (
+ await fs.promises.readFile(localGitConfigPath)
+ ).toString()
+ expect(gitConfigContent.indexOf('includeIf')).toBeLessThan(0)
+ expect(gitConfigContent.indexOf(credentialsFilePath)).toBeLessThan(0)
+
+ // Assert credentials config file deleted
+ try {
+ await fs.promises.stat(credentialsFilePath)
+ throw new Error('Credentials file should have been deleted')
+ } catch (err) {
+ if ((err as any)?.code !== 'ENOENT') {
+ throw err
+ }
+ }
+ })
+
+ const removeAuth_removesV6StyleCredentialsFromSubmodules =
+ 'removeAuth removes v6 style credentials from submodules'
+ it(removeAuth_removesV6StyleCredentialsFromSubmodules, async () => {
+ // Arrange
+ await setup(removeAuth_removesV6StyleCredentialsFromSubmodules)
+
+ // Create fake submodule config paths
+ const submodule1Dir = path.join(workspace, '.git', 'modules', 'submodule-1')
+ const submodule1ConfigPath = path.join(submodule1Dir, 'config')
+ await fs.promises.mkdir(submodule1Dir, {recursive: true})
+ await fs.promises.writeFile(submodule1ConfigPath, '')
+
+ const authHelper = gitAuthHelper.createAuthHelper(git, settings)
+ await authHelper.configureAuth()
+
+ // Create v6-style credentials file
+ const credentialsFileName =
+ 'git-credentials-abcdef12-3456-7890-abcd-ef1234567890.config'
+ const credentialsFilePath = path.join(runnerTemp, credentialsFileName)
+ const basicCredential = Buffer.from(
+ `x-access-token:${settings.authToken}`,
+ 'utf8'
+ ).toString('base64')
+ const credentialsContent = `[http "https://github.com/"]\n\textraheader = AUTHORIZATION: basic ${basicCredential}\n`
+ await fs.promises.writeFile(credentialsFilePath, credentialsContent)
+
+ // Add includeIf entries to submodule config
+ const submodule1GitDir = submodule1Dir.replace(/\\/g, '/')
+ await fs.promises.appendFile(
+ submodule1ConfigPath,
+ `[includeIf "gitdir:${submodule1GitDir}/"]\n\tpath = ${credentialsFilePath}\n`
+ )
+
+ // Verify submodule config has includeIf entry
+ let submoduleConfigContent = (
+ await fs.promises.readFile(submodule1ConfigPath)
+ ).toString()
+ expect(submoduleConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(
+ 0
+ )
+ expect(
+ submoduleConfigContent.indexOf(credentialsFilePath)
+ ).toBeGreaterThanOrEqual(0)
+
+ // Mock getSubmoduleConfigPaths
+ const mockGetSubmoduleConfigPaths =
+ git.getSubmoduleConfigPaths as jest.Mock<any, any>
+ mockGetSubmoduleConfigPaths.mockResolvedValue([submodule1ConfigPath])
+
+ // Mock tryGetConfigKeys for submodule
+ const mockTryGetConfigKeys = git.tryGetConfigKeys as jest.Mock<any, any>
+ mockTryGetConfigKeys.mockImplementation(
+ async (pattern: string, globalConfig?: boolean, configPath?: string) => {
+ if (configPath === submodule1ConfigPath) {
+ return [`includeIf.gitdir:${submodule1GitDir}/.path`]
+ }
+ return []
+ }
+ )
+
+ // Mock tryGetConfigValues for submodule
+ const mockTryGetConfigValues = git.tryGetConfigValues as jest.Mock<any, any>
+ mockTryGetConfigValues.mockImplementation(
+ async (key: string, globalConfig?: boolean, configPath?: string) => {
+ if (
+ configPath === submodule1ConfigPath &&
+ key === `includeIf.gitdir:${submodule1GitDir}/.path`
+ ) {
+ return [credentialsFilePath]
+ }
+ return []
+ }
+ )
+
+ // Mock tryConfigUnsetValue for submodule
+ const mockTryConfigUnsetValue = git.tryConfigUnsetValue as jest.Mock<
+ any,
+ any
+ >
+ mockTryConfigUnsetValue.mockImplementation(
+ async (
+ key: string,
+ value: string,
+ globalConfig?: boolean,
+ configPath?: string
+ ) => {
+ const targetPath = configPath || localGitConfigPath
+ let content = await fs.promises.readFile(targetPath, 'utf8')
+ const lines = content
+ .split('\n')
+ .filter(line => !line.includes('includeIf') && !line.includes(value))
+ await fs.promises.writeFile(targetPath, lines.join('\n'))
+ return true
+ }
+ )
+
+ // Act
+ await authHelper.removeAuth()
+
+ // Assert submodule includeIf entries removed
+ submoduleConfigContent = (
+ await fs.promises.readFile(submodule1ConfigPath)
+ ).toString()
+ expect(submoduleConfigContent.indexOf('includeIf')).toBeLessThan(0)
+ expect(submoduleConfigContent.indexOf(credentialsFilePath)).toBeLessThan(0)
+
+ // Assert credentials file deleted
+ try {
+ await fs.promises.stat(credentialsFilePath)
+ throw new Error('Credentials file should have been deleted')
+ } catch (err) {
+ if ((err as any)?.code !== 'ENOENT') {
+ throw err
+ }
+ }
+ })
+
+ const removeAuth_skipsV6CleanupWhenEnvVarSet =
+ 'removeAuth skips v6 cleanup when ACTIONS_CHECKOUT_SKIP_V6_CLEANUP is set'
+ it(removeAuth_skipsV6CleanupWhenEnvVarSet, async () => {
+ // Arrange
+ await setup(removeAuth_skipsV6CleanupWhenEnvVarSet)
+
+ // Set the skip environment variable
+ process.env['ACTIONS_CHECKOUT_SKIP_V6_CLEANUP'] = '1'
+
+ const authHelper = gitAuthHelper.createAuthHelper(git, settings)
+ await authHelper.configureAuth()
+
+ // Create v6-style credentials file in RUNNER_TEMP
+ const credentialsFileName = 'git-credentials-test-uuid-1234-5678.config'
+ const credentialsFilePath = path.join(runnerTemp, credentialsFileName)
+ const credentialsContent =
+ '[http "https://github.com/"]\n\textraheader = AUTHORIZATION: basic token\n'
+ await fs.promises.writeFile(credentialsFilePath, credentialsContent)
+
+ // Add includeIf section to local git config (separate from http.* config)
+ const includeIfSection = `\n[includeIf "gitdir:/some/path/.git/"]\n\tpath = ${credentialsFilePath}\n`
+ await fs.promises.appendFile(localGitConfigPath, includeIfSection)
+
+ // Verify v6 style config exists
+ let gitConfigContent = (
+ await fs.promises.readFile(localGitConfigPath)
+ ).toString()
+ expect(gitConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(0)
+ await fs.promises.stat(credentialsFilePath) // Verify file exists
+
+ // Act
+ await authHelper.removeAuth()
+
+ // Assert v5 cleanup still happened (http.* removed)
+ gitConfigContent = (
+ await fs.promises.readFile(localGitConfigPath)
+ ).toString()
+ expect(
+ gitConfigContent.indexOf('http.https://github.com/.extraheader')
+ ).toBeLessThan(0)
+
+ // Assert v6 cleanup was skipped - includeIf should still be present
+ expect(gitConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(0)
+ expect(
+ gitConfigContent.indexOf(credentialsFilePath)
+ ).toBeGreaterThanOrEqual(0)
+
+ // Assert credentials file still exists (wasn't deleted)
+ await fs.promises.stat(credentialsFilePath) // File should still exist
+
+ // Assert debug message was logged
+ expect(core.debug).toHaveBeenCalledWith(
+ 'Skipping v6 style cleanup due to ACTIONS_CHECKOUT_SKIP_V6_CLEANUP'
+ )
+
+ // Cleanup
+ delete process.env['ACTIONS_CHECKOUT_SKIP_V6_CLEANUP']
+ })
+
const removeGlobalConfig_removesOverride =
'removeGlobalConfig removes override'
it(removeGlobalConfig_removesOverride, async () => {
@@ -796,6 +1073,18 @@ async function setup(testName: string): Promise<void> {
),
tryDisableAutomaticGarbageCollection: jest.fn(),
tryGetFetchUrl: jest.fn(),
+ getSubmoduleConfigPaths: jest.fn(async () => {
+ return []
+ }),
+ tryConfigUnsetValue: jest.fn(async () => {
+ return true
+ }),
+ tryGetConfigValues: jest.fn(async () => {
+ return []
+ }),
+ tryGetConfigKeys: jest.fn(async () => {
+ return []
+ }),
tryReset: jest.fn(),
version: jest.fn()
}