@ -86,29 +86,16 @@ describe('git-auth-helper tests', () => {
// Act
await authHelper . configureAuth ( )
// Assert config - check that .git/config contains includeIf entries
const lo calC onfigContent = (
// Assert config
const configContent = (
await fs . promises . readFile ( localGitConfigPath )
) . toString ( )
expect (
localConfigContent . indexOf ( 'includeIf.gitdir:' )
) . toBeGreaterThanOrEqual ( 0 )
// Assert credentials config file contains the actual credentials
const credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBe ( 1 )
const credentialsConfigPath = path . join ( runnerTemp , credentialsFiles [ 0 ] )
const credentialsContent = (
await fs . promises . readFile ( credentialsConfigPath )
) . toString ( )
const basicCredential = Buffer . from (
` x-access-token: ${ settings . authToken } ` ,
'utf8'
) . toString ( 'base64' )
expect (
c redentials Content. indexOf (
configContent . indexOf (
` http. ${ expectedServerUrl } /.extraheader AUTHORIZATION: basic ${ basicCredential } `
)
) . toBeGreaterThanOrEqual ( 0 )
@ -133,7 +120,7 @@ describe('git-auth-helper tests', () => {
'inject https://github.com as github server url'
it ( configureAuth_AcceptsGitHubServerUrlSetToGHEC , async ( ) = > {
await testAuthHeader (
configureAuth_AcceptsGitHubServerUrl SetToGHEC ,
configureAuth_AcceptsGitHubServerUrl ,
'https://github.com'
)
} )
@ -154,17 +141,12 @@ describe('git-auth-helper tests', () => {
// Act
await authHelper . configureAuth ( )
// Assert config - check credentials config file (not local .git/config)
const credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBe ( 1 )
const credentialsConfigPath = path . join ( runnerTemp , credentialsFiles [ 0 ] )
const credentialsContent = (
await fs . promises . readFile ( credentialsConfigPath )
// Assert config
const configContent = (
await fs . promises . readFile ( localGitConfigPath )
) . toString ( )
expect (
c redentials Content. indexOf (
configContent . indexOf (
` http.https://github.com/.extraheader AUTHORIZATION `
)
) . toBeGreaterThanOrEqual ( 0 )
@ -269,16 +251,13 @@ describe('git-auth-helper tests', () => {
expectedSshCommand
)
// Assert git config
// Assert y git config
const gitConfigLines = ( await fs . promises . readFile ( localGitConfigPath ) )
. toString ( )
. split ( '\n' )
. filter ( x = > x )
// Should have includeIf entries pointing to credentials file
expect ( gitConfigLines . length ) . toBeGreaterThan ( 0 )
expect (
gitConfigLines . some ( line = > line . indexOf ( 'includeIf.gitdir:' ) >= 0 )
) . toBeTruthy ( )
expect ( gitConfigLines ) . toHaveLength ( 1 )
expect ( gitConfigLines [ 0 ] ) . toMatch ( /^http\./ )
} )
const configureAuth_setsSshCommandWhenPersistCredentialsTrue =
@ -440,20 +419,8 @@ describe('git-auth-helper tests', () => {
expect (
configContent . indexOf ( 'value-from-global-config' )
) . toBeGreaterThanOrEqual ( 0 )
// Global config should have include.path pointing to credentials file
expect ( configContent . indexOf ( 'include.path' ) ) . toBeGreaterThanOrEqual ( 0 )
// Check credentials in the separate config file
const credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBeGreaterThan ( 0 )
const credentialsConfigPath = path . join ( runnerTemp , credentialsFiles [ 0 ] )
const credentialsContent = (
await fs . promises . readFile ( credentialsConfigPath )
) . toString ( )
expect (
c redentials Content. indexOf (
configContent . indexOf (
` http.https://github.com/.extraheader AUTHORIZATION: basic ${ basicCredential } `
)
) . toBeGreaterThanOrEqual ( 0 )
@ -496,20 +463,8 @@ describe('git-auth-helper tests', () => {
const configContent = (
await fs . promises . readFile ( path . join ( git . env [ 'HOME' ] , '.gitconfig' ) )
) . toString ( )
// Global config should have include.path pointing to credentials file
expect ( configContent . indexOf ( 'include.path' ) ) . toBeGreaterThanOrEqual ( 0 )
// Check credentials in the separate config file
const credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBeGreaterThan ( 0 )
const credentialsConfigPath = path . join ( runnerTemp , credentialsFiles [ 0 ] )
const credentialsContent = (
await fs . promises . readFile ( credentialsConfigPath )
) . toString ( )
expect (
c redentials Content. indexOf (
configContent . indexOf (
` http.https://github.com/.extraheader AUTHORIZATION: basic ${ basicCredential } `
)
) . toBeGreaterThanOrEqual ( 0 )
@ -595,15 +550,15 @@ describe('git-auth-helper tests', () => {
await authHelper . configureSubmoduleAuth ( )
// Assert
// Should configure insteadOf (2 calls for two values)
expect ( mockSubmoduleForeach ) . toHaveBeenCalledTimes ( 3 )
expect ( mockSubmoduleForeach ) . toHaveBeenCalledTimes ( 4 )
expect ( mockSubmoduleForeach . mock . calls [ 0 ] [ 0 ] ) . toMatch (
/unset-all.*insteadOf/
)
expect ( mockSubmoduleForeach . mock . calls [ 1 ] [ 0 ] ) . toMatch (
expect ( mockSubmoduleForeach . mock . calls [ 1 ] [ 0 ] ) . toMatch ( /http.*extraheader/ )
expect ( mockSubmoduleForeach . mock . calls [ 2 ] [ 0 ] ) . toMatch (
/url.*insteadOf.*git@github.com:/
)
expect ( mockSubmoduleForeach . mock . calls [ 2 ] [ 0 ] ) . toMatch (
expect ( mockSubmoduleForeach . mock . calls [ 3 ] [ 0 ] ) . toMatch (
/url.*insteadOf.*org-123456@github.com:/
)
}
@ -634,12 +589,12 @@ describe('git-auth-helper tests', () => {
await authHelper . configureSubmoduleAuth ( )
// Assert
// Should configure sshCommand (1 call)
expect ( mockSubmoduleForeach ) . toHaveBeenCalledTimes ( 2 )
expect ( mockSubmoduleForeach ) . toHaveBeenCalledTimes ( 3 )
expect ( mockSubmoduleForeach . mock . calls [ 0 ] [ 0 ] ) . toMatch (
/unset-all.*insteadOf/
)
expect ( mockSubmoduleForeach . mock . calls [ 1 ] [ 0 ] ) . toMatch ( /core\.sshCommand/ )
expect ( mockSubmoduleForeach . mock . calls [ 1 ] [ 0 ] ) . toMatch ( /http.*extraheader/ )
expect ( mockSubmoduleForeach . mock . calls [ 2 ] [ 0 ] ) . toMatch ( /core\.sshCommand/ )
}
)
@ -705,81 +660,112 @@ describe('git-auth-helper tests', () => {
await setup ( removeAuth_removesToken )
const authHelper = gitAuthHelper . createAuthHelper ( git , settings )
await authHelper . configureAuth ( )
// Verify includeIf entries exist in local config
let localConfigContent = (
let gitConfigContent = (
await fs . promises . readFile ( localGitConfigPath )
) . toString ( )
expect (
localConfigContent . indexOf ( 'includeIf.gitdir:' )
) . toBeGreaterThanOrEqual ( 0 )
// Verify both host and container includeIf entries are present
const hostGitDir = path . join ( workspace , '.git' ) . replace ( /\\/g , '/' )
expect (
localConfigContent . indexOf ( ` includeIf.gitdir: ${ hostGitDir } .path ` )
) . toBeGreaterThanOrEqual ( 0 )
expect (
localConfigContent . indexOf ( 'includeIf.gitdir:/github/workspace/.git.path' )
) . toBeGreaterThanOrEqual ( 0 )
expect ( gitConfigContent . indexOf ( 'http.' ) ) . toBeGreaterThanOrEqual ( 0 ) // sanity check
// Verify credentials file exists
let credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBe ( 1 )
const credentialsFilePath = path . join ( runnerTemp , credentialsFiles [ 0 ] )
// Act
await authHelper . removeAuth ( )
// Verify credentials file contains the auth token
let credentials Content = (
await fs . promises . readFile ( credentialsFile Path)
// Assert git config
gitConfigContent = (
await fs . promises . readFile ( localGitConfigPath )
) . toString ( )
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' )
expect (
credentialsContent . indexOf (
` http.https://github.com/.extraheader AUTHORIZATION: basic ${ basicCredential } `
)
) . toBeGreaterThanOrEqual ( 0 )
const credentialsContent = ` [http "https://github.com/"] \ n \ textraheader = AUTHORIZATION: basic ${ basicCredential } \ n `
await fs . promises . writeFile ( credentialsFilePath , credentialsContent )
// Verify the includeIf entries point to the credentials file
const containerCredentialsPath = path . posix . join (
'/github/runner_temp' ,
path . basename ( credentialsFilePath )
// 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 (
localConfigContent . indexOf ( credentialsFilePath )
) . toBeGreaterThanOrEqual ( 0 )
expect (
localConfigContent . indexOf ( containerCredentialsPath )
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 all includeIf entries removed from local git config
localConfigContent = (
// Assert includeIf entries removed from local git config
git ConfigContent = (
await fs . promises . readFile ( localGitConfigPath )
) . toString ( )
expect ( localConfigContent . indexOf ( 'includeIf.gitdir:' ) ) . toBeLessThan ( 0 )
expect (
localConfigContent . indexOf ( ` includeIf.gitdir: ${ hostGitDir } .path ` )
) . toBeLessThan ( 0 )
expect (
localConfigContent . indexOf ( 'includeIf.gitdir:/github/workspace/.git.path' )
) . toBeLessThan ( 0 )
expect ( localConfigContent . indexOf ( credentialsFilePath ) ) . toBeLessThan ( 0 )
expect ( localConfigContent . indexOf ( containerCredentialsPath ) ) . toBeLessThan ( 0 )
expect ( gitConfigContent . indexOf ( 'includeIf' ) ) . toBeLessThan ( 0 )
expect ( gitConfigContent . indexOf ( credentialsFilePath ) ) . toBeLessThan ( 0 )
// Assert credentials config file deleted
credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBe ( 0 )
// Verify credentials file no longer exists on disk
try {
await fs . promises . stat ( credentialsFilePath )
throw new Error ( 'Credentials file should have been deleted' )
@ -790,108 +776,113 @@ describe('git-auth-helper tests', () => {
}
} )
const removeAuth_removes Token FromSubmodules =
'removeAuth removes token from submodules'
it ( removeAuth_removes Token FromSubmodules, async ( ) = > {
const removeAuth_removes V6StyleCredentials FromSubmodules =
'removeAuth removes v6 style credentials from submodules'
it ( removeAuth_removes V6StyleCredentials FromSubmodules, async ( ) = > {
// Arrange
await setup ( removeAuth_removes Token FromSubmodules)
await setup ( removeAuth_removes V6StyleCredentials FromSubmodules)
// Create fake submodule config paths
const submodule1Dir = path . join ( workspace , '.git' , 'modules' , 'submodule-1' )
const submodule2Dir = path . join ( workspace , '.git' , 'modules' , 'submodule-2' )
const submodule1ConfigPath = path . join ( submodule1Dir , 'config' )
const submodule2ConfigPath = path . join ( submodule2Dir , 'config' )
await fs . promises . mkdir ( submodule1Dir , { recursive : true } )
await fs . promises . mkdir ( submodule2Dir , { recursive : true } )
await fs . promises . writeFile ( submodule1ConfigPath , '' )
await fs . promises . writeFile ( submodule2ConfigPath , '' )
// Mock getSubmoduleConfigPaths to return our fake submodules (for both configure and remove)
const mockGetSubmoduleConfigPaths =
git . getSubmoduleConfigPaths as jest . Mock < any , any >
mockGetSubmoduleConfigPaths . mockResolvedValue ( [
submodule1ConfigPath ,
submodule2ConfigPath
] )
const authHelper = gitAuthHelper . createAuthHelper ( git , settings )
await authHelper . configureAuth ( )
await authHelper . configureSubmoduleAuth ( )
// Verify credentials file exists
let credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
// 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 `
)
expect ( credentialsFiles . length ) . toBe ( 1 )
const credentialsFilePath = path . join ( runnerTemp , credentialsFiles [ 0 ] )
// Verify submodule 1 config has includeIf entries
let submodule1Content = (
// Verify submodule config has includeIf entry
let submodule Config Content = (
await fs . promises . readFile ( submodule1ConfigPath )
) . toString ( )
const submodule1GitDir = submodule1Dir . replace ( /\\/g , '/' )
expect (
submodule1Content . indexOf ( ` includeIf.gitdir: ${ submodule1GitDir } .path ` )
) . toBeGreaterThanOrEqual ( 0 )
expect ( submoduleConfigContent . indexOf ( 'includeIf' ) ) . toBeGreaterThanOrEqual (
0
)
expect (
submodule 1 Content. indexOf ( credentialsFilePath )
submodule Config Content. indexOf ( credentialsFilePath )
) . toBeGreaterThanOrEqual ( 0 )
// Verify submodule 2 config has includeIf entries
let submodule2Content = (
await fs . promises . readFile ( submodule2ConfigPath )
) . toString ( )
const submodule2GitDir = submodule2Dir . replace ( /\\/g , '/' )
expect (
submodule2Content . indexOf ( ` includeIf.gitdir: ${ submodule2GitDir } .path ` )
) . toBeGreaterThanOrEqual ( 0 )
expect (
submodule2Content . 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 [ ]
}
)
// Verify both host and container paths are in each submodule config
const containerCredentialsPath = path . posix . join (
'/github/runner_temp' ,
path . basename ( credentialsFilePath )
// 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 [ ]
}
)
expect (
submodule1Content . indexOf ( containerCredentialsPath )
) . toBeGreaterThanOrEqual ( 0 )
expect (
submodule2Content . indexOf ( containerCredentialsPath )
) . toBeGreaterThanOrEqual ( 0 )
// Act - ensure mock persists for removeAuth
mockGetSubmoduleConfigPaths . mockResolvedValue ( [
submodule1ConfigPath ,
submodule2ConfigPath
] )
// 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 1 includeIf entries removed
submodule1Content = (
// Assert submodule includeIf entries removed
submodule Config Content = (
await fs . promises . readFile ( submodule1ConfigPath )
) . toString ( )
expect ( submodule1Content . indexOf ( 'includeIf.gitdir:' ) ) . toBeLessThan ( 0 )
expect ( submodule1Content . indexOf ( credentialsFilePath ) ) . toBeLessThan ( 0 )
expect ( submodule1Content . indexOf ( containerCredentialsPath ) ) . toBeLessThan ( 0 )
// Assert submodule 2 includeIf entries removed
submodule2Content = (
await fs . promises . readFile ( submodule2ConfigPath )
) . toString ( )
expect ( submodule2Content . indexOf ( 'includeIf.gitdir:' ) ) . toBeLessThan ( 0 )
expect ( submodule2Content . indexOf ( credentialsFilePath ) ) . toBeLessThan ( 0 )
expect ( submodule2Content . indexOf ( containerCredentialsPath ) ) . toBeLessThan ( 0 )
// Assert credentials config file deleted
credentialsFiles = ( await fs . promises . readdir ( runnerTemp ) ) . filter (
f = > f . startsWith ( 'git-credentials-' ) && f . endsWith ( '.config' )
)
expect ( credentialsFiles . length ) . toBe ( 0 )
expect ( submoduleConfigContent . indexOf ( 'includeIf' ) ) . toBeLessThan ( 0 )
expect ( submoduleConfigContent . indexOf ( credentialsFilePath ) ) . toBeLessThan ( 0 )
// Verify credentials file no longer exists on disk
// Assert credentials file deleted
try {
await fs . promises . stat ( credentialsFilePath )
throw new Error ( 'Credentials file should have been deleted' )
@ -902,6 +893,65 @@ describe('git-auth-helper tests', () => {
}
} )
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 ( ) = > {
@ -928,52 +978,6 @@ describe('git-auth-helper tests', () => {
}
}
} )
const testCredentialsConfigPath_matchesCredentialsConfigPaths =
'testCredentialsConfigPath matches credentials config paths'
it ( testCredentialsConfigPath_matchesCredentialsConfigPaths , async ( ) = > {
// Arrange
await setup ( testCredentialsConfigPath_matchesCredentialsConfigPaths )
const authHelper = gitAuthHelper . createAuthHelper ( git , settings )
// Get a real credentials config path
const credentialsConfigPath = await (
authHelper as any
) . getCredentialsConfigPath ( )
// Act & Assert
expect (
( authHelper as any ) . testCredentialsConfigPath ( credentialsConfigPath )
) . toBe ( true )
expect (
( authHelper as any ) . testCredentialsConfigPath (
'/some/path/git-credentials-12345678-abcd-1234-5678-123456789012.config'
)
) . toBe ( true )
expect (
( authHelper as any ) . testCredentialsConfigPath (
'/some/path/git-credentials-abcdef12-3456-7890-abcd-ef1234567890.config'
)
) . toBe ( true )
// Test invalid paths
expect (
( authHelper as any ) . testCredentialsConfigPath (
'/some/path/other-config.config'
)
) . toBe ( false )
expect (
( authHelper as any ) . testCredentialsConfigPath (
'/some/path/git-credentials-invalid.config'
)
) . toBe ( false )
expect (
( authHelper as any ) . testCredentialsConfigPath (
'/some/path/git-credentials-.config'
)
) . toBe ( false )
expect ( ( authHelper as any ) . testCredentialsConfigPath ( '' ) ) . toBe ( false )
} )
} )
async function setup ( testName : string ) : Promise < void > {
@ -988,7 +992,6 @@ async function setup(testName: string): Promise<void> {
await fs . promises . mkdir ( tempHomedir , { recursive : true } )
process . env [ 'RUNNER_TEMP' ] = runnerTemp
process . env [ 'HOME' ] = tempHomedir
process . env [ 'GITHUB_WORKSPACE' ] = workspace
// Create git config
globalGitConfigPath = path . join ( tempHomedir , '.gitconfig' )
@ -1007,20 +1010,10 @@ async function setup(testName: string): Promise<void> {
checkout : jest.fn ( ) ,
checkoutDetach : jest.fn ( ) ,
config : jest.fn (
async (
key : string ,
value : string ,
globalConfig? : boolean ,
add? : boolean ,
configFile? : string
) = > {
const configPath =
configFile ||
( globalConfig
? path . join ( git . env [ 'HOME' ] || tempHomedir , '.gitconfig' )
: localGitConfigPath )
// Ensure directory exists
await fs . promises . mkdir ( path . dirname ( configPath ) , { recursive : true } )
async ( key : string , value : string , globalConfig? : boolean ) = > {
const configPath = globalConfig
? path . join ( git . env [ 'HOME' ] || tempHomedir , '.gitconfig' )
: localGitConfigPath
await fs . promises . appendFile ( configPath , ` \ n ${ key } ${ value } ` )
}
) ,
@ -1040,7 +1033,6 @@ async function setup(testName: string): Promise<void> {
env : { } ,
fetch : jest.fn ( ) ,
getDefaultBranch : jest.fn ( ) ,
getSubmoduleConfigPaths : jest.fn ( async ( ) = > [ ] ) ,
getWorkingDirectory : jest.fn ( ( ) = > workspace ) ,
init : jest.fn ( ) ,
isDetached : jest.fn ( ) ,
@ -1079,72 +1071,20 @@ async function setup(testName: string): Promise<void> {
return true
}
) ,
tryConfigUnsetValue : jest.fn (
async (
key : string ,
value : string ,
globalConfig? : boolean ,
configPath? : string
) : Promise < boolean > = > {
const targetConfigPath =
configPath ||
( globalConfig
? path . join ( git . env [ 'HOME' ] || tempHomedir , '.gitconfig' )
: localGitConfigPath )
let content = await fs . promises . readFile ( targetConfigPath )
let lines = content
. toString ( )
. split ( '\n' )
. filter ( x = > x )
. filter ( x = > ! ( x . startsWith ( key ) && x . includes ( value ) ) )
await fs . promises . writeFile ( targetConfigPath , lines . join ( '\n' ) )
return true
}
) ,
tryDisableAutomaticGarbageCollection : jest.fn ( ) ,
tryGetFetchUrl : jest.fn ( ) ,
tryGetConfigValues : jest.fn (
async (
key : string ,
globalConfig? : boolean ,
configPath? : string
) : Promise < string [ ] > = > {
const targetConfigPath =
configPath ||
( globalConfig
? path . join ( git . env [ 'HOME' ] || tempHomedir , '.gitconfig' )
: localGitConfigPath )
const content = await fs . promises . readFile ( targetConfigPath )
const lines = content
. toString ( )
. split ( '\n' )
. filter ( x = > x && x . startsWith ( key ) )
. map ( x = > x . substring ( key . length ) . trim ( ) )
return lines
}
) ,
tryGetConfigKeys : jest.fn (
async (
pattern : string ,
globalConfig? : boolean ,
configPath? : string
) : Promise < string [ ] > = > {
const targetConfigPath =
configPath ||
( globalConfig
? path . join ( git . env [ 'HOME' ] || tempHomedir , '.gitconfig' )
: localGitConfigPath )
const content = await fs . promises . readFile ( targetConfigPath )
const lines = content
. toString ( )
. split ( '\n' )
. filter ( x = > x )
const keys = lines
. filter ( x = > new RegExp ( pattern ) . test ( x . split ( ' ' ) [ 0 ] ) )
. map ( x = > x . split ( ' ' ) [ 0 ] )
return [ . . . new Set ( keys ) ] // Remove duplicates
}
) ,
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 ( )
}
@ -1179,7 +1119,6 @@ async function setup(testName: string): Promise<void> {
async function getActualSshKeyPath ( ) : Promise < string > {
let actualTempFiles = ( await fs . promises . readdir ( runnerTemp ) )
. filter ( x = > ! x . startsWith ( 'git-credentials-' ) ) // Exclude credentials config file
. sort ( )
. map ( x = > path . join ( runnerTemp , x ) )
if ( actualTempFiles . length === 0 ) {
@ -1193,7 +1132,6 @@ async function getActualSshKeyPath(): Promise<string> {
async function getActualSshKnownHostsPath ( ) : Promise < string > {
let actualTempFiles = ( await fs . promises . readdir ( runnerTemp ) )
. filter ( x = > ! x . startsWith ( 'git-credentials-' ) ) // Exclude credentials config file
. sort ( )
. map ( x = > path . join ( runnerTemp , x ) )
if ( actualTempFiles . length === 0 ) {