Skip to content

Commit f67ee5d

Browse files
authored
Add set-safe-directory input to allow customers to take control. (#770) (#776)
* Add set-safe-directory input to allow customers to take control.
1 parent f25a3a9 commit f67ee5d

11 files changed

+144
-32
lines changed

.github/workflows/test.yml

+38
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,41 @@ jobs:
205205
path: basic
206206
- name: Verify basic
207207
run: __test__/verify-basic.sh --archive
208+
209+
test-git-container:
210+
runs-on: ubuntu-latest
211+
container: bitnami/git:latest
212+
steps:
213+
# Clone this repo
214+
- name: Checkout
215+
uses: actions/checkout@v3
216+
with:
217+
path: v3
218+
219+
# Basic checkout using git
220+
- name: Checkout basic
221+
uses: ./v3
222+
with:
223+
ref: test-data/v2/basic
224+
- name: Verify basic
225+
run: |
226+
if [ ! -f "./basic-file.txt" ]; then
227+
echo "Expected basic file does not exist"
228+
exit 1
229+
fi
230+
231+
# Verify .git folder
232+
if [ ! -d "./.git" ]; then
233+
echo "Expected ./.git folder to exist"
234+
exit 1
235+
fi
236+
237+
# Verify auth token
238+
git config --global --add safe.directory "*"
239+
git fetch --no-tags --depth=1 origin +refs/heads/main:refs/remotes/origin/main
240+
241+
# needed to make checkout post cleanup succeed
242+
- name: Fix Checkout v3
243+
uses: actions/checkout@v3
244+
with:
245+
path: v3

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
105105
#
106106
# Default: false
107107
submodules: ''
108+
109+
# Add repository path as safe.directory for Git global config by running `git
110+
# config --global --add safe.directory <path>`
111+
# Default: true
112+
set-safe-directory: ''
108113
```
109114
<!-- end usage -->
110115

__test__/git-auth-helper.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,8 @@ async function setup(testName: string): Promise<void> {
777777
sshKey: sshPath ? 'some ssh private key' : '',
778778
sshKnownHosts: '',
779779
sshStrict: true,
780-
workflowOrganizationId: 123456
780+
workflowOrganizationId: 123456,
781+
setSafeDirectory: true
781782
}
782783
}
783784

__test__/input-helper.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ describe('input-helper tests', () => {
8585
expect(settings.repositoryName).toBe('some-repo')
8686
expect(settings.repositoryOwner).toBe('some-owner')
8787
expect(settings.repositoryPath).toBe(gitHubWorkspace)
88+
expect(settings.setSafeDirectory).toBe(true)
8889
})
8990

9091
it('qualifies ref', async () => {

action.yml

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ inputs:
6868
When the `ssh-key` input is not provided, SSH URLs beginning with `[email protected]:` are
6969
converted to HTTPS.
7070
default: false
71+
set-safe-directory:
72+
description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory <path>`
73+
default: true
7174
runs:
7275
using: node12
7376
main: dist/index.js

dist/index.js

+39-12
Original file line numberDiff line numberDiff line change
@@ -3592,7 +3592,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
35923592
return result;
35933593
};
35943594
Object.defineProperty(exports, "__esModule", { value: true });
3595-
exports.setSshKnownHostsPath = exports.setSshKeyPath = exports.setRepositoryPath = exports.SshKnownHostsPath = exports.SshKeyPath = exports.RepositoryPath = exports.IsPost = void 0;
3595+
exports.setSafeDirectory = exports.setSshKnownHostsPath = exports.setSshKeyPath = exports.setRepositoryPath = exports.SshKnownHostsPath = exports.SshKeyPath = exports.PostSetSafeDirectory = exports.RepositoryPath = exports.IsPost = void 0;
35963596
const coreCommand = __importStar(__webpack_require__(431));
35973597
/**
35983598
* Indicates whether the POST action is running
@@ -3602,6 +3602,10 @@ exports.IsPost = !!process.env['STATE_isPost'];
36023602
* The repository path for the POST action. The value is empty during the MAIN action.
36033603
*/
36043604
exports.RepositoryPath = process.env['STATE_repositoryPath'] || '';
3605+
/**
3606+
* The set-safe-directory for the POST action. The value is set if input: 'safe-directory' is set during the MAIN action.
3607+
*/
3608+
exports.PostSetSafeDirectory = process.env['STATE_setSafeDirectory'] === 'true';
36053609
/**
36063610
* The SSH key path for the POST action. The value is empty during the MAIN action.
36073611
*/
@@ -3631,6 +3635,13 @@ function setSshKnownHostsPath(sshKnownHostsPath) {
36313635
coreCommand.issueCommand('save-state', { name: 'sshKnownHostsPath' }, sshKnownHostsPath);
36323636
}
36333637
exports.setSshKnownHostsPath = setSshKnownHostsPath;
3638+
/**
3639+
* Save the sef-safe-directory input so the POST action can retrieve the value.
3640+
*/
3641+
function setSafeDirectory() {
3642+
coreCommand.issueCommand('save-state', { name: 'setSafeDirectory' }, 'true');
3643+
}
3644+
exports.setSafeDirectory = setSafeDirectory;
36343645
// Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic.
36353646
// This is necessary since we don't have a separate entry point.
36363647
if (!exports.IsPost) {
@@ -6572,7 +6583,7 @@ class GitAuthHelper {
65726583
yield this.configureToken();
65736584
});
65746585
}
6575-
configureTempGlobalConfig(repositoryPath) {
6586+
configureTempGlobalConfig() {
65766587
var _a, _b;
65776588
return __awaiter(this, void 0, void 0, function* () {
65786589
// Already setup global config
@@ -6608,14 +6619,6 @@ class GitAuthHelper {
66086619
// Override HOME
66096620
core.info(`Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes`);
66106621
this.git.setEnvironmentVariable('HOME', this.temporaryHomePath);
6611-
// Setup the workspace as a safe directory, so if we pass this into a container job with a different user it doesn't fail
6612-
// Otherwise all git commands we run in a container fail
6613-
core.info(`Adding working directory to the temporary git global config as a safe directory`);
6614-
yield this.git
6615-
.config('safe.directory', repositoryPath !== null && repositoryPath !== void 0 ? repositoryPath : this.settings.repositoryPath, true, true)
6616-
.catch(error => {
6617-
core.info(`Failed to initialize safe directory with error: ${error}`);
6618-
});
66196622
return newGitConfigPath;
66206623
});
66216624
}
@@ -7352,7 +7355,18 @@ function getSource(settings) {
73527355
try {
73537356
if (git) {
73547357
authHelper = gitAuthHelper.createAuthHelper(git, settings);
7355-
yield authHelper.configureTempGlobalConfig();
7358+
if (settings.setSafeDirectory) {
7359+
// Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
7360+
// Otherwise all git commands we run in a container fail
7361+
yield authHelper.configureTempGlobalConfig();
7362+
core.info(`Adding repository directory to the temporary git global config as a safe directory`);
7363+
yield git
7364+
.config('safe.directory', settings.repositoryPath, true, true)
7365+
.catch(error => {
7366+
core.info(`Failed to initialize safe directory with error: ${error}`);
7367+
});
7368+
stateHelper.setSafeDirectory();
7369+
}
73567370
}
73577371
// Prepare existing directory, otherwise recreate
73587372
if (isExisting) {
@@ -7500,7 +7514,17 @@ function cleanup(repositoryPath) {
75007514
// Remove auth
75017515
const authHelper = gitAuthHelper.createAuthHelper(git);
75027516
try {
7503-
yield authHelper.configureTempGlobalConfig(repositoryPath);
7517+
if (stateHelper.PostSetSafeDirectory) {
7518+
// Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
7519+
// Otherwise all git commands we run in a container fail
7520+
yield authHelper.configureTempGlobalConfig();
7521+
core.info(`Adding repository directory to the temporary git global config as a safe directory`);
7522+
yield git
7523+
.config('safe.directory', repositoryPath, true, true)
7524+
.catch(error => {
7525+
core.info(`Failed to initialize safe directory with error: ${error}`);
7526+
});
7527+
}
75047528
yield authHelper.removeAuth();
75057529
}
75067530
finally {
@@ -17277,6 +17301,9 @@ function getInputs() {
1727717301
(core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE';
1727817302
// Workflow organization ID
1727917303
result.workflowOrganizationId = yield workflowContextHelper.getOrganizationId();
17304+
// Set safe.directory in git global config.
17305+
result.setSafeDirectory =
17306+
(core.getInput('set-safe-directory') || 'true').toUpperCase() === 'TRUE';
1728017307
return result;
1728117308
});
1728217309
}

src/git-auth-helper.ts

+2-17
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface IGitAuthHelper {
1919
configureAuth(): Promise<void>
2020
configureGlobalAuth(): Promise<void>
2121
configureSubmoduleAuth(): Promise<void>
22-
configureTempGlobalConfig(repositoryPath?: string): Promise<string>
22+
configureTempGlobalConfig(): Promise<string>
2323
removeAuth(): Promise<void>
2424
removeGlobalConfig(): Promise<void>
2525
}
@@ -81,7 +81,7 @@ class GitAuthHelper {
8181
await this.configureToken()
8282
}
8383

84-
async configureTempGlobalConfig(repositoryPath?: string): Promise<string> {
84+
async configureTempGlobalConfig(): Promise<string> {
8585
// Already setup global config
8686
if (this.temporaryHomePath?.length > 0) {
8787
return path.join(this.temporaryHomePath, '.gitconfig')
@@ -121,21 +121,6 @@ class GitAuthHelper {
121121
)
122122
this.git.setEnvironmentVariable('HOME', this.temporaryHomePath)
123123

124-
// Setup the workspace as a safe directory, so if we pass this into a container job with a different user it doesn't fail
125-
// Otherwise all git commands we run in a container fail
126-
core.info(
127-
`Adding working directory to the temporary git global config as a safe directory`
128-
)
129-
await this.git
130-
.config(
131-
'safe.directory',
132-
repositoryPath ?? this.settings.repositoryPath,
133-
true,
134-
true
135-
)
136-
.catch(error => {
137-
core.info(`Failed to initialize safe directory with error: ${error}`)
138-
})
139124
return newGitConfigPath
140125
}
141126

src/git-source-provider.ts

+33-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,24 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
4040
try {
4141
if (git) {
4242
authHelper = gitAuthHelper.createAuthHelper(git, settings)
43-
await authHelper.configureTempGlobalConfig()
43+
if (settings.setSafeDirectory) {
44+
// Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
45+
// Otherwise all git commands we run in a container fail
46+
await authHelper.configureTempGlobalConfig()
47+
core.info(
48+
`Adding repository directory to the temporary git global config as a safe directory`
49+
)
50+
51+
await git
52+
.config('safe.directory', settings.repositoryPath, true, true)
53+
.catch(error => {
54+
core.info(
55+
`Failed to initialize safe directory with error: ${error}`
56+
)
57+
})
58+
59+
stateHelper.setSafeDirectory()
60+
}
4461
}
4562

4663
// Prepare existing directory, otherwise recreate
@@ -249,7 +266,21 @@ export async function cleanup(repositoryPath: string): Promise<void> {
249266
// Remove auth
250267
const authHelper = gitAuthHelper.createAuthHelper(git)
251268
try {
252-
await authHelper.configureTempGlobalConfig(repositoryPath)
269+
if (stateHelper.PostSetSafeDirectory) {
270+
// Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
271+
// Otherwise all git commands we run in a container fail
272+
await authHelper.configureTempGlobalConfig()
273+
core.info(
274+
`Adding repository directory to the temporary git global config as a safe directory`
275+
)
276+
277+
await git
278+
.config('safe.directory', repositoryPath, true, true)
279+
.catch(error => {
280+
core.info(`Failed to initialize safe directory with error: ${error}`)
281+
})
282+
}
283+
253284
await authHelper.removeAuth()
254285
} finally {
255286
await authHelper.removeGlobalConfig()

src/git-source-settings.ts

+5
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,9 @@ export interface IGitSourceSettings {
7878
* Organization ID for the currently running workflow (used for auth settings)
7979
*/
8080
workflowOrganizationId: number | undefined
81+
82+
/**
83+
* Indicates whether to add repositoryPath as safe.directory in git global config
84+
*/
85+
setSafeDirectory: boolean
8186
}

src/input-helper.ts

+3
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,8 @@ export async function getInputs(): Promise<IGitSourceSettings> {
122122
// Workflow organization ID
123123
result.workflowOrganizationId = await workflowContextHelper.getOrganizationId()
124124

125+
// Set safe.directory in git global config.
126+
result.setSafeDirectory =
127+
(core.getInput('set-safe-directory') || 'true').toUpperCase() === 'TRUE'
125128
return result
126129
}

src/state-helper.ts

+13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ export const IsPost = !!process.env['STATE_isPost']
1111
export const RepositoryPath =
1212
(process.env['STATE_repositoryPath'] as string) || ''
1313

14+
/**
15+
* The set-safe-directory for the POST action. The value is set if input: 'safe-directory' is set during the MAIN action.
16+
*/
17+
export const PostSetSafeDirectory =
18+
(process.env['STATE_setSafeDirectory'] as string) === 'true'
19+
1420
/**
1521
* The SSH key path for the POST action. The value is empty during the MAIN action.
1622
*/
@@ -51,6 +57,13 @@ export function setSshKnownHostsPath(sshKnownHostsPath: string) {
5157
)
5258
}
5359

60+
/**
61+
* Save the sef-safe-directory input so the POST action can retrieve the value.
62+
*/
63+
export function setSafeDirectory() {
64+
coreCommand.issueCommand('save-state', {name: 'setSafeDirectory'}, 'true')
65+
}
66+
5467
// Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic.
5568
// This is necessary since we don't have a separate entry point.
5669
if (!IsPost) {

0 commit comments

Comments
 (0)