@@ -411,8 +411,40 @@ class GitAuthHelper {
411411 }
412412 removeToken() {
413413 return __awaiter(this, void 0, void 0, function* () {
414- // HTTP extra header
414+ // Remove HTTP extra header from local git config and submodule configs
415415 yield this.removeGitConfig(this.tokenConfigKey);
416+ //
417+ // Cleanup actions/checkout@v6 style credentials
418+ //
419+ // Collect credentials config paths that need to be removed
420+ const credentialsPaths = new Set();
421+ // Remove includeIf entries that point to git-credentials-*.config files
422+ const mainCredentialsPaths = yield this.removeIncludeIfCredentials();
423+ mainCredentialsPaths.forEach(path => credentialsPaths.add(path));
424+ // Remove submodule includeIf entries that point to git-credentials-*.config files
425+ try {
426+ const submoduleConfigPaths = yield this.git.getSubmoduleConfigPaths(true);
427+ for (const configPath of submoduleConfigPaths) {
428+ const submoduleCredentialsPaths = yield this.removeIncludeIfCredentials(configPath);
429+ submoduleCredentialsPaths.forEach(path => credentialsPaths.add(path));
430+ }
431+ }
432+ catch (err) {
433+ core.debug(`Unable to get submodule config paths: ${err}`);
434+ }
435+ // Remove credentials config files
436+ for (const credentialsPath of credentialsPaths) {
437+ // Only remove credentials config files if they are under RUNNER_TEMP
438+ const runnerTemp = process.env['RUNNER_TEMP'];
439+ if (runnerTemp && credentialsPath.startsWith(runnerTemp)) {
440+ try {
441+ yield io.rmRF(credentialsPath);
442+ }
443+ catch (err) {
444+ core.debug(`Failed to remove credentials config '${credentialsPath}': ${err}`);
445+ }
446+ }
447+ }
416448 });
417449 }
418450 removeGitConfig(configKey_1) {
@@ -430,6 +462,49 @@ class GitAuthHelper {
430462 `sh -c "git config --local --name-only --get-regexp '${pattern}' && git config --local --unset-all '${configKey}' || :"`, true);
431463 });
432464 }
465+ /**
466+ * Removes includeIf entries that point to git-credentials-*.config files.
467+ * This handles cleanup of credentials configured by newer versions of the action.
468+ * @param configPath Optional path to a specific git config file to operate on
469+ * @returns Array of unique credentials config file paths that were found and removed
470+ */
471+ removeIncludeIfCredentials(configPath) {
472+ return __awaiter(this, void 0, void 0, function* () {
473+ const credentialsPaths = new Set();
474+ try {
475+ // Get all includeIf.gitdir keys
476+ const keys = yield this.git.tryGetConfigKeys('^includeIf\\.gitdir:', false, // globalConfig?
477+ configPath);
478+ for (const key of keys) {
479+ // Get all values for this key
480+ const values = yield this.git.tryGetConfigValues(key, false, // globalConfig?
481+ configPath);
482+ if (values.length > 0) {
483+ // Remove only values that match git-credentials-<uuid>.config pattern
484+ for (const value of values) {
485+ if (this.testCredentialsConfigPath(value)) {
486+ credentialsPaths.add(value);
487+ yield this.git.tryConfigUnsetValue(key, value, false, configPath);
488+ }
489+ }
490+ }
491+ }
492+ }
493+ catch (err) {
494+ // Ignore errors - this is cleanup code
495+ core.debug(`Error during includeIf cleanup${configPath ? ` for ${configPath}` : ''}: ${err}`);
496+ }
497+ return Array.from(credentialsPaths);
498+ });
499+ }
500+ /**
501+ * Tests if a path matches the git-credentials-*.config pattern used by newer versions.
502+ * @param path The path to test
503+ * @returns True if the path matches the credentials config pattern
504+ */
505+ testCredentialsConfigPath(path) {
506+ return /git-credentials-[0-9a-f-]+\.config$/i.test(path);
507+ }
433508}
434509
435510
@@ -706,6 +781,16 @@ class GitCommandManager {
706781 throw new Error('Unexpected output when retrieving default branch');
707782 });
708783 }
784+ getSubmoduleConfigPaths(recursive) {
785+ return __awaiter(this, void 0, void 0, function* () {
786+ // Get submodule config file paths.
787+ // Use `--show-origin` to get the config file path for each submodule.
788+ const output = yield this.submoduleForeach(`git config --local --show-origin --name-only --get-regexp remote.origin.url`, recursive);
789+ // Extract config file paths from the output (lines starting with "file:").
790+ const configPaths = output.match(/(?<=(^|\n)file:)[^\t]+(?=\tremote\.origin\.url)/g) || [];
791+ return configPaths;
792+ });
793+ }
709794 getWorkingDirectory() {
710795 return this.workingDirectory;
711796 }
@@ -836,6 +921,20 @@ class GitCommandManager {
836921 return output.exitCode === 0;
837922 });
838923 }
924+ tryConfigUnsetValue(configKey, configValue, globalConfig, configFile) {
925+ return __awaiter(this, void 0, void 0, function* () {
926+ const args = ['config'];
927+ if (configFile) {
928+ args.push('--file', configFile);
929+ }
930+ else {
931+ args.push(globalConfig ? '--global' : '--local');
932+ }
933+ args.push('--unset', configKey, configValue);
934+ const output = yield this.execGit(args, true);
935+ return output.exitCode === 0;
936+ });
937+ }
839938 tryDisableAutomaticGarbageCollection() {
840939 return __awaiter(this, void 0, void 0, function* () {
841940 const output = yield this.execGit(['config', '--local', 'gc.auto', '0'], true);
@@ -855,6 +954,46 @@ class GitCommandManager {
855954 return stdout;
856955 });
857956 }
957+ tryGetConfigValues(configKey, globalConfig, configFile) {
958+ return __awaiter(this, void 0, void 0, function* () {
959+ const args = ['config'];
960+ if (configFile) {
961+ args.push('--file', configFile);
962+ }
963+ else {
964+ args.push(globalConfig ? '--global' : '--local');
965+ }
966+ args.push('--get-all', configKey);
967+ const output = yield this.execGit(args, true);
968+ if (output.exitCode !== 0) {
969+ return [];
970+ }
971+ return output.stdout
972+ .trim()
973+ .split('\n')
974+ .filter(value => value.trim());
975+ });
976+ }
977+ tryGetConfigKeys(pattern, globalConfig, configFile) {
978+ return __awaiter(this, void 0, void 0, function* () {
979+ const args = ['config'];
980+ if (configFile) {
981+ args.push('--file', configFile);
982+ }
983+ else {
984+ args.push(globalConfig ? '--global' : '--local');
985+ }
986+ args.push('--name-only', '--get-regexp', pattern);
987+ const output = yield this.execGit(args, true);
988+ if (output.exitCode !== 0) {
989+ return [];
990+ }
991+ return output.stdout
992+ .trim()
993+ .split('\n')
994+ .filter(key => key.trim());
995+ });
996+ }
858997 tryReset() {
859998 return __awaiter(this, void 0, void 0, function* () {
860999 const output = yield this.execGit(['reset', '--hard', 'HEAD'], true);
0 commit comments