Read-only mirror — the public repositories of the Forgejo instance, refreshed every 10 minutes. The live instance (fg.dieschoenewolke.de) is reachable only over the VPN; clone here with https://git.dieschoenewolke.de/git/<owner>/<repo>.git.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreric sciple <ericsciple@users.noreply.github.com>2019-12-12 13:49:26 -0500
committerGitHub <noreply@github.com>2019-12-12 13:49:26 -0500
commitca3a763d5ed9e04331c8a6aea85ddabcb3a6aa4d (patch)
tree236058d4a2be4208412dc3ed294e2db566aab7d6
parent25ac60e43ded675f082e10f444b0ad95ea43622e (diff)
add input persist-credentials (#107)
-rw-r--r--.github/workflows/test.yml10
-rw-r--r--README.md18
-rw-r--r--__test__/input-helper.test.ts2
-rw-r--r--action.yml14
-rw-r--r--dist/index.js99
-rw-r--r--src/git-command-manager.ts13
-rw-r--r--src/git-source-provider.ts99
-rw-r--r--src/github-api-helper.ts8
-rw-r--r--src/input-helper.ts8
9 files changed, 146 insertions, 125 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 62dce24..93a3792 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,6 +18,7 @@ jobs:
- run: npm run lint
- run: npm run pack
- run: npm run gendocs
+ - run: npm test
- name: Verify no unstaged changes
run: __test__/verify-no-unstaged-changes.sh
@@ -84,15 +85,12 @@ jobs:
test-job-container:
runs-on: ubuntu-latest
- container: pstauffer/curl:latest
+ container: alpine:latest
steps:
# Clone this repo
- # todo: after v2-beta contains the latest changes, switch this to "uses: actions/checkout@v2-beta". Also switch to "alpine:latest"
+ # todo: after v2-beta contains the latest changes, switch this to "uses: actions/checkout@v2-beta"
- name: Checkout
- run: |
- curl --location --user token:${{ github.token }} --output checkout.tar.gz https://api.github.com/repos/actions/checkout/tarball/${{ github.sha }}
- tar -xzf checkout.tar.gz
- mv */* ./
+ uses: actions/checkout@a572f640b07e96fc5837b3adfa0e5a2ddd8dae21
# Basic checkout
- name: Basic checkout
diff --git a/README.md b/README.md
index 44aea2c..f27df23 100644
--- a/README.md
+++ b/README.md
@@ -15,16 +15,16 @@ Refer [here](https://help.github.com/en/articles/events-that-trigger-workflows)
- Improved fetch performance
- The default behavior now fetches only the commit being checked-out
- Script authenticated git commands
- - Persists `with.token` in the local git config
+ - Persists the input `token` in the local git config
- Enables your scripts to run authenticated git commands
- Post-job cleanup removes the token
- - Coming soon: Opt out by setting `with.persist-credentials` to `false`
+ - Opt out by setting the input `persist-credentials: false`
- Creates a local branch
- No longer detached HEAD when checking out a branch
- A local branch is created with the corresponding upstream branch set
- Improved layout
- - `with.path` is always relative to `github.workspace`
- - Aligns better with container actions, where `github.workspace` gets mapped in
+ - The input `path` is always relative to $GITHUB_WORKSPACE
+ - Aligns better with container actions, where $GITHUB_WORKSPACE gets mapped in
- Fallback to REST API download
- When Git 2.18 or higher is not in the PATH, the REST API will be used to download the files
- Removed input `submodules`
@@ -41,15 +41,21 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
# Default: ${{ github.repository }}
repository: ''
- # The branch, tag or SHA to checkout. When checking out the repository that
+ # The branch, tag or SHA to checkout. When checking out the repository that
# triggered a workflow, this defaults to the reference or SHA for that event.
# Otherwise, defaults to `master`.
ref: ''
- # Access token for clone repository
+ # Auth token used to fetch the repository. The token is stored in the local git
+ # config, which enables your scripts to run authenticated git commands. The
+ # post-job step removes the token from the git config.
# Default: ${{ github.token }}
token: ''
+ # Whether to persist the token in the git config
+ # Default: true
+ persist-credentials: ''
+
# Relative path under $GITHUB_WORKSPACE to place the repository
path: ''
diff --git a/__test__/input-helper.test.ts b/__test__/input-helper.test.ts
index 6010e11..ecd3cd1 100644
--- a/__test__/input-helper.test.ts
+++ b/__test__/input-helper.test.ts
@@ -63,7 +63,7 @@ describe('input-helper tests', () => {
it('sets defaults', () => {
const settings: ISourceSettings = inputHelper.getInputs()
expect(settings).toBeTruthy()
- expect(settings.accessToken).toBeFalsy()
+ expect(settings.authToken).toBeFalsy()
expect(settings.clean).toBe(true)
expect(settings.commit).toBeTruthy()
expect(settings.commit).toBe('1234567890123456789012345678901234567890')
diff --git a/action.yml b/action.yml
index d21e5f1..54cf4b3 100644
--- a/action.yml
+++ b/action.yml
@@ -6,12 +6,18 @@ inputs:
default: ${{ github.repository }}
ref:
description: >
- The branch, tag or SHA to checkout. When checking out the repository
- that triggered a workflow, this defaults to the reference or SHA for
- that event. Otherwise, defaults to `master`.
+ The branch, tag or SHA to checkout. When checking out the repository that
+ triggered a workflow, this defaults to the reference or SHA for that
+ event. Otherwise, defaults to `master`.
token:
- description: 'Access token for clone repository'
+ description: >
+ Auth token used to fetch the repository. The token is stored in the local
+ git config, which enables your scripts to run authenticated git commands.
+ The post-job step removes the token from the git config.
default: ${{ github.token }}
+ persist-credentials:
+ description: 'Whether to persist the token in the git config'
+ default: true
path:
description: 'Relative path under $GITHUB_WORKSPACE to place the repository'
clean:
diff --git a/dist/index.js b/dist/index.js
index c6444b5..380d8c3 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -4838,7 +4838,7 @@ class GitCommandManager {
}
config(configKey, configValue) {
return __awaiter(this, void 0, void 0, function* () {
- yield this.execGit(['config', configKey, configValue]);
+ yield this.execGit(['config', '--local', configKey, configValue]);
});
}
configExists(configKey) {
@@ -4846,7 +4846,7 @@ class GitCommandManager {
const pattern = configKey.replace(/[^a-zA-Z0-9_]/g, x => {
return `\\${x}`;
});
- const output = yield this.execGit(['config', '--name-only', '--get-regexp', pattern], true);
+ const output = yield this.execGit(['config', '--local', '--name-only', '--get-regexp', pattern], true);
return output.exitCode === 0;
});
}
@@ -4932,19 +4932,19 @@ class GitCommandManager {
}
tryConfigUnset(configKey) {
return __awaiter(this, void 0, void 0, function* () {
- const output = yield this.execGit(['config', '--unset-all', configKey], true);
+ const output = yield this.execGit(['config', '--local', '--unset-all', configKey], true);
return output.exitCode === 0;
});
}
tryDisableAutomaticGarbageCollection() {
return __awaiter(this, void 0, void 0, function* () {
- const output = yield this.execGit(['config', 'gc.auto', '0'], true);
+ const output = yield this.execGit(['config', '--local', 'gc.auto', '0'], true);
return output.exitCode === 0;
});
}
tryGetFetchUrl() {
return __awaiter(this, void 0, void 0, function* () {
- const output = yield this.execGit(['config', '--get', 'remote.origin.url'], true);
+ const output = yield this.execGit(['config', '--local', '--get', 'remote.origin.url'], true);
if (output.exitCode !== 0) {
return '';
}
@@ -5121,7 +5121,7 @@ function getSource(settings) {
// Downloading using REST API
core.info(`The repository will be downloaded using the GitHub REST API`);
core.info(`To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH`);
- yield githubApiHelper.downloadRepository(settings.accessToken, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.repositoryPath);
+ yield githubApiHelper.downloadRepository(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.repositoryPath);
}
else {
// Save state for POST action
@@ -5137,30 +5137,34 @@ function getSource(settings) {
}
// Remove possible previous extraheader
yield removeGitConfig(git, authConfigKey);
- // Add extraheader (auth)
- const base64Credentials = Buffer.from(`x-access-token:${settings.accessToken}`, 'utf8').toString('base64');
- core.setSecret(base64Credentials);
- const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`;
- yield git.config(authConfigKey, authConfigValue);
- // LFS install
- if (settings.lfs) {
- yield git.lfsInstall();
- }
- // Fetch
- const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
- yield git.fetch(settings.fetchDepth, refSpec);
- // Checkout info
- const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
- // LFS fetch
- // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
- // Explicit lfs fetch will fetch lfs objects in parallel.
- if (settings.lfs) {
- yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
+ try {
+ // Config auth token
+ yield configureAuthToken(git, settings.authToken);
+ // LFS install
+ if (settings.lfs) {
+ yield git.lfsInstall();
+ }
+ // Fetch
+ const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
+ yield git.fetch(settings.fetchDepth, refSpec);
+ // Checkout info
+ const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
+ // LFS fetch
+ // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
+ // Explicit lfs fetch will fetch lfs objects in parallel.
+ if (settings.lfs) {
+ yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
+ }
+ // Checkout
+ yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
+ // Dump some info about the checked out commit
+ yield git.log1();
+ }
+ finally {
+ if (!settings.persistCredentials) {
+ yield removeGitConfig(git, authConfigKey);
+ }
}
- // Checkout
- yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
- // Dump some info about the checked out commit
- yield git.log1();
}
});
}
@@ -5265,23 +5269,21 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
}
});
}
+function configureAuthToken(git, authToken) {
+ return __awaiter(this, void 0, void 0, function* () {
+ // Add extraheader (auth)
+ const base64Credentials = Buffer.from(`x-access-token:${authToken}`, 'utf8').toString('base64');
+ core.setSecret(base64Credentials);
+ const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`;
+ yield git.config(authConfigKey, authConfigValue);
+ });
+}
function removeGitConfig(git, configKey) {
return __awaiter(this, void 0, void 0, function* () {
if ((yield git.configExists(configKey)) &&
!(yield git.tryConfigUnset(configKey))) {
// Load the config contents
- core.warning(`Failed to remove '${configKey}' from the git config. Attempting to remove the config value by editing the file directly.`);
- const configPath = path.join(git.getWorkingDirectory(), '.git', 'config');
- fsHelper.fileExistsSync(configPath);
- let contents = fs.readFileSync(configPath).toString() || '';
- // Filter - only includes lines that do not contain the config key
- const upperConfigKey = configKey.toUpperCase();
- const split = contents
- .split('\n')
- .filter(x => !x.toUpperCase().includes(upperConfigKey));
- contents = split.join('\n');
- // Rewrite the config file
- fs.writeFileSync(configPath, contents);
+ core.warning(`Failed to remove '${configKey}' from the git config`);
}
});
}
@@ -8403,12 +8405,12 @@ const retryHelper = __importStar(__webpack_require__(587));
const toolCache = __importStar(__webpack_require__(533));
const v4_1 = __importDefault(__webpack_require__(826));
const IS_WINDOWS = process.platform === 'win32';
-function downloadRepository(accessToken, owner, repo, ref, commit, repositoryPath) {
+function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath) {
return __awaiter(this, void 0, void 0, function* () {
// Download the archive
let archiveData = yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
core.info('Downloading the archive');
- return yield downloadArchive(accessToken, owner, repo, ref, commit);
+ return yield downloadArchive(authToken, owner, repo, ref, commit);
}));
// Write archive to disk
core.info('Writing archive to disk');
@@ -8449,9 +8451,9 @@ function downloadRepository(accessToken, owner, repo, ref, commit, repositoryPat
});
}
exports.downloadRepository = downloadRepository;
-function downloadArchive(accessToken, owner, repo, ref, commit) {
+function downloadArchive(authToken, owner, repo, ref, commit) {
return __awaiter(this, void 0, void 0, function* () {
- const octokit = new github.GitHub(accessToken);
+ const octokit = new github.GitHub(authToken);
const params = {
owner: owner,
repo: repo,
@@ -12764,8 +12766,11 @@ function getInputs() {
// LFS
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE';
core.debug(`lfs = ${result.lfs}`);
- // Access token
- result.accessToken = core.getInput('token');
+ // Auth token
+ result.authToken = core.getInput('token');
+ // Persist credentials
+ result.persistCredentials =
+ (core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE';
return result;
}
exports.getInputs = getInputs;
diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts
index ddd5ec6..f86b8c0 100644
--- a/src/git-command-manager.ts
+++ b/src/git-command-manager.ts
@@ -116,7 +116,7 @@ class GitCommandManager {
}
async config(configKey: string, configValue: string): Promise<void> {
- await this.execGit(['config', configKey, configValue])
+ await this.execGit(['config', '--local', configKey, configValue])
}
async configExists(configKey: string): Promise<boolean> {
@@ -124,7 +124,7 @@ class GitCommandManager {
return `\\${x}`
})
const output = await this.execGit(
- ['config', '--name-only', '--get-regexp', pattern],
+ ['config', '--local', '--name-only', '--get-regexp', pattern],
true
)
return output.exitCode === 0
@@ -211,20 +211,23 @@ class GitCommandManager {
async tryConfigUnset(configKey: string): Promise<boolean> {
const output = await this.execGit(
- ['config', '--unset-all', configKey],
+ ['config', '--local', '--unset-all', configKey],
true
)
return output.exitCode === 0
}
async tryDisableAutomaticGarbageCollection(): Promise<boolean> {
- const output = await this.execGit(['config', 'gc.auto', '0'], true)
+ const output = await this.execGit(
+ ['config', '--local', 'gc.auto', '0'],
+ true
+ )
return output.exitCode === 0
}
async tryGetFetchUrl(): Promise<string> {
const output = await this.execGit(
- ['config', '--get', 'remote.origin.url'],
+ ['config', '--local', '--get', 'remote.origin.url'],
true
)
diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts
index bf086ff..6b7a9f7 100644
--- a/src/git-source-provider.ts
+++ b/src/git-source-provider.ts
@@ -1,5 +1,4 @@
import * as core from '@actions/core'
-import * as coreCommand from '@actions/core/lib/command'
import * as fs from 'fs'
import * as fsHelper from './fs-helper'
import * as gitCommandManager from './git-command-manager'
@@ -21,7 +20,8 @@ export interface ISourceSettings {
clean: boolean
fetchDepth: number
lfs: boolean
- accessToken: string
+ authToken: string
+ persistCredentials: boolean
}
export async function getSource(settings: ISourceSettings): Promise<void> {
@@ -65,7 +65,7 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
`To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH`
)
await githubApiHelper.downloadRepository(
- settings.accessToken,
+ settings.authToken,
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
@@ -94,43 +94,43 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
// Remove possible previous extraheader
await removeGitConfig(git, authConfigKey)
- // Add extraheader (auth)
- const base64Credentials = Buffer.from(
- `x-access-token:${settings.accessToken}`,
- 'utf8'
- ).toString('base64')
- core.setSecret(base64Credentials)
- const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`
- await git.config(authConfigKey, authConfigValue)
+ try {
+ // Config auth token
+ await configureAuthToken(git, settings.authToken)
- // LFS install
- if (settings.lfs) {
- await git.lfsInstall()
- }
+ // LFS install
+ if (settings.lfs) {
+ await git.lfsInstall()
+ }
- // Fetch
- const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
- await git.fetch(settings.fetchDepth, refSpec)
+ // Fetch
+ const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
+ await git.fetch(settings.fetchDepth, refSpec)
- // Checkout info
- const checkoutInfo = await refHelper.getCheckoutInfo(
- git,
- settings.ref,
- settings.commit
- )
+ // Checkout info
+ const checkoutInfo = await refHelper.getCheckoutInfo(
+ git,
+ settings.ref,
+ settings.commit
+ )
- // LFS fetch
- // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
- // Explicit lfs fetch will fetch lfs objects in parallel.
- if (settings.lfs) {
- await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
- }
+ // LFS fetch
+ // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
+ // Explicit lfs fetch will fetch lfs objects in parallel.
+ if (settings.lfs) {
+ await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
+ }
- // Checkout
- await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
+ // Checkout
+ await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
- // Dump some info about the checked out commit
- await git.log1()
+ // Dump some info about the checked out commit
+ await git.log1()
+ } finally {
+ if (!settings.persistCredentials) {
+ await removeGitConfig(git, authConfigKey)
+ }
+ }
}
}
@@ -255,6 +255,20 @@ async function prepareExistingDirectory(
}
}
+async function configureAuthToken(
+ git: IGitCommandManager,
+ authToken: string
+): Promise<void> {
+ // Add extraheader (auth)
+ const base64Credentials = Buffer.from(
+ `x-access-token:${authToken}`,
+ 'utf8'
+ ).toString('base64')
+ core.setSecret(base64Credentials)
+ const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`
+ await git.config(authConfigKey, authConfigValue)
+}
+
async function removeGitConfig(
git: IGitCommandManager,
configKey: string
@@ -264,21 +278,6 @@ async function removeGitConfig(
!(await git.tryConfigUnset(configKey))
) {
// Load the config contents
- core.warning(
- `Failed to remove '${configKey}' from the git config. Attempting to remove the config value by editing the file directly.`
- )
- const configPath = path.join(git.getWorkingDirectory(), '.git', 'config')
- fsHelper.fileExistsSync(configPath)
- let contents = fs.readFileSync(configPath).toString() || ''
-
- // Filter - only includes lines that do not contain the config key
- const upperConfigKey = configKey.toUpperCase()
- const split = contents
- .split('\n')
- .filter(x => !x.toUpperCase().includes(upperConfigKey))
- contents = split.join('\n')
-
- // Rewrite the config file
- fs.writeFileSync(configPath, contents)
+ core.warning(`Failed to remove '${configKey}' from the git config`)
}
}
diff --git a/src/github-api-helper.ts b/src/github-api-helper.ts
index b370d06..83a2b86 100644
--- a/src/github-api-helper.ts
+++ b/src/github-api-helper.ts
@@ -12,7 +12,7 @@ import {ReposGetArchiveLinkParams} from '@octokit/rest'
const IS_WINDOWS = process.platform === 'win32'
export async function downloadRepository(
- accessToken: string,
+ authToken: string,
owner: string,
repo: string,
ref: string,
@@ -22,7 +22,7 @@ export async function downloadRepository(
// Download the archive
let archiveData = await retryHelper.execute(async () => {
core.info('Downloading the archive')
- return await downloadArchive(accessToken, owner, repo, ref, commit)
+ return await downloadArchive(authToken, owner, repo, ref, commit)
})
// Write archive to disk
@@ -68,13 +68,13 @@ export async function downloadRepository(
}
async function downloadArchive(
- accessToken: string,
+ authToken: string,
owner: string,
repo: string,
ref: string,
commit: string
): Promise<Buffer> {
- const octokit = new github.GitHub(accessToken)
+ const octokit = new github.GitHub(authToken)
const params: ReposGetArchiveLinkParams = {
owner: owner,
repo: repo,
diff --git a/src/input-helper.ts b/src/input-helper.ts
index d7d8779..56b58f2 100644
--- a/src/input-helper.ts
+++ b/src/input-helper.ts
@@ -97,8 +97,12 @@ export function getInputs(): ISourceSettings {
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'
core.debug(`lfs = ${result.lfs}`)
- // Access token
- result.accessToken = core.getInput('token')
+ // Auth token
+ result.authToken = core.getInput('token')
+
+ // Persist credentials
+ result.persistCredentials =
+ (core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE'
return result
}