mirror of https://github.com/actions/checkout
Compare commits
4 Commits
36dc31b87a
...
410995bbce
| Author | SHA1 | Date |
|---|---|---|
|
|
410995bbce | |
|
|
f9e715a95f | |
|
|
7618b1f401 | |
|
|
b6625bb44a |
|
|
@ -166,6 +166,17 @@ jobs:
|
||||||
- name: Verify submodules true
|
- name: Verify submodules true
|
||||||
run: __test__/verify-submodules-true.sh
|
run: __test__/verify-submodules-true.sh
|
||||||
|
|
||||||
|
# Submodules limited
|
||||||
|
- name: Checkout submodules limited
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
ref: test-data/v2/submodule-ssh-url
|
||||||
|
path: submodules-true
|
||||||
|
submodules: true
|
||||||
|
submodule-directories: submodule-level-1
|
||||||
|
- name: Verify submodules true
|
||||||
|
run: __test__/verify-submodules-true.sh
|
||||||
|
|
||||||
# Submodules recursive
|
# Submodules recursive
|
||||||
- name: Checkout submodules recursive
|
- name: Checkout submodules recursive
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
|
||||||
13
README.md
13
README.md
|
|
@ -150,6 +150,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
|
||||||
# Default: false
|
# Default: false
|
||||||
submodules: ''
|
submodules: ''
|
||||||
|
|
||||||
|
# A list of submodules to checkout.
|
||||||
|
# Default: null
|
||||||
|
submodule-directories: ''
|
||||||
|
|
||||||
# Add repository path as safe.directory for Git global config by running `git
|
# Add repository path as safe.directory for Git global config by running `git
|
||||||
# config --global --add safe.directory <path>`
|
# config --global --add safe.directory <path>`
|
||||||
# Default: true
|
# Default: true
|
||||||
|
|
@ -160,6 +164,15 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
|
||||||
# running from unless specified. Example URLs are https://github.com or
|
# running from unless specified. Example URLs are https://github.com or
|
||||||
# https://my-ghes-server.example.com
|
# https://my-ghes-server.example.com
|
||||||
github-server-url: ''
|
github-server-url: ''
|
||||||
|
|
||||||
|
# Required to check out fork pull request code from a workflow triggered by
|
||||||
|
# `pull_request_target` or `workflow_run`. These workflows run with the base
|
||||||
|
# repository's GITHUB_TOKEN, secrets, default-branch cache scope, and runner
|
||||||
|
# access; fetching and executing a fork's code in that trusted context commonly
|
||||||
|
# leads to "pwn request" vulnerabilities. Set to `true` only after reviewing the
|
||||||
|
# risks at https://gh.io/securely-using-pull_request_target.
|
||||||
|
# Default: false
|
||||||
|
allow-unsafe-pr-checkout: ''
|
||||||
```
|
```
|
||||||
<!-- end usage -->
|
<!-- end usage -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1162,6 +1162,7 @@ async function setup(testName: string): Promise<void> {
|
||||||
lfs: false,
|
lfs: false,
|
||||||
submodules: false,
|
submodules: false,
|
||||||
nestedSubmodules: false,
|
nestedSubmodules: false,
|
||||||
|
submoduleDirectories: [],
|
||||||
persistCredentials: true,
|
persistCredentials: true,
|
||||||
ref: 'refs/heads/main',
|
ref: 'refs/heads/main',
|
||||||
repositoryName: 'my-repo',
|
repositoryName: 'my-repo',
|
||||||
|
|
@ -1173,7 +1174,8 @@ async function setup(testName: string): Promise<void> {
|
||||||
sshUser: '',
|
sshUser: '',
|
||||||
workflowOrganizationId: 123456,
|
workflowOrganizationId: 123456,
|
||||||
setSafeDirectory: true,
|
setSafeDirectory: true,
|
||||||
githubServerUrl: githubServerUrl
|
githubServerUrl: githubServerUrl,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@ describe('input-helper tests', () => {
|
||||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||||
return inputs[name]
|
return inputs[name]
|
||||||
})
|
})
|
||||||
|
// Mock getMultilineInput
|
||||||
|
jest.spyOn(core, 'getMultilineInput').mockImplementation((name: string) => {
|
||||||
|
const input: string[] = (inputs[name] || '')
|
||||||
|
.split('\n')
|
||||||
|
.filter(x => x !== '')
|
||||||
|
return input.map(inp => inp.trim())
|
||||||
|
})
|
||||||
|
|
||||||
// Mock error/warning/info/debug
|
// Mock error/warning/info/debug
|
||||||
jest.spyOn(core, 'error').mockImplementation(jest.fn())
|
jest.spyOn(core, 'error').mockImplementation(jest.fn())
|
||||||
|
|
@ -87,10 +94,12 @@ describe('input-helper tests', () => {
|
||||||
expect(settings.showProgress).toBe(true)
|
expect(settings.showProgress).toBe(true)
|
||||||
expect(settings.lfs).toBe(false)
|
expect(settings.lfs).toBe(false)
|
||||||
expect(settings.ref).toBe('refs/heads/some-ref')
|
expect(settings.ref).toBe('refs/heads/some-ref')
|
||||||
|
expect(settings.submoduleDirectories).toStrictEqual([])
|
||||||
expect(settings.repositoryName).toBe('some-repo')
|
expect(settings.repositoryName).toBe('some-repo')
|
||||||
expect(settings.repositoryOwner).toBe('some-owner')
|
expect(settings.repositoryOwner).toBe('some-owner')
|
||||||
expect(settings.repositoryPath).toBe(gitHubWorkspace)
|
expect(settings.repositoryPath).toBe(gitHubWorkspace)
|
||||||
expect(settings.setSafeDirectory).toBe(true)
|
expect(settings.setSafeDirectory).toBe(true)
|
||||||
|
expect(settings.allowUnsafePrCheckout).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('qualifies ref', async () => {
|
it('qualifies ref', async () => {
|
||||||
|
|
@ -154,4 +163,13 @@ describe('input-helper tests', () => {
|
||||||
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
||||||
expect(settings.workflowOrganizationId).toBe(123456)
|
expect(settings.workflowOrganizationId).toBe(123456)
|
||||||
})
|
})
|
||||||
|
it('sets submoduleDirectories', async () => {
|
||||||
|
inputs['submodule-directories'] = 'submodule1\nsubmodule2'
|
||||||
|
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
||||||
|
expect(settings.submoduleDirectories).toStrictEqual([
|
||||||
|
'submodule1',
|
||||||
|
'submodule2'
|
||||||
|
])
|
||||||
|
expect(settings.submodules).toBe(true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,267 @@
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import {assertSafePrCheckout} from '../lib/unsafe-pr-checkout-helper'
|
||||||
|
|
||||||
|
// Shallow clone original @actions/github context
|
||||||
|
const originalContext = {...github.context}
|
||||||
|
const originalEventName = github.context.eventName
|
||||||
|
const originalPayload = github.context.payload
|
||||||
|
|
||||||
|
const BASE_REPO_ID = 100
|
||||||
|
const FORK_REPO_ID = 200
|
||||||
|
const PR_HEAD_SHA = '1111111111111111111111111111111111111111'
|
||||||
|
const PR_MERGE_SHA = '2222222222222222222222222222222222222222'
|
||||||
|
const SAFE_BASE_SHA = '3333333333333333333333333333333333333333'
|
||||||
|
const WORKFLOW_RUN_HEAD_COMMIT_SHA = '4444444444444444444444444444444444444444'
|
||||||
|
const BASE_QUALIFIED_REPO = 'some-owner/some-repo'
|
||||||
|
const FORK_QUALIFIED_REPO = 'another-repo/fork'
|
||||||
|
|
||||||
|
function setContext(eventName: string, payload: object): void {
|
||||||
|
;(github.context as {eventName: string}).eventName = eventName
|
||||||
|
;(github.context as {payload: object}).payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
function forkPullRequestTargetPayload(): object {
|
||||||
|
return {
|
||||||
|
repository: {id: BASE_REPO_ID},
|
||||||
|
pull_request: {
|
||||||
|
head: {
|
||||||
|
sha: PR_HEAD_SHA,
|
||||||
|
repo: {id: FORK_REPO_ID, full_name: FORK_QUALIFIED_REPO}
|
||||||
|
},
|
||||||
|
merge_commit_sha: PR_MERGE_SHA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sameRepoPullRequestTargetPayload(): object {
|
||||||
|
return {
|
||||||
|
repository: {id: BASE_REPO_ID},
|
||||||
|
pull_request: {
|
||||||
|
head: {
|
||||||
|
sha: PR_HEAD_SHA,
|
||||||
|
repo: {id: BASE_REPO_ID, full_name: BASE_QUALIFIED_REPO}
|
||||||
|
},
|
||||||
|
merge_commit_sha: PR_MERGE_SHA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function forkWorkflowRunPayload(): object {
|
||||||
|
return {
|
||||||
|
repository: {id: BASE_REPO_ID},
|
||||||
|
workflow_run: {
|
||||||
|
event: 'pull_request',
|
||||||
|
head_commit: {id: WORKFLOW_RUN_HEAD_COMMIT_SHA},
|
||||||
|
head_repository: {id: FORK_REPO_ID, full_name: FORK_QUALIFIED_REPO}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('unsafe-pr-checkout-helper', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(github.context, 'repo', 'get').mockReturnValue({
|
||||||
|
owner: 'some-owner',
|
||||||
|
repo: 'some-repo'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
;(github.context as {eventName: string}).eventName = originalEventName
|
||||||
|
;(github.context as {payload: object}).payload = originalPayload
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
;(github.context as {eventName: string}).eventName =
|
||||||
|
originalContext.eventName
|
||||||
|
;(github.context as {payload: object}).payload = originalContext.payload
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows pull_request events untouched', () => {
|
||||||
|
setContext('pull_request', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: 'attacker/fork',
|
||||||
|
ref: 'refs/pull/1/merge',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows pull_request_target default checkout (base branch)', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: 'refs/heads/main',
|
||||||
|
commit: SAFE_BASE_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows same-repo pull_request_target checkout of PR head', () => {
|
||||||
|
setContext('pull_request_target', sameRepoPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: PR_HEAD_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target fork PR head SHA checkout', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: PR_HEAD_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow(/Refusing to check out fork pull request code/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target fork PR merge_commit_sha checkout', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: PR_MERGE_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow(/allow-unsafe-pr-checkout/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target fork PR ref pattern (head)', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: 'refs/pull/42/head',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target fork PR ref pattern (merge)', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: 'refs/pull/42/merge',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target when repository points at the fork', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: FORK_QUALIFIED_REPO,
|
||||||
|
ref: 'refs/heads/main',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows pull_request_target checkout of an unrelated third-party repo', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: 'some-other/unrelated',
|
||||||
|
ref: 'refs/heads/main',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target ignoring repository case differences', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: FORK_QUALIFIED_REPO.toUpperCase(),
|
||||||
|
ref: '',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses pull_request_target ignoring commit SHA case differences', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: PR_HEAD_SHA.toUpperCase(),
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows pull_request_target fork PR checkout when opted in', () => {
|
||||||
|
setContext('pull_request_target', forkPullRequestTargetPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: 'refs/pull/42/merge',
|
||||||
|
commit: '',
|
||||||
|
allowUnsafePrCheckout: true
|
||||||
|
})
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses workflow_run fork PR head_commit.id checkout', () => {
|
||||||
|
setContext('workflow_run', forkWorkflowRunPayload())
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: WORKFLOW_RUN_HEAD_COMMIT_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses workflow_run with pull_request_target underlying event', () => {
|
||||||
|
const payload = forkWorkflowRunPayload() as {
|
||||||
|
workflow_run: {event: string}
|
||||||
|
}
|
||||||
|
payload.workflow_run.event = 'pull_request_target'
|
||||||
|
setContext('workflow_run', payload)
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: WORKFLOW_RUN_HEAD_COMMIT_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows workflow_run same-repo PR (head_repository.id matches base)', () => {
|
||||||
|
const payload = forkWorkflowRunPayload() as {
|
||||||
|
workflow_run: {head_repository: {id: number}}
|
||||||
|
}
|
||||||
|
payload.workflow_run.head_repository.id = BASE_REPO_ID
|
||||||
|
setContext('workflow_run', payload)
|
||||||
|
expect(() =>
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository: BASE_QUALIFIED_REPO,
|
||||||
|
ref: '',
|
||||||
|
commit: WORKFLOW_RUN_HEAD_COMMIT_SHA,
|
||||||
|
allowUnsafePrCheckout: false
|
||||||
|
})
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
13
action.yml
13
action.yml
|
|
@ -92,12 +92,25 @@ inputs:
|
||||||
When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are
|
When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are
|
||||||
converted to HTTPS.
|
converted to HTTPS.
|
||||||
default: false
|
default: false
|
||||||
|
submodule-directories:
|
||||||
|
description: >
|
||||||
|
A list of submodules to checkout.
|
||||||
|
default: null
|
||||||
set-safe-directory:
|
set-safe-directory:
|
||||||
description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory <path>`
|
description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory <path>`
|
||||||
default: true
|
default: true
|
||||||
github-server-url:
|
github-server-url:
|
||||||
description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. Example URLs are https://github.com or https://my-ghes-server.example.com
|
description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. Example URLs are https://github.com or https://my-ghes-server.example.com
|
||||||
required: false
|
required: false
|
||||||
|
allow-unsafe-pr-checkout:
|
||||||
|
description: >
|
||||||
|
Required to check out fork pull request code from a workflow triggered by
|
||||||
|
`pull_request_target` or `workflow_run`. These workflows run with the
|
||||||
|
base repository's GITHUB_TOKEN, secrets, default-branch cache scope, and
|
||||||
|
runner access; fetching and executing a fork's code in that trusted
|
||||||
|
context commonly leads to "pwn request" vulnerabilities. Set to `true`
|
||||||
|
only after reviewing the risks at https://gh.io/securely-using-pull_request_target.
|
||||||
|
default: false
|
||||||
outputs:
|
outputs:
|
||||||
ref:
|
ref:
|
||||||
description: 'The branch, tag or SHA that was checked out'
|
description: 'The branch, tag or SHA that was checked out'
|
||||||
|
|
|
||||||
|
|
@ -985,10 +985,10 @@ class GitCommandManager {
|
||||||
yield this.execGit(args);
|
yield this.execGit(args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
submoduleUpdate(fetchDepth, recursive) {
|
submoduleUpdate(fetchDepth, recursive, submoduleDirectories) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const args = ['-c', 'protocol.version=2'];
|
const args = ['-c', 'protocol.version=2'];
|
||||||
args.push('submodule', 'update', '--init', '--force');
|
args.push('submodule', 'update', '--init', '--force', ...submoduleDirectories);
|
||||||
if (fetchDepth > 0) {
|
if (fetchDepth > 0) {
|
||||||
args.push(`--depth=${fetchDepth}`);
|
args.push(`--depth=${fetchDepth}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1618,7 +1618,7 @@ function getSource(settings) {
|
||||||
// Checkout submodules
|
// Checkout submodules
|
||||||
core.startGroup('Fetching submodules');
|
core.startGroup('Fetching submodules');
|
||||||
yield git.submoduleSync(settings.nestedSubmodules);
|
yield git.submoduleSync(settings.nestedSubmodules);
|
||||||
yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules);
|
yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules, settings.submoduleDirectories);
|
||||||
yield git.submoduleForeach('git config --local gc.auto 0', settings.nestedSubmodules);
|
yield git.submoduleForeach('git config --local gc.auto 0', settings.nestedSubmodules);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
// Persist credentials
|
// Persist credentials
|
||||||
|
|
@ -2023,6 +2023,7 @@ const core = __importStar(__nccwpck_require__(2186));
|
||||||
const fsHelper = __importStar(__nccwpck_require__(7219));
|
const fsHelper = __importStar(__nccwpck_require__(7219));
|
||||||
const github = __importStar(__nccwpck_require__(5438));
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
|
const unsafePrCheckoutHelper = __importStar(__nccwpck_require__(843));
|
||||||
const workflowContextHelper = __importStar(__nccwpck_require__(9568));
|
const workflowContextHelper = __importStar(__nccwpck_require__(9568));
|
||||||
function getInputs() {
|
function getInputs() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
|
@ -2114,6 +2115,7 @@ function getInputs() {
|
||||||
// Submodules
|
// Submodules
|
||||||
result.submodules = false;
|
result.submodules = false;
|
||||||
result.nestedSubmodules = false;
|
result.nestedSubmodules = false;
|
||||||
|
result.submoduleDirectories = [];
|
||||||
const submodulesString = (core.getInput('submodules') || '').toUpperCase();
|
const submodulesString = (core.getInput('submodules') || '').toUpperCase();
|
||||||
if (submodulesString == 'RECURSIVE') {
|
if (submodulesString == 'RECURSIVE') {
|
||||||
result.submodules = true;
|
result.submodules = true;
|
||||||
|
|
@ -2122,8 +2124,15 @@ function getInputs() {
|
||||||
else if (submodulesString == 'TRUE') {
|
else if (submodulesString == 'TRUE') {
|
||||||
result.submodules = true;
|
result.submodules = true;
|
||||||
}
|
}
|
||||||
|
const submoduleDirectories = core.getMultilineInput('submodule-directories');
|
||||||
|
if (submoduleDirectories.length > 0) {
|
||||||
|
result.submoduleDirectories = submoduleDirectories;
|
||||||
|
if (!result.submodules)
|
||||||
|
result.submodules = true;
|
||||||
|
}
|
||||||
core.debug(`submodules = ${result.submodules}`);
|
core.debug(`submodules = ${result.submodules}`);
|
||||||
core.debug(`recursive submodules = ${result.nestedSubmodules}`);
|
core.debug(`recursive submodules = ${result.nestedSubmodules}`);
|
||||||
|
core.debug(`submodule directories = ${result.submoduleDirectories}`);
|
||||||
// Auth token
|
// Auth token
|
||||||
result.authToken = core.getInput('token', { required: true });
|
result.authToken = core.getInput('token', { required: true });
|
||||||
// SSH
|
// SSH
|
||||||
|
|
@ -2144,6 +2153,17 @@ function getInputs() {
|
||||||
// Determine the GitHub URL that the repository is being hosted from
|
// Determine the GitHub URL that the repository is being hosted from
|
||||||
result.githubServerUrl = core.getInput('github-server-url');
|
result.githubServerUrl = core.getInput('github-server-url');
|
||||||
core.debug(`GitHub Host URL = ${result.githubServerUrl}`);
|
core.debug(`GitHub Host URL = ${result.githubServerUrl}`);
|
||||||
|
// Allow unsafe PR checkout (opt-in for pull_request_target / workflow_run fork PRs)
|
||||||
|
result.allowUnsafePrCheckout =
|
||||||
|
(core.getInput('allow-unsafe-pr-checkout') || 'false').toUpperCase() ===
|
||||||
|
'TRUE';
|
||||||
|
core.debug(`allow unsafe PR checkout = ${result.allowUnsafePrCheckout}`);
|
||||||
|
unsafePrCheckoutHelper.assertSafePrCheckout({
|
||||||
|
qualifiedRepository,
|
||||||
|
ref: result.ref,
|
||||||
|
commit: result.commit,
|
||||||
|
allowUnsafePrCheckout: result.allowUnsafePrCheckout
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -2284,6 +2304,7 @@ exports.getRefSpecForAllHistory = getRefSpecForAllHistory;
|
||||||
exports.getRefSpec = getRefSpec;
|
exports.getRefSpec = getRefSpec;
|
||||||
exports.testRef = testRef;
|
exports.testRef = testRef;
|
||||||
exports.checkCommitInfo = checkCommitInfo;
|
exports.checkCommitInfo = checkCommitInfo;
|
||||||
|
exports.fromPayload = fromPayload;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const github = __importStar(__nccwpck_require__(5438));
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
const url_helper_1 = __nccwpck_require__(9437);
|
const url_helper_1 = __nccwpck_require__(9437);
|
||||||
|
|
@ -2732,6 +2753,105 @@ if (!exports.IsPost) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 843:
|
||||||
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.assertSafePrCheckout = assertSafePrCheckout;
|
||||||
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
|
const ref_helper_1 = __nccwpck_require__(8601);
|
||||||
|
const PR_REF_PATTERN = /^refs\/pull\/[0-9]+\/(?:head|merge)$/;
|
||||||
|
function assertSafePrCheckout(input) {
|
||||||
|
if (input.allowUnsafePrCheckout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const eventName = github.context.eventName;
|
||||||
|
if (eventName !== 'pull_request_target' && eventName !== 'workflow_run') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const baseRepoId = (0, ref_helper_1.fromPayload)('repository.id');
|
||||||
|
if (typeof baseRepoId !== 'number') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let prHeadRepoId;
|
||||||
|
let prHeadRepoFullName;
|
||||||
|
const prShas = [];
|
||||||
|
if (eventName === 'pull_request_target') {
|
||||||
|
prHeadRepoId = (0, ref_helper_1.fromPayload)('pull_request.head.repo.id');
|
||||||
|
prHeadRepoFullName = (0, ref_helper_1.fromPayload)('pull_request.head.repo.full_name');
|
||||||
|
pushIfSha(prShas, (0, ref_helper_1.fromPayload)('pull_request.head.sha'));
|
||||||
|
pushIfSha(prShas, (0, ref_helper_1.fromPayload)('pull_request.merge_commit_sha'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const wrEvent = (0, ref_helper_1.fromPayload)('workflow_run.event');
|
||||||
|
if (typeof wrEvent !== 'string' || !wrEvent.startsWith('pull_request')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prHeadRepoId = (0, ref_helper_1.fromPayload)('workflow_run.head_repository.id');
|
||||||
|
prHeadRepoFullName = (0, ref_helper_1.fromPayload)('workflow_run.head_repository.full_name');
|
||||||
|
pushIfSha(prShas, (0, ref_helper_1.fromPayload)('workflow_run.head_commit.id'));
|
||||||
|
// For `pull_request_target`-triggered workflow_run, `head_sha` is the base
|
||||||
|
// default branch SHA (not the PR head)
|
||||||
|
if (wrEvent !== 'pull_request_target') {
|
||||||
|
pushIfSha(prShas, (0, ref_helper_1.fromPayload)('workflow_run.head_sha'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (A) Fork PR?
|
||||||
|
if (typeof prHeadRepoId !== 'number' || prHeadRepoId === baseRepoId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// (B) We cannot check for all fork PR refs so check to see
|
||||||
|
// if the resolved input points to the fork PR sha we have in the payload
|
||||||
|
const repositoryMatchesPrHead = typeof prHeadRepoFullName === 'string' &&
|
||||||
|
input.qualifiedRepository.toLowerCase() === prHeadRepoFullName.toLowerCase();
|
||||||
|
const refMatchesPullPattern = PR_REF_PATTERN.test(input.ref);
|
||||||
|
const commitMatchesPrHeadSha = !!input.commit && prShas.includes(input.commit.toLowerCase());
|
||||||
|
if (!repositoryMatchesPrHead &&
|
||||||
|
!refMatchesPullPattern &&
|
||||||
|
!commitMatchesPrHeadSha) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(`Refusing to check out fork pull request code from a '${eventName}' workflow. ` +
|
||||||
|
`This workflow runs with the base repository's GITHUB_TOKEN, secrets, default-branch ` +
|
||||||
|
`cache scope, and runner access. Fetching and executing a fork's code in that trusted ` +
|
||||||
|
`context commonly leads to "pwn request" vulnerabilities. To opt in after reviewing ` +
|
||||||
|
`the risks at https://gh.io/securely-using-pull_request_target, set ` +
|
||||||
|
`'allow-unsafe-pr-checkout: true' on the actions/checkout step.`);
|
||||||
|
}
|
||||||
|
function pushIfSha(target, value) {
|
||||||
|
if (typeof value === 'string' && value.length > 0) {
|
||||||
|
target.push(value.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 9437:
|
/***/ 9437:
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,11 @@ export interface IGitCommandManager {
|
||||||
shaExists(sha: string): Promise<boolean>
|
shaExists(sha: string): Promise<boolean>
|
||||||
submoduleForeach(command: string, recursive: boolean): Promise<string>
|
submoduleForeach(command: string, recursive: boolean): Promise<string>
|
||||||
submoduleSync(recursive: boolean): Promise<void>
|
submoduleSync(recursive: boolean): Promise<void>
|
||||||
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
|
submoduleUpdate(
|
||||||
|
fetchDepth: number,
|
||||||
|
recursive: boolean,
|
||||||
|
submoduleDirectories: string[]
|
||||||
|
): Promise<void>
|
||||||
submoduleStatus(): Promise<boolean>
|
submoduleStatus(): Promise<boolean>
|
||||||
tagExists(pattern: string): Promise<boolean>
|
tagExists(pattern: string): Promise<boolean>
|
||||||
tryClean(): Promise<boolean>
|
tryClean(): Promise<boolean>
|
||||||
|
|
@ -452,9 +456,19 @@ class GitCommandManager {
|
||||||
await this.execGit(args)
|
await this.execGit(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
async submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void> {
|
async submoduleUpdate(
|
||||||
|
fetchDepth: number,
|
||||||
|
recursive: boolean,
|
||||||
|
submoduleDirectories: string[]
|
||||||
|
): Promise<void> {
|
||||||
const args = ['-c', 'protocol.version=2']
|
const args = ['-c', 'protocol.version=2']
|
||||||
args.push('submodule', 'update', '--init', '--force')
|
args.push(
|
||||||
|
'submodule',
|
||||||
|
'update',
|
||||||
|
'--init',
|
||||||
|
'--force',
|
||||||
|
...submoduleDirectories
|
||||||
|
)
|
||||||
if (fetchDepth > 0) {
|
if (fetchDepth > 0) {
|
||||||
args.push(`--depth=${fetchDepth}`)
|
args.push(`--depth=${fetchDepth}`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,11 @@ 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(settings.fetchDepth, settings.nestedSubmodules)
|
await git.submoduleUpdate(
|
||||||
|
settings.fetchDepth,
|
||||||
|
settings.nestedSubmodules,
|
||||||
|
settings.submoduleDirectories
|
||||||
|
)
|
||||||
await git.submoduleForeach(
|
await git.submoduleForeach(
|
||||||
'git config --local gc.auto 0',
|
'git config --local gc.auto 0',
|
||||||
settings.nestedSubmodules
|
settings.nestedSubmodules
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,11 @@ export interface IGitSourceSettings {
|
||||||
*/
|
*/
|
||||||
nestedSubmodules: boolean
|
nestedSubmodules: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates which submodule paths to checkout
|
||||||
|
*/
|
||||||
|
submoduleDirectories: string[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The auth token to use when fetching the repository
|
* The auth token to use when fetching the repository
|
||||||
*/
|
*/
|
||||||
|
|
@ -118,4 +123,10 @@ export interface IGitSourceSettings {
|
||||||
* User override on the GitHub Server/Host URL that hosts the repository to be cloned
|
* User override on the GitHub Server/Host URL that hosts the repository to be cloned
|
||||||
*/
|
*/
|
||||||
githubServerUrl: string | undefined
|
githubServerUrl: string | undefined
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opt-in to allow checking out fork pull request code from a workflow
|
||||||
|
* triggered by pull_request_target or workflow_run.
|
||||||
|
*/
|
||||||
|
allowUnsafePrCheckout: boolean
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import * as core from '@actions/core'
|
||||||
import * as fsHelper from './fs-helper'
|
import * as fsHelper from './fs-helper'
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
import * as unsafePrCheckoutHelper from './unsafe-pr-checkout-helper'
|
||||||
import * as workflowContextHelper from './workflow-context-helper'
|
import * as workflowContextHelper from './workflow-context-helper'
|
||||||
import {IGitSourceSettings} from './git-source-settings'
|
import {IGitSourceSettings} from './git-source-settings'
|
||||||
|
|
||||||
|
|
@ -125,6 +126,7 @@ export async function getInputs(): Promise<IGitSourceSettings> {
|
||||||
// Submodules
|
// Submodules
|
||||||
result.submodules = false
|
result.submodules = false
|
||||||
result.nestedSubmodules = false
|
result.nestedSubmodules = false
|
||||||
|
result.submoduleDirectories = []
|
||||||
const submodulesString = (core.getInput('submodules') || '').toUpperCase()
|
const submodulesString = (core.getInput('submodules') || '').toUpperCase()
|
||||||
if (submodulesString == 'RECURSIVE') {
|
if (submodulesString == 'RECURSIVE') {
|
||||||
result.submodules = true
|
result.submodules = true
|
||||||
|
|
@ -132,9 +134,16 @@ export async function getInputs(): Promise<IGitSourceSettings> {
|
||||||
} else if (submodulesString == 'TRUE') {
|
} else if (submodulesString == 'TRUE') {
|
||||||
result.submodules = true
|
result.submodules = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const submoduleDirectories = core.getMultilineInput('submodule-directories')
|
||||||
|
if (submoduleDirectories.length > 0) {
|
||||||
|
result.submoduleDirectories = submoduleDirectories
|
||||||
|
if (!result.submodules) result.submodules = true
|
||||||
|
}
|
||||||
|
|
||||||
core.debug(`submodules = ${result.submodules}`)
|
core.debug(`submodules = ${result.submodules}`)
|
||||||
core.debug(`recursive submodules = ${result.nestedSubmodules}`)
|
core.debug(`recursive submodules = ${result.nestedSubmodules}`)
|
||||||
|
core.debug(`submodule directories = ${result.submoduleDirectories}`)
|
||||||
// Auth token
|
// Auth token
|
||||||
result.authToken = core.getInput('token', {required: true})
|
result.authToken = core.getInput('token', {required: true})
|
||||||
|
|
||||||
|
|
@ -161,5 +170,18 @@ export async function getInputs(): Promise<IGitSourceSettings> {
|
||||||
result.githubServerUrl = core.getInput('github-server-url')
|
result.githubServerUrl = core.getInput('github-server-url')
|
||||||
core.debug(`GitHub Host URL = ${result.githubServerUrl}`)
|
core.debug(`GitHub Host URL = ${result.githubServerUrl}`)
|
||||||
|
|
||||||
|
// Allow unsafe PR checkout (opt-in for pull_request_target / workflow_run fork PRs)
|
||||||
|
result.allowUnsafePrCheckout =
|
||||||
|
(core.getInput('allow-unsafe-pr-checkout') || 'false').toUpperCase() ===
|
||||||
|
'TRUE'
|
||||||
|
core.debug(`allow unsafe PR checkout = ${result.allowUnsafePrCheckout}`)
|
||||||
|
|
||||||
|
unsafePrCheckoutHelper.assertSafePrCheckout({
|
||||||
|
qualifiedRepository,
|
||||||
|
ref: result.ref,
|
||||||
|
commit: result.commit,
|
||||||
|
allowUnsafePrCheckout: result.allowUnsafePrCheckout
|
||||||
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ export async function checkCommitInfo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fromPayload(path: string): any {
|
export function fromPayload(path: string): any {
|
||||||
return select(github.context.payload, path)
|
return select(github.context.payload, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import {fromPayload} from './ref-helper'
|
||||||
|
|
||||||
|
const PR_REF_PATTERN = /^refs\/pull\/[0-9]+\/(?:head|merge)$/
|
||||||
|
|
||||||
|
export interface IUnsafePrCheckoutInput {
|
||||||
|
qualifiedRepository: string
|
||||||
|
ref: string
|
||||||
|
commit: string | undefined
|
||||||
|
allowUnsafePrCheckout: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertSafePrCheckout(input: IUnsafePrCheckoutInput): void {
|
||||||
|
if (input.allowUnsafePrCheckout) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventName = github.context.eventName
|
||||||
|
if (eventName !== 'pull_request_target' && eventName !== 'workflow_run') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseRepoId = fromPayload('repository.id')
|
||||||
|
if (typeof baseRepoId !== 'number') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let prHeadRepoId: unknown
|
||||||
|
let prHeadRepoFullName: unknown
|
||||||
|
const prShas: string[] = []
|
||||||
|
|
||||||
|
if (eventName === 'pull_request_target') {
|
||||||
|
prHeadRepoId = fromPayload('pull_request.head.repo.id')
|
||||||
|
prHeadRepoFullName = fromPayload('pull_request.head.repo.full_name')
|
||||||
|
pushIfSha(prShas, fromPayload('pull_request.head.sha'))
|
||||||
|
pushIfSha(prShas, fromPayload('pull_request.merge_commit_sha'))
|
||||||
|
} else {
|
||||||
|
const wrEvent = fromPayload('workflow_run.event')
|
||||||
|
if (typeof wrEvent !== 'string' || !wrEvent.startsWith('pull_request')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
prHeadRepoId = fromPayload('workflow_run.head_repository.id')
|
||||||
|
prHeadRepoFullName = fromPayload('workflow_run.head_repository.full_name')
|
||||||
|
pushIfSha(prShas, fromPayload('workflow_run.head_commit.id'))
|
||||||
|
// For `pull_request_target`-triggered workflow_run, `head_sha` is the base
|
||||||
|
// default branch SHA (not the PR head)
|
||||||
|
if (wrEvent !== 'pull_request_target') {
|
||||||
|
pushIfSha(prShas, fromPayload('workflow_run.head_sha'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (A) Fork PR?
|
||||||
|
if (typeof prHeadRepoId !== 'number' || prHeadRepoId === baseRepoId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// (B) We cannot check for all fork PR refs so check to see
|
||||||
|
// if the resolved input points to the fork PR sha we have in the payload
|
||||||
|
const repositoryMatchesPrHead =
|
||||||
|
typeof prHeadRepoFullName === 'string' &&
|
||||||
|
input.qualifiedRepository.toLowerCase() === prHeadRepoFullName.toLowerCase()
|
||||||
|
const refMatchesPullPattern = PR_REF_PATTERN.test(input.ref)
|
||||||
|
const commitMatchesPrHeadSha =
|
||||||
|
!!input.commit && prShas.includes(input.commit.toLowerCase())
|
||||||
|
|
||||||
|
if (
|
||||||
|
!repositoryMatchesPrHead &&
|
||||||
|
!refMatchesPullPattern &&
|
||||||
|
!commitMatchesPrHeadSha
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Refusing to check out fork pull request code from a '${eventName}' workflow. ` +
|
||||||
|
`This workflow runs with the base repository's GITHUB_TOKEN, secrets, default-branch ` +
|
||||||
|
`cache scope, and runner access. Fetching and executing a fork's code in that trusted ` +
|
||||||
|
`context commonly leads to "pwn request" vulnerabilities. To opt in after reviewing ` +
|
||||||
|
`the risks at https://gh.io/securely-using-pull_request_target, set ` +
|
||||||
|
`'allow-unsafe-pr-checkout: true' on the actions/checkout step.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushIfSha(target: string[], value: unknown): void {
|
||||||
|
if (typeof value === 'string' && value.length > 0) {
|
||||||
|
target.push(value.toLowerCase())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue