Преглед на файлове

Fix includeIf case sensitivity on Windows self-hosted runners

Switch to includeIf.gitdir/i: on Windows so path matching is
case-insensitive, matching the filesystem behavior. This fixes
auth failures on self-hosted Windows runners where the workspace
folder casing doesn't match between the runner config and disk.

Also update the cleanup regex to handle both gitdir: and gitdir/i:
variants.

Fixes #2345
Salman Muin Kayser Chishti преди 1 месец
родител
ревизия
be385d8fff
променени са 3 файла, в които са добавени 66 реда и са изтрити 14 реда
  1. 40 0
      __test__/git-auth-helper.test.ts
  2. 13 7
      dist/index.js
  3. 13 7
      src/git-auth-helper.ts

+ 40 - 0
__test__/git-auth-helper.test.ts

@@ -974,6 +974,46 @@ describe('git-auth-helper tests', () => {
     ).toBe(false)
     expect((authHelper as any).testCredentialsConfigPath('')).toBe(false)
   })
+
+  const includeIfCleanupRegex_matchesBothVariants =
+    'includeIf cleanup regex matches both gitdir: and gitdir/i: keys'
+  it(includeIfCleanupRegex_matchesBothVariants, async () => {
+    // The cleanup regex must match both variants so credential
+    // removal works regardless of which was written
+    const regex = /^includeIf\.gitdir(\/i)?:/
+    expect(regex.test('includeIf.gitdir:D:/workspaces/repo/.git.path')).toBe(
+      true
+    )
+    expect(regex.test('includeIf.gitdir/i:D:/Workspaces/repo/.git.path')).toBe(
+      true
+    )
+    expect(regex.test('includeIf.gitdir/i:/github/workspace/.git.path')).toBe(
+      true
+    )
+    expect(regex.test('includeIf.gitdir:~/projects/foo/.git.path')).toBe(true)
+    expect(regex.test('includeIf.onbranch:main.path')).toBe(false)
+    expect(regex.test('include.path')).toBe(false)
+  })
+
+  const includeIfDirective_usesCorrectVariantForPlatform =
+    'includeIf directive uses gitdir/i on Windows and gitdir on other platforms'
+  it(includeIfDirective_usesCorrectVariantForPlatform, async () => {
+    await setup(includeIfDirective_usesCorrectVariantForPlatform)
+    const authHelper = gitAuthHelper.createAuthHelper(git, settings)
+    await authHelper.configureAuth()
+
+    const localConfigContent = (
+      await fs.promises.readFile(localGitConfigPath)
+    ).toString()
+
+    if (isWindows) {
+      expect(localConfigContent).toContain('includeIf.gitdir/i:')
+      expect(localConfigContent).not.toContain('includeIf.gitdir:')
+    } else {
+      expect(localConfigContent).toContain('includeIf.gitdir:')
+      expect(localConfigContent).not.toContain('includeIf.gitdir/i:')
+    }
+  })
 })
 
 async function setup(testName: string): Promise<void> {

+ 13 - 7
dist/index.js

@@ -151,6 +151,12 @@ const stateHelper = __importStar(__nccwpck_require__(4866));
 const urlHelper = __importStar(__nccwpck_require__(9437));
 const uuid_1 = __nccwpck_require__(5840);
 const IS_WINDOWS = process.platform === 'win32';
+// Use case-insensitive gitdir matching on Windows to handle path casing mismatches
+// between the runner's GITHUB_WORKSPACE and the actual filesystem casing.
+// See: https://github.com/actions/checkout/issues/2345
+const INCLUDE_IF_GITDIR = IS_WINDOWS
+    ? 'includeIf.gitdir/i:'
+    : 'includeIf.gitdir:';
 const SSH_COMMAND_KEY = 'core.sshCommand';
 function createAuthHelper(git, settings) {
     return new GitAuthHelper(git, settings);
@@ -270,7 +276,7 @@ class GitAuthHelper {
                     let submoduleGitDir = path.dirname(configPath); // The config file is at .git/modules/submodule-name/config
                     submoduleGitDir = submoduleGitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
                     // Configure host includeIf
-                    yield this.git.config(`includeIf.gitdir:${submoduleGitDir}.path`, credentialsConfigPath, false, // globalConfig?
+                    yield this.git.config(`${INCLUDE_IF_GITDIR}${submoduleGitDir}.path`, credentialsConfigPath, false, // globalConfig?
                     false, // add?
                     configPath);
                     // Container submodule git directory
@@ -280,7 +286,7 @@ class GitAuthHelper {
                     relativeSubmoduleGitDir = relativeSubmoduleGitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
                     const containerSubmoduleGitDir = path.posix.join('/github/workspace', relativeSubmoduleGitDir);
                     // Configure container includeIf
-                    yield this.git.config(`includeIf.gitdir:${containerSubmoduleGitDir}.path`, containerCredentialsPath, false, // globalConfig?
+                    yield this.git.config(`${INCLUDE_IF_GITDIR}${containerSubmoduleGitDir}.path`, containerCredentialsPath, false, // globalConfig?
                     false, // add?
                     configPath);
                 }
@@ -410,10 +416,10 @@ class GitAuthHelper {
                 let gitDir = path.join(this.git.getWorkingDirectory(), '.git');
                 gitDir = gitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
                 // Configure host includeIf
-                const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`;
+                const hostIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}.path`;
                 yield this.git.config(hostIncludeKey, credentialsConfigPath);
                 // Configure host includeIf for worktrees
-                const hostWorktreeIncludeKey = `includeIf.gitdir:${gitDir}/worktrees/*.path`;
+                const hostWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}/worktrees/*.path`;
                 yield this.git.config(hostWorktreeIncludeKey, credentialsConfigPath);
                 // Container git directory
                 const workingDirectory = this.git.getWorkingDirectory();
@@ -425,10 +431,10 @@ class GitAuthHelper {
                 // Container credentials config path
                 const containerCredentialsPath = path.posix.join('/github/runner_temp', path.basename(credentialsConfigPath));
                 // Configure container includeIf
-                const containerIncludeKey = `includeIf.gitdir:${containerGitDir}.path`;
+                const containerIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}.path`;
                 yield this.git.config(containerIncludeKey, containerCredentialsPath);
                 // Configure container includeIf for worktrees
-                const containerWorktreeIncludeKey = `includeIf.gitdir:${containerGitDir}/worktrees/*.path`;
+                const containerWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}/worktrees/*.path`;
                 yield this.git.config(containerWorktreeIncludeKey, containerCredentialsPath);
             }
         });
@@ -565,7 +571,7 @@ class GitAuthHelper {
             const credentialsPaths = new Set();
             try {
                 // Get all includeIf.gitdir keys
-                const keys = yield this.git.tryGetConfigKeys('^includeIf\\.gitdir:', false, // globalConfig?
+                const keys = yield this.git.tryGetConfigKeys('^includeIf\\.gitdir(/i)?:', false, // globalConfig?
                 configPath);
                 for (const key of keys) {
                     // Get all values for this key

+ 13 - 7
src/git-auth-helper.ts

@@ -13,6 +13,12 @@ import {IGitCommandManager} from './git-command-manager'
 import {IGitSourceSettings} from './git-source-settings'
 
 const IS_WINDOWS = process.platform === 'win32'
+// Use case-insensitive gitdir matching on Windows to handle path casing mismatches
+// between the runner's GITHUB_WORKSPACE and the actual filesystem casing.
+// See: https://github.com/actions/checkout/issues/2345
+const INCLUDE_IF_GITDIR = IS_WINDOWS
+  ? 'includeIf.gitdir/i:'
+  : 'includeIf.gitdir:'
 const SSH_COMMAND_KEY = 'core.sshCommand'
 
 export interface IGitAuthHelper {
@@ -182,7 +188,7 @@ class GitAuthHelper {
 
         // Configure host includeIf
         await this.git.config(
-          `includeIf.gitdir:${submoduleGitDir}.path`,
+          `${INCLUDE_IF_GITDIR}${submoduleGitDir}.path`,
           credentialsConfigPath,
           false, // globalConfig?
           false, // add?
@@ -204,7 +210,7 @@ class GitAuthHelper {
 
         // Configure container includeIf
         await this.git.config(
-          `includeIf.gitdir:${containerSubmoduleGitDir}.path`,
+          `${INCLUDE_IF_GITDIR}${containerSubmoduleGitDir}.path`,
           containerCredentialsPath,
           false, // globalConfig?
           false, // add?
@@ -371,11 +377,11 @@ class GitAuthHelper {
       gitDir = gitDir.replace(/\\/g, '/') // Use forward slashes, even on Windows
 
       // Configure host includeIf
-      const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`
+      const hostIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}.path`
       await this.git.config(hostIncludeKey, credentialsConfigPath)
 
       // Configure host includeIf for worktrees
-      const hostWorktreeIncludeKey = `includeIf.gitdir:${gitDir}/worktrees/*.path`
+      const hostWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}/worktrees/*.path`
       await this.git.config(hostWorktreeIncludeKey, credentialsConfigPath)
 
       // Container git directory
@@ -397,11 +403,11 @@ class GitAuthHelper {
       )
 
       // Configure container includeIf
-      const containerIncludeKey = `includeIf.gitdir:${containerGitDir}.path`
+      const containerIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}.path`
       await this.git.config(containerIncludeKey, containerCredentialsPath)
 
       // Configure container includeIf for worktrees
-      const containerWorktreeIncludeKey = `includeIf.gitdir:${containerGitDir}/worktrees/*.path`
+      const containerWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}/worktrees/*.path`
       await this.git.config(
         containerWorktreeIncludeKey,
         containerCredentialsPath
@@ -554,7 +560,7 @@ class GitAuthHelper {
     try {
       // Get all includeIf.gitdir keys
       const keys = await this.git.tryGetConfigKeys(
-        '^includeIf\\.gitdir:',
+        '^includeIf\\.gitdir(/i)?:',
         false, // globalConfig?
         configPath
       )