Skip to content

Commit c170eef

Browse files
authored
add input persist-credentials (#107)
1 parent a572f64 commit c170eef

File tree

9 files changed

+146
-125
lines changed

9 files changed

+146
-125
lines changed

Diff for: .github/workflows/test.yml

+4-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
- run: npm run lint
1919
- run: npm run pack
2020
- run: npm run gendocs
21+
- run: npm test
2122
- name: Verify no unstaged changes
2223
run: __test__/verify-no-unstaged-changes.sh
2324

@@ -84,15 +85,12 @@ jobs:
8485

8586
test-job-container:
8687
runs-on: ubuntu-latest
87-
container: pstauffer/curl:latest
88+
container: alpine:latest
8889
steps:
8990
# Clone this repo
90-
# todo: after v2-beta contains the latest changes, switch this to "uses: actions/checkout@v2-beta". Also switch to "alpine:latest"
91+
# todo: after v2-beta contains the latest changes, switch this to "uses: actions/checkout@v2-beta"
9192
- name: Checkout
92-
run: |
93-
curl --location --user token:${{ github.token }} --output checkout.tar.gz https://api.github.com/repos/actions/checkout/tarball/${{ github.sha }}
94-
tar -xzf checkout.tar.gz
95-
mv */* ./
93+
uses: actions/checkout@a572f640b07e96fc5837b3adfa0e5a2ddd8dae21
9694

9795
# Basic checkout
9896
- name: Basic checkout

Diff for: README.md

+12-6
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ Refer [here](https://help.github.com/en/articles/events-that-trigger-workflows)
1515
- Improved fetch performance
1616
- The default behavior now fetches only the commit being checked-out
1717
- Script authenticated git commands
18-
- Persists `with.token` in the local git config
18+
- Persists the input `token` in the local git config
1919
- Enables your scripts to run authenticated git commands
2020
- Post-job cleanup removes the token
21-
- Coming soon: Opt out by setting `with.persist-credentials` to `false`
21+
- Opt out by setting the input `persist-credentials: false`
2222
- Creates a local branch
2323
- No longer detached HEAD when checking out a branch
2424
- A local branch is created with the corresponding upstream branch set
2525
- Improved layout
26-
- `with.path` is always relative to `github.workspace`
27-
- Aligns better with container actions, where `github.workspace` gets mapped in
26+
- The input `path` is always relative to $GITHUB_WORKSPACE
27+
- Aligns better with container actions, where $GITHUB_WORKSPACE gets mapped in
2828
- Fallback to REST API download
2929
- When Git 2.18 or higher is not in the PATH, the REST API will be used to download the files
3030
- Removed input `submodules`
@@ -41,15 +41,21 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
4141
# Default: ${{ github.repository }}
4242
repository: ''
4343

44-
# The branch, tag or SHA to checkout. When checking out the repository that
44+
# The branch, tag or SHA to checkout. When checking out the repository that
4545
# triggered a workflow, this defaults to the reference or SHA for that event.
4646
# Otherwise, defaults to `master`.
4747
ref: ''
4848

49-
# Access token for clone repository
49+
# Auth token used to fetch the repository. The token is stored in the local git
50+
# config, which enables your scripts to run authenticated git commands. The
51+
# post-job step removes the token from the git config.
5052
# Default: ${{ github.token }}
5153
token: ''
5254

55+
# Whether to persist the token in the git config
56+
# Default: true
57+
persist-credentials: ''
58+
5359
# Relative path under $GITHUB_WORKSPACE to place the repository
5460
path: ''
5561

Diff for: __test__/input-helper.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('input-helper tests', () => {
6363
it('sets defaults', () => {
6464
const settings: ISourceSettings = inputHelper.getInputs()
6565
expect(settings).toBeTruthy()
66-
expect(settings.accessToken).toBeFalsy()
66+
expect(settings.authToken).toBeFalsy()
6767
expect(settings.clean).toBe(true)
6868
expect(settings.commit).toBeTruthy()
6969
expect(settings.commit).toBe('1234567890123456789012345678901234567890')

Diff for: action.yml

+10-4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@ inputs:
66
default: ${{ github.repository }}
77
ref:
88
description: >
9-
The branch, tag or SHA to checkout. When checking out the repository
10-
that triggered a workflow, this defaults to the reference or SHA for
11-
that event. Otherwise, defaults to `master`.
9+
The branch, tag or SHA to checkout. When checking out the repository that
10+
triggered a workflow, this defaults to the reference or SHA for that
11+
event. Otherwise, defaults to `master`.
1212
token:
13-
description: 'Access token for clone repository'
13+
description: >
14+
Auth token used to fetch the repository. The token is stored in the local
15+
git config, which enables your scripts to run authenticated git commands.
16+
The post-job step removes the token from the git config.
1417
default: ${{ github.token }}
18+
persist-credentials:
19+
description: 'Whether to persist the token in the git config'
20+
default: true
1521
path:
1622
description: 'Relative path under $GITHUB_WORKSPACE to place the repository'
1723
clean:

Diff for: dist/index.js

+52-47
Original file line numberDiff line numberDiff line change
@@ -4838,15 +4838,15 @@ class GitCommandManager {
48384838
}
48394839
config(configKey, configValue) {
48404840
return __awaiter(this, void 0, void 0, function* () {
4841-
yield this.execGit(['config', configKey, configValue]);
4841+
yield this.execGit(['config', '--local', configKey, configValue]);
48424842
});
48434843
}
48444844
configExists(configKey) {
48454845
return __awaiter(this, void 0, void 0, function* () {
48464846
const pattern = configKey.replace(/[^a-zA-Z0-9_]/g, x => {
48474847
return `\\${x}`;
48484848
});
4849-
const output = yield this.execGit(['config', '--name-only', '--get-regexp', pattern], true);
4849+
const output = yield this.execGit(['config', '--local', '--name-only', '--get-regexp', pattern], true);
48504850
return output.exitCode === 0;
48514851
});
48524852
}
@@ -4932,19 +4932,19 @@ class GitCommandManager {
49324932
}
49334933
tryConfigUnset(configKey) {
49344934
return __awaiter(this, void 0, void 0, function* () {
4935-
const output = yield this.execGit(['config', '--unset-all', configKey], true);
4935+
const output = yield this.execGit(['config', '--local', '--unset-all', configKey], true);
49364936
return output.exitCode === 0;
49374937
});
49384938
}
49394939
tryDisableAutomaticGarbageCollection() {
49404940
return __awaiter(this, void 0, void 0, function* () {
4941-
const output = yield this.execGit(['config', 'gc.auto', '0'], true);
4941+
const output = yield this.execGit(['config', '--local', 'gc.auto', '0'], true);
49424942
return output.exitCode === 0;
49434943
});
49444944
}
49454945
tryGetFetchUrl() {
49464946
return __awaiter(this, void 0, void 0, function* () {
4947-
const output = yield this.execGit(['config', '--get', 'remote.origin.url'], true);
4947+
const output = yield this.execGit(['config', '--local', '--get', 'remote.origin.url'], true);
49484948
if (output.exitCode !== 0) {
49494949
return '';
49504950
}
@@ -5121,7 +5121,7 @@ function getSource(settings) {
51215121
// Downloading using REST API
51225122
core.info(`The repository will be downloaded using the GitHub REST API`);
51235123
core.info(`To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH`);
5124-
yield githubApiHelper.downloadRepository(settings.accessToken, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.repositoryPath);
5124+
yield githubApiHelper.downloadRepository(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.repositoryPath);
51255125
}
51265126
else {
51275127
// Save state for POST action
@@ -5137,30 +5137,34 @@ function getSource(settings) {
51375137
}
51385138
// Remove possible previous extraheader
51395139
yield removeGitConfig(git, authConfigKey);
5140-
// Add extraheader (auth)
5141-
const base64Credentials = Buffer.from(`x-access-token:${settings.accessToken}`, 'utf8').toString('base64');
5142-
core.setSecret(base64Credentials);
5143-
const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`;
5144-
yield git.config(authConfigKey, authConfigValue);
5145-
// LFS install
5146-
if (settings.lfs) {
5147-
yield git.lfsInstall();
5148-
}
5149-
// Fetch
5150-
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
5151-
yield git.fetch(settings.fetchDepth, refSpec);
5152-
// Checkout info
5153-
const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
5154-
// LFS fetch
5155-
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
5156-
// Explicit lfs fetch will fetch lfs objects in parallel.
5157-
if (settings.lfs) {
5158-
yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
5140+
try {
5141+
// Config auth token
5142+
yield configureAuthToken(git, settings.authToken);
5143+
// LFS install
5144+
if (settings.lfs) {
5145+
yield git.lfsInstall();
5146+
}
5147+
// Fetch
5148+
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
5149+
yield git.fetch(settings.fetchDepth, refSpec);
5150+
// Checkout info
5151+
const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
5152+
// LFS fetch
5153+
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
5154+
// Explicit lfs fetch will fetch lfs objects in parallel.
5155+
if (settings.lfs) {
5156+
yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
5157+
}
5158+
// Checkout
5159+
yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
5160+
// Dump some info about the checked out commit
5161+
yield git.log1();
5162+
}
5163+
finally {
5164+
if (!settings.persistCredentials) {
5165+
yield removeGitConfig(git, authConfigKey);
5166+
}
51595167
}
5160-
// Checkout
5161-
yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
5162-
// Dump some info about the checked out commit
5163-
yield git.log1();
51645168
}
51655169
});
51665170
}
@@ -5265,23 +5269,21 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
52655269
}
52665270
});
52675271
}
5272+
function configureAuthToken(git, authToken) {
5273+
return __awaiter(this, void 0, void 0, function* () {
5274+
// Add extraheader (auth)
5275+
const base64Credentials = Buffer.from(`x-access-token:${authToken}`, 'utf8').toString('base64');
5276+
core.setSecret(base64Credentials);
5277+
const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`;
5278+
yield git.config(authConfigKey, authConfigValue);
5279+
});
5280+
}
52685281
function removeGitConfig(git, configKey) {
52695282
return __awaiter(this, void 0, void 0, function* () {
52705283
if ((yield git.configExists(configKey)) &&
52715284
!(yield git.tryConfigUnset(configKey))) {
52725285
// Load the config contents
5273-
core.warning(`Failed to remove '${configKey}' from the git config. Attempting to remove the config value by editing the file directly.`);
5274-
const configPath = path.join(git.getWorkingDirectory(), '.git', 'config');
5275-
fsHelper.fileExistsSync(configPath);
5276-
let contents = fs.readFileSync(configPath).toString() || '';
5277-
// Filter - only includes lines that do not contain the config key
5278-
const upperConfigKey = configKey.toUpperCase();
5279-
const split = contents
5280-
.split('\n')
5281-
.filter(x => !x.toUpperCase().includes(upperConfigKey));
5282-
contents = split.join('\n');
5283-
// Rewrite the config file
5284-
fs.writeFileSync(configPath, contents);
5286+
core.warning(`Failed to remove '${configKey}' from the git config`);
52855287
}
52865288
});
52875289
}
@@ -8403,12 +8405,12 @@ const retryHelper = __importStar(__webpack_require__(587));
84038405
const toolCache = __importStar(__webpack_require__(533));
84048406
const v4_1 = __importDefault(__webpack_require__(826));
84058407
const IS_WINDOWS = process.platform === 'win32';
8406-
function downloadRepository(accessToken, owner, repo, ref, commit, repositoryPath) {
8408+
function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath) {
84078409
return __awaiter(this, void 0, void 0, function* () {
84088410
// Download the archive
84098411
let archiveData = yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
84108412
core.info('Downloading the archive');
8411-
return yield downloadArchive(accessToken, owner, repo, ref, commit);
8413+
return yield downloadArchive(authToken, owner, repo, ref, commit);
84128414
}));
84138415
// Write archive to disk
84148416
core.info('Writing archive to disk');
@@ -8449,9 +8451,9 @@ function downloadRepository(accessToken, owner, repo, ref, commit, repositoryPat
84498451
});
84508452
}
84518453
exports.downloadRepository = downloadRepository;
8452-
function downloadArchive(accessToken, owner, repo, ref, commit) {
8454+
function downloadArchive(authToken, owner, repo, ref, commit) {
84538455
return __awaiter(this, void 0, void 0, function* () {
8454-
const octokit = new github.GitHub(accessToken);
8456+
const octokit = new github.GitHub(authToken);
84558457
const params = {
84568458
owner: owner,
84578459
repo: repo,
@@ -12764,8 +12766,11 @@ function getInputs() {
1276412766
// LFS
1276512767
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE';
1276612768
core.debug(`lfs = ${result.lfs}`);
12767-
// Access token
12768-
result.accessToken = core.getInput('token');
12769+
// Auth token
12770+
result.authToken = core.getInput('token');
12771+
// Persist credentials
12772+
result.persistCredentials =
12773+
(core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE';
1276912774
return result;
1277012775
}
1277112776
exports.getInputs = getInputs;

Diff for: src/git-command-manager.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ class GitCommandManager {
116116
}
117117

118118
async config(configKey: string, configValue: string): Promise<void> {
119-
await this.execGit(['config', configKey, configValue])
119+
await this.execGit(['config', '--local', configKey, configValue])
120120
}
121121

122122
async configExists(configKey: string): Promise<boolean> {
123123
const pattern = configKey.replace(/[^a-zA-Z0-9_]/g, x => {
124124
return `\\${x}`
125125
})
126126
const output = await this.execGit(
127-
['config', '--name-only', '--get-regexp', pattern],
127+
['config', '--local', '--name-only', '--get-regexp', pattern],
128128
true
129129
)
130130
return output.exitCode === 0
@@ -211,20 +211,23 @@ class GitCommandManager {
211211

212212
async tryConfigUnset(configKey: string): Promise<boolean> {
213213
const output = await this.execGit(
214-
['config', '--unset-all', configKey],
214+
['config', '--local', '--unset-all', configKey],
215215
true
216216
)
217217
return output.exitCode === 0
218218
}
219219

220220
async tryDisableAutomaticGarbageCollection(): Promise<boolean> {
221-
const output = await this.execGit(['config', 'gc.auto', '0'], true)
221+
const output = await this.execGit(
222+
['config', '--local', 'gc.auto', '0'],
223+
true
224+
)
222225
return output.exitCode === 0
223226
}
224227

225228
async tryGetFetchUrl(): Promise<string> {
226229
const output = await this.execGit(
227-
['config', '--get', 'remote.origin.url'],
230+
['config', '--local', '--get', 'remote.origin.url'],
228231
true
229232
)
230233

0 commit comments

Comments
 (0)