mirror of
				https://github.com/actions/checkout.git
				synced 2025-10-31 13:58:09 +08:00 
			
		
		
		
	Persist creds to a separate file
This commit is contained in:
		
							
								
								
									
										95
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										95
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							| @@ -162,6 +162,8 @@ class GitAuthHelper { | ||||
|         this.sshKeyPath = ''; | ||||
|         this.sshKnownHostsPath = ''; | ||||
|         this.temporaryHomePath = ''; | ||||
|         this.credentialsConfigPath = ''; // Path to separate credentials config file in RUNNER_TEMP
 | ||||
|         this.credentialsIncludeKeys = []; // Track includeIf/include config keys for cleanup
 | ||||
|         this.git = gitCommandManager; | ||||
|         this.settings = gitSourceSettings || {}; | ||||
|         // Token auth header
 | ||||
| @@ -187,6 +189,20 @@ class GitAuthHelper { | ||||
|             yield this.configureToken(); | ||||
|         }); | ||||
|     } | ||||
|     getCredentialsConfigPath() { | ||||
|         return __awaiter(this, void 0, void 0, function* () { | ||||
|             if (this.credentialsConfigPath) { | ||||
|                 return this.credentialsConfigPath; | ||||
|             } | ||||
|             const runnerTemp = process.env['RUNNER_TEMP'] || ''; | ||||
|             assert.ok(runnerTemp, 'RUNNER_TEMP is not defined'); | ||||
|             // Create a unique filename for this checkout instance
 | ||||
|             const configFileName = `git-credentials-${(0, uuid_1.v4)()}.config`; | ||||
|             this.credentialsConfigPath = path.join(runnerTemp, configFileName); | ||||
|             core.debug(`Credentials config path: ${this.credentialsConfigPath}`); | ||||
|             return this.credentialsConfigPath; | ||||
|         }); | ||||
|     } | ||||
|     configureTempGlobalConfig() { | ||||
|         return __awaiter(this, void 0, void 0, function* () { | ||||
|             var _a; | ||||
| @@ -229,10 +245,10 @@ class GitAuthHelper { | ||||
|     configureGlobalAuth() { | ||||
|         return __awaiter(this, void 0, void 0, function* () { | ||||
|             // 'configureTempGlobalConfig' noops if already set, just returns the path
 | ||||
|             const newGitConfigPath = yield this.configureTempGlobalConfig(); | ||||
|             yield this.configureTempGlobalConfig(); | ||||
|             try { | ||||
|                 // Configure the token
 | ||||
|                 yield this.configureToken(newGitConfigPath, true); | ||||
|                 yield this.configureToken(true); | ||||
|                 // Configure HTTPS instead of SSH
 | ||||
|                 yield this.git.tryConfigUnset(this.insteadOfKey, true); | ||||
|                 if (!this.settings.sshKey) { | ||||
| @@ -351,20 +367,45 @@ class GitAuthHelper { | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|     configureToken(configPath, globalConfig) { | ||||
|     configureToken(globalConfig) { | ||||
|         return __awaiter(this, void 0, void 0, function* () { | ||||
|             // Validate args
 | ||||
|             assert.ok((configPath && globalConfig) || (!configPath && !globalConfig), 'Unexpected configureToken parameter combinations'); | ||||
|             // Default config path
 | ||||
|             if (!configPath && !globalConfig) { | ||||
|                 configPath = path.join(this.git.getWorkingDirectory(), '.git', 'config'); | ||||
|             // Get the credentials config file path in RUNNER_TEMP
 | ||||
|             const credentialsConfigPath = yield this.getCredentialsConfigPath(); | ||||
|             // Write placeholder to the separate credentials config file using git config.
 | ||||
|             // This approach avoids the credential being captured by process creation audit events,
 | ||||
|             // which are commonly logged. For more information, refer to
 | ||||
|             // https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
 | ||||
|             yield this.git.config(this.tokenConfigKey, this.tokenPlaceholderConfigValue, false, false, credentialsConfigPath); | ||||
|             // Replace the placeholder in the credentials config file
 | ||||
|             yield this.replaceTokenPlaceholder(credentialsConfigPath); | ||||
|             // Add include or includeIf to reference the credentials config
 | ||||
|             if (globalConfig) { | ||||
|                 // For global config, use unconditional include.
 | ||||
|                 // No need to track for cleanup since the temp .gitconfig file (which contains
 | ||||
|                 // this include.path entry) gets deleted by removeGlobalConfig().
 | ||||
|                 yield this.git.config('include.path', credentialsConfigPath, true); | ||||
|             } | ||||
|             else { | ||||
|                 // For local config, use includeIf.gitdir to match the .git directory.
 | ||||
|                 // Configure for both host and container paths to support Docker container actions.
 | ||||
|                 const gitDir = path.join(this.git.getWorkingDirectory(), '.git'); | ||||
|                 const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`; | ||||
|                 yield this.git.config(hostIncludeKey, credentialsConfigPath); | ||||
|                 this.credentialsIncludeKeys.push(hostIncludeKey); | ||||
|                 // Configure for container scenario where paths are mapped to fixed locations
 | ||||
|                 const githubWorkspace = process.env['GITHUB_WORKSPACE']; | ||||
|                 if (githubWorkspace) { | ||||
|                     // Calculate the relative path of the working directory from GITHUB_WORKSPACE
 | ||||
|                     const workingDirectory = this.git.getWorkingDirectory(); | ||||
|                     const relativePath = path.relative(githubWorkspace, workingDirectory); | ||||
|                     // Container paths: GITHUB_WORKSPACE -> /github/workspace, RUNNER_TEMP -> /github/runner_temp
 | ||||
|                     const containerGitDir = path.posix.join('/github/workspace', relativePath, '.git'); | ||||
|                     const containerCredentialsPath = path.posix.join('/github/runner_temp', path.basename(credentialsConfigPath)); | ||||
|                     const containerIncludeKey = `includeIf.gitdir:${containerGitDir}.path`; | ||||
|                     yield this.git.config(containerIncludeKey, containerCredentialsPath); | ||||
|                     this.credentialsIncludeKeys.push(containerIncludeKey); | ||||
|                 } | ||||
|             } | ||||
|             // Configure a placeholder value. This approach avoids the credential being captured
 | ||||
|             // by process creation audit events, which are commonly logged. For more information,
 | ||||
|             // refer to https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
 | ||||
|             yield this.git.config(this.tokenConfigKey, this.tokenPlaceholderConfigValue, globalConfig); | ||||
|             // Replace the placeholder
 | ||||
|             yield this.replaceTokenPlaceholder(configPath || ''); | ||||
|         }); | ||||
|     } | ||||
|     replaceTokenPlaceholder(configPath) { | ||||
| @@ -411,8 +452,24 @@ class GitAuthHelper { | ||||
|     } | ||||
|     removeToken() { | ||||
|         return __awaiter(this, void 0, void 0, function* () { | ||||
|             var _a; | ||||
|             // HTTP extra header
 | ||||
|             yield this.removeGitConfig(this.tokenConfigKey); | ||||
|             // Remove include/includeIf config entries
 | ||||
|             for (const includeKey of this.credentialsIncludeKeys) { | ||||
|                 yield this.removeGitConfig(includeKey); | ||||
|             } | ||||
|             this.credentialsIncludeKeys = []; | ||||
|             // Remove credentials config file
 | ||||
|             if (this.credentialsConfigPath) { | ||||
|                 try { | ||||
|                     yield io.rmRF(this.credentialsConfigPath); | ||||
|                 } | ||||
|                 catch (err) { | ||||
|                     core.debug(`${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`); | ||||
|                     core.warning(`Failed to remove credentials config '${this.credentialsConfigPath}'`); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|     removeGitConfig(configKey_1) { | ||||
| @@ -627,9 +684,15 @@ class GitCommandManager { | ||||
|             yield this.execGit(args); | ||||
|         }); | ||||
|     } | ||||
|     config(configKey, configValue, globalConfig, add) { | ||||
|     config(configKey, configValue, globalConfig, add, configFile) { | ||||
|         return __awaiter(this, void 0, void 0, function* () { | ||||
|             const args = ['config', globalConfig ? '--global' : '--local']; | ||||
|             const args = ['config']; | ||||
|             if (configFile) { | ||||
|                 args.push('--file', configFile); | ||||
|             } | ||||
|             else { | ||||
|                 args.push(globalConfig ? '--global' : '--local'); | ||||
|             } | ||||
|             if (add) { | ||||
|                 args.push('--add'); | ||||
|             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user