Enforce safe directory (#762)

* set safe directory when running checkout

* Update CHANGELOG.md
This commit is contained in:
Thomas Boop 2022-04-14 14:13:20 -04:00 committed by GitHub
parent add3486cc3
commit dcd71f6466
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 244 additions and 169 deletions

View file

@ -1,5 +1,9 @@
# Changelog # Changelog
## v3.0.1
- [Fixed an issue where checkout failed to run in container jobs due to the new git setting `safe.directory`](https://github.com/actions/checkout/pull/762)
- [Bumped various npm package versions](https://github.com/actions/checkout/pull/744)
## v3.0.0 ## v3.0.0
- [Update to node 16](https://github.com/actions/checkout/pull/689) - [Update to node 16](https://github.com/actions/checkout/pull/689)

View file

@ -643,10 +643,11 @@ describe('git-auth-helper tests', () => {
expect(gitConfigContent.indexOf('http.')).toBeLessThan(0) expect(gitConfigContent.indexOf('http.')).toBeLessThan(0)
}) })
const removeGlobalAuth_removesOverride = 'removeGlobalAuth removes override' const removeGlobalConfig_removesOverride =
it(removeGlobalAuth_removesOverride, async () => { 'removeGlobalConfig removes override'
it(removeGlobalConfig_removesOverride, async () => {
// Arrange // Arrange
await setup(removeGlobalAuth_removesOverride) await setup(removeGlobalConfig_removesOverride)
const authHelper = gitAuthHelper.createAuthHelper(git, settings) const authHelper = gitAuthHelper.createAuthHelper(git, settings)
await authHelper.configureAuth() await authHelper.configureAuth()
await authHelper.configureGlobalAuth() await authHelper.configureGlobalAuth()
@ -655,7 +656,7 @@ describe('git-auth-helper tests', () => {
await fs.promises.stat(path.join(git.env['HOME'], '.gitconfig')) await fs.promises.stat(path.join(git.env['HOME'], '.gitconfig'))
// Act // Act
await authHelper.removeGlobalAuth() await authHelper.removeGlobalConfig()
// Assert // Assert
expect(git.env['HOME']).toBeUndefined() expect(git.env['HOME']).toBeUndefined()

59
dist/index.js vendored
View file

@ -6572,9 +6572,13 @@ class GitAuthHelper {
yield this.configureToken(); yield this.configureToken();
}); });
} }
configureGlobalAuth() { configureTempGlobalConfig(repositoryPath) {
var _a; var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Already setup global config
if (((_a = this.temporaryHomePath) === null || _a === void 0 ? void 0 : _a.length) > 0) {
return path.join(this.temporaryHomePath, '.gitconfig');
}
// Create a temp home directory // Create a temp home directory
const runnerTemp = process.env['RUNNER_TEMP'] || ''; const runnerTemp = process.env['RUNNER_TEMP'] || '';
assert.ok(runnerTemp, 'RUNNER_TEMP is not defined'); assert.ok(runnerTemp, 'RUNNER_TEMP is not defined');
@ -6590,7 +6594,7 @@ class GitAuthHelper {
configExists = true; configExists = true;
} }
catch (err) { catch (err) {
if (((_a = err) === null || _a === void 0 ? void 0 : _a.code) !== 'ENOENT') { if (((_b = err) === null || _b === void 0 ? void 0 : _b.code) !== 'ENOENT') {
throw err; throw err;
} }
} }
@ -6601,10 +6605,25 @@ class GitAuthHelper {
else { else {
yield fs.promises.writeFile(newGitConfigPath, ''); yield fs.promises.writeFile(newGitConfigPath, '');
} }
try {
// Override HOME // Override HOME
core.info(`Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes`); core.info(`Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes`);
this.git.setEnvironmentVariable('HOME', this.temporaryHomePath); this.git.setEnvironmentVariable('HOME', this.temporaryHomePath);
// Setup the workspace as a safe directory, so if we pass this into a container job with a different user it doesn't fail
// Otherwise all git commands we run in a container fail
core.info(`Adding working directory to the temporary git global config as a safe directory`);
yield this.git
.config('safe.directory', repositoryPath !== null && repositoryPath !== void 0 ? repositoryPath : this.settings.repositoryPath, true, true)
.catch(error => {
core.info(`Failed to initialize safe directory with error: ${error}`);
});
return newGitConfigPath;
});
}
configureGlobalAuth() {
return __awaiter(this, void 0, void 0, function* () {
// 'configureTempGlobalConfig' noops if already set, just returns the path
const newGitConfigPath = yield this.configureTempGlobalConfig();
try {
// Configure the token // Configure the token
yield this.configureToken(newGitConfigPath, true); yield this.configureToken(newGitConfigPath, true);
// Configure HTTPS instead of SSH // Configure HTTPS instead of SSH
@ -6657,11 +6676,14 @@ class GitAuthHelper {
yield this.removeToken(); yield this.removeToken();
}); });
} }
removeGlobalAuth() { removeGlobalConfig() {
var _a;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (((_a = this.temporaryHomePath) === null || _a === void 0 ? void 0 : _a.length) > 0) {
core.debug(`Unsetting HOME override`); core.debug(`Unsetting HOME override`);
this.git.removeEnvironmentVariable('HOME'); this.git.removeEnvironmentVariable('HOME');
yield io.rmRF(this.temporaryHomePath); yield io.rmRF(this.temporaryHomePath);
}
}); });
} }
configureSsh() { configureSsh() {
@ -7326,6 +7348,12 @@ function getSource(settings) {
core.startGroup('Getting Git version info'); core.startGroup('Getting Git version info');
const git = yield getGitCommandManager(settings); const git = yield getGitCommandManager(settings);
core.endGroup(); core.endGroup();
let authHelper = null;
try {
if (git) {
authHelper = gitAuthHelper.createAuthHelper(git, settings);
yield authHelper.configureTempGlobalConfig();
}
// Prepare existing directory, otherwise recreate // Prepare existing directory, otherwise recreate
if (isExisting) { if (isExisting) {
yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean, settings.ref); yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean, settings.ref);
@ -7358,8 +7386,10 @@ function getSource(settings) {
core.warning(`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`); core.warning(`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`);
} }
core.endGroup(); core.endGroup();
const authHelper = gitAuthHelper.createAuthHelper(git, settings); // If we didn't initialize it above, do it now
try { if (!authHelper) {
authHelper = gitAuthHelper.createAuthHelper(git, settings);
}
// Configure auth // Configure auth
core.startGroup('Setting up auth'); core.startGroup('Setting up auth');
yield authHelper.configureAuth(); yield authHelper.configureAuth();
@ -7415,7 +7445,6 @@ function getSource(settings) {
core.endGroup(); core.endGroup();
// Submodules // Submodules
if (settings.submodules) { if (settings.submodules) {
try {
// Temporarily override global config // Temporarily override global config
core.startGroup('Setting up auth for fetching submodules'); core.startGroup('Setting up auth for fetching submodules');
yield authHelper.configureGlobalAuth(); yield authHelper.configureGlobalAuth();
@ -7433,11 +7462,6 @@ function getSource(settings) {
core.endGroup(); core.endGroup();
} }
} }
finally {
// Remove temporary global config override
yield authHelper.removeGlobalAuth();
}
}
// Get commit information // Get commit information
const commitInfo = yield git.log1(); const commitInfo = yield git.log1();
// Log commit sha // Log commit sha
@ -7447,11 +7471,14 @@ function getSource(settings) {
} }
finally { finally {
// Remove auth // Remove auth
if (authHelper) {
if (!settings.persistCredentials) { if (!settings.persistCredentials) {
core.startGroup('Removing auth'); core.startGroup('Removing auth');
yield authHelper.removeAuth(); yield authHelper.removeAuth();
core.endGroup(); core.endGroup();
} }
authHelper.removeGlobalConfig();
}
} }
}); });
} }
@ -7472,7 +7499,13 @@ function cleanup(repositoryPath) {
} }
// Remove auth // Remove auth
const authHelper = gitAuthHelper.createAuthHelper(git); const authHelper = gitAuthHelper.createAuthHelper(git);
try {
yield authHelper.configureTempGlobalConfig(repositoryPath);
yield authHelper.removeAuth(); yield authHelper.removeAuth();
}
finally {
yield authHelper.removeGlobalConfig();
}
}); });
} }
exports.cleanup = cleanup; exports.cleanup = cleanup;

View file

@ -19,8 +19,9 @@ export interface IGitAuthHelper {
configureAuth(): Promise<void> configureAuth(): Promise<void>
configureGlobalAuth(): Promise<void> configureGlobalAuth(): Promise<void>
configureSubmoduleAuth(): Promise<void> configureSubmoduleAuth(): Promise<void>
configureTempGlobalConfig(repositoryPath?: string): Promise<string>
removeAuth(): Promise<void> removeAuth(): Promise<void>
removeGlobalAuth(): Promise<void> removeGlobalConfig(): Promise<void>
} }
export function createAuthHelper( export function createAuthHelper(
@ -80,7 +81,11 @@ class GitAuthHelper {
await this.configureToken() await this.configureToken()
} }
async configureGlobalAuth(): Promise<void> { async configureTempGlobalConfig(repositoryPath?: string): Promise<string> {
// Already setup global config
if (this.temporaryHomePath?.length > 0) {
return path.join(this.temporaryHomePath, '.gitconfig')
}
// Create a temp home directory // Create a temp home directory
const runnerTemp = process.env['RUNNER_TEMP'] || '' const runnerTemp = process.env['RUNNER_TEMP'] || ''
assert.ok(runnerTemp, 'RUNNER_TEMP is not defined') assert.ok(runnerTemp, 'RUNNER_TEMP is not defined')
@ -110,13 +115,34 @@ class GitAuthHelper {
await fs.promises.writeFile(newGitConfigPath, '') await fs.promises.writeFile(newGitConfigPath, '')
} }
try {
// Override HOME // Override HOME
core.info( core.info(
`Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes` `Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes`
) )
this.git.setEnvironmentVariable('HOME', this.temporaryHomePath) this.git.setEnvironmentVariable('HOME', this.temporaryHomePath)
// Setup the workspace as a safe directory, so if we pass this into a container job with a different user it doesn't fail
// Otherwise all git commands we run in a container fail
core.info(
`Adding working directory to the temporary git global config as a safe directory`
)
await this.git
.config(
'safe.directory',
repositoryPath ?? this.settings.repositoryPath,
true,
true
)
.catch(error => {
core.info(`Failed to initialize safe directory with error: ${error}`)
})
return newGitConfigPath
}
async configureGlobalAuth(): Promise<void> {
// 'configureTempGlobalConfig' noops if already set, just returns the path
const newGitConfigPath = await this.configureTempGlobalConfig()
try {
// Configure the token // Configure the token
await this.configureToken(newGitConfigPath, true) await this.configureToken(newGitConfigPath, true)
@ -181,11 +207,13 @@ class GitAuthHelper {
await this.removeToken() await this.removeToken()
} }
async removeGlobalAuth(): Promise<void> { async removeGlobalConfig(): Promise<void> {
if (this.temporaryHomePath?.length > 0) {
core.debug(`Unsetting HOME override`) core.debug(`Unsetting HOME override`)
this.git.removeEnvironmentVariable('HOME') this.git.removeEnvironmentVariable('HOME')
await io.rmRF(this.temporaryHomePath) await io.rmRF(this.temporaryHomePath)
} }
}
private async configureSsh(): Promise<void> { private async configureSsh(): Promise<void> {
if (!this.settings.sshKey) { if (!this.settings.sshKey) {

View file

@ -36,6 +36,13 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
const git = await getGitCommandManager(settings) const git = await getGitCommandManager(settings)
core.endGroup() core.endGroup()
let authHelper: gitAuthHelper.IGitAuthHelper | null = null
try {
if (git) {
authHelper = gitAuthHelper.createAuthHelper(git, settings)
await authHelper.configureTempGlobalConfig()
}
// Prepare existing directory, otherwise recreate // Prepare existing directory, otherwise recreate
if (isExisting) { if (isExisting) {
await gitDirectoryHelper.prepareExistingDirectory( await gitDirectoryHelper.prepareExistingDirectory(
@ -96,8 +103,10 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
} }
core.endGroup() core.endGroup()
const authHelper = gitAuthHelper.createAuthHelper(git, settings) // If we didn't initialize it above, do it now
try { if (!authHelper) {
authHelper = gitAuthHelper.createAuthHelper(git, settings)
}
// Configure auth // Configure auth
core.startGroup('Setting up auth') core.startGroup('Setting up auth')
await authHelper.configureAuth() await authHelper.configureAuth()
@ -170,7 +179,6 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Submodules // Submodules
if (settings.submodules) { if (settings.submodules) {
try {
// Temporarily override global config // Temporarily override global config
core.startGroup('Setting up auth for fetching submodules') core.startGroup('Setting up auth for fetching submodules')
await authHelper.configureGlobalAuth() await authHelper.configureGlobalAuth()
@ -179,10 +187,7 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Checkout submodules // Checkout submodules
core.startGroup('Fetching submodules') core.startGroup('Fetching submodules')
await git.submoduleSync(settings.nestedSubmodules) await git.submoduleSync(settings.nestedSubmodules)
await git.submoduleUpdate( await git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules)
settings.fetchDepth,
settings.nestedSubmodules
)
await git.submoduleForeach( await git.submoduleForeach(
'git config --local gc.auto 0', 'git config --local gc.auto 0',
settings.nestedSubmodules settings.nestedSubmodules
@ -195,10 +200,6 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
await authHelper.configureSubmoduleAuth() await authHelper.configureSubmoduleAuth()
core.endGroup() core.endGroup()
} }
} finally {
// Remove temporary global config override
await authHelper.removeGlobalAuth()
}
} }
// Get commit information // Get commit information
@ -218,11 +219,14 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
) )
} finally { } finally {
// Remove auth // Remove auth
if (authHelper) {
if (!settings.persistCredentials) { if (!settings.persistCredentials) {
core.startGroup('Removing auth') core.startGroup('Removing auth')
await authHelper.removeAuth() await authHelper.removeAuth()
core.endGroup() core.endGroup()
} }
authHelper.removeGlobalConfig()
}
} }
} }
@ -244,7 +248,12 @@ export async function cleanup(repositoryPath: string): Promise<void> {
// Remove auth // Remove auth
const authHelper = gitAuthHelper.createAuthHelper(git) const authHelper = gitAuthHelper.createAuthHelper(git)
try {
await authHelper.configureTempGlobalConfig(repositoryPath)
await authHelper.removeAuth() await authHelper.removeAuth()
} finally {
await authHelper.removeGlobalConfig()
}
} }
async function getGitCommandManager( async function getGitCommandManager(