mirror of https://github.com/actions/checkout
Compare commits
3 Commits
def8c478f1
...
91bf996e2f
| Author | SHA1 | Date |
|---|---|---|
|
|
91bf996e2f | |
|
|
62661c4e71 | |
|
|
38cc68387c |
|
|
@ -180,4 +180,50 @@ 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)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('unsafe PR checkout guard', () => {
|
||||||
|
const forkPayload = {
|
||||||
|
repository: {id: 100},
|
||||||
|
pull_request: {
|
||||||
|
head: {
|
||||||
|
sha: '1234567890123456789012345678901234567890',
|
||||||
|
repo: {id: 200, full_name: 'attacker/fork'}
|
||||||
|
},
|
||||||
|
merge_commit_sha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('allows the default self-checkout on a fork pull_request_target', async () => {
|
||||||
|
const originalEvent = mockGithubContext.eventName
|
||||||
|
const originalPayload = mockGithubContext.payload
|
||||||
|
try {
|
||||||
|
mockGithubContext.eventName = 'pull_request_target'
|
||||||
|
mockGithubContext.payload = forkPayload
|
||||||
|
// Simulate a rebase/fast-forward merge where the base tip (event SHA)
|
||||||
|
// equals the PR head SHA. The default self-checkout must still succeed.
|
||||||
|
mockGithubContext.sha = '1234567890123456789012345678901234567890'
|
||||||
|
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
||||||
|
expect(settings.commit).toBe('1234567890123456789012345678901234567890')
|
||||||
|
} finally {
|
||||||
|
mockGithubContext.eventName = originalEvent
|
||||||
|
mockGithubContext.payload = originalPayload
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('refuses an explicit fork repository on pull_request_target', async () => {
|
||||||
|
const originalEvent = mockGithubContext.eventName
|
||||||
|
const originalPayload = mockGithubContext.payload
|
||||||
|
try {
|
||||||
|
mockGithubContext.eventName = 'pull_request_target'
|
||||||
|
mockGithubContext.payload = forkPayload
|
||||||
|
inputs.repository = 'attacker/fork'
|
||||||
|
await expect(inputHelper.getInputs()).rejects.toThrow(
|
||||||
|
/Refusing to check out fork pull request code/
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
mockGithubContext.eventName = originalEvent
|
||||||
|
mockGithubContext.payload = originalPayload
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -42191,12 +42191,19 @@ async function getInputs() {
|
||||||
(getInput('allow-unsafe-pr-checkout') || 'false').toUpperCase() ===
|
(getInput('allow-unsafe-pr-checkout') || 'false').toUpperCase() ===
|
||||||
'TRUE';
|
'TRUE';
|
||||||
core_debug(`allow unsafe PR checkout = ${result.allowUnsafePrCheckout}`);
|
core_debug(`allow unsafe PR checkout = ${result.allowUnsafePrCheckout}`);
|
||||||
assertSafePrCheckout({
|
// The default self-checkout (this repository with no explicit ref) always
|
||||||
qualifiedRepository,
|
// resolves to the trusted ref/commit GitHub set for the triggering event, so
|
||||||
ref: result.ref,
|
// the fork-checkout guard only needs to run when the caller customized the
|
||||||
commit: result.commit,
|
// repository or ref.
|
||||||
allowUnsafePrCheckout: result.allowUnsafePrCheckout
|
const isDefaultCheckout = isWorkflowRepository && !getInput('ref');
|
||||||
});
|
if (!isDefaultCheckout) {
|
||||||
|
assertSafePrCheckout({
|
||||||
|
qualifiedRepository,
|
||||||
|
ref: result.ref,
|
||||||
|
commit: result.commit,
|
||||||
|
allowUnsafePrCheckout: result.allowUnsafePrCheckout
|
||||||
|
});
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ export interface IGitCommandManager {
|
||||||
getWorkingDirectory(): string
|
getWorkingDirectory(): string
|
||||||
init(objectFormat?: string): Promise<void>
|
init(objectFormat?: string): Promise<void>
|
||||||
isDetached(): Promise<boolean>
|
isDetached(): Promise<boolean>
|
||||||
|
lfsCheckout(): Promise<void>
|
||||||
lfsFetch(ref: string): Promise<void>
|
lfsFetch(ref: string): Promise<void>
|
||||||
lfsInstall(): Promise<void>
|
lfsInstall(): Promise<void>
|
||||||
log1(format?: string): Promise<string>
|
log1(format?: string): Promise<string>
|
||||||
|
|
@ -383,6 +384,10 @@ class GitCommandManager {
|
||||||
return !output.stdout.trim().startsWith('refs/heads/')
|
return !output.stdout.trim().startsWith('refs/heads/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async lfsCheckout(): Promise<void> {
|
||||||
|
await this.execGit(['lfs', 'checkout'])
|
||||||
|
}
|
||||||
|
|
||||||
async lfsFetch(ref: string): Promise<void> {
|
async lfsFetch(ref: string): Promise<void> {
|
||||||
const args = ['lfs', 'fetch', 'origin', ref]
|
const args = ['lfs', 'fetch', 'origin', ref]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,11 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
||||||
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
|
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
|
|
||||||
|
// LFS checkout
|
||||||
|
core.startGroup('Checking out LFS objects')
|
||||||
|
await git.lfsCheckout()
|
||||||
|
core.endGroup()
|
||||||
|
|
||||||
// Submodules
|
// Submodules
|
||||||
if (settings.submodules) {
|
if (settings.submodules) {
|
||||||
// Temporarily override global config
|
// Temporarily override global config
|
||||||
|
|
|
||||||
|
|
@ -168,12 +168,19 @@ export async function getInputs(): Promise<IGitSourceSettings> {
|
||||||
'TRUE'
|
'TRUE'
|
||||||
core.debug(`allow unsafe PR checkout = ${result.allowUnsafePrCheckout}`)
|
core.debug(`allow unsafe PR checkout = ${result.allowUnsafePrCheckout}`)
|
||||||
|
|
||||||
unsafePrCheckoutHelper.assertSafePrCheckout({
|
// The default self-checkout (this repository with no explicit ref) always
|
||||||
qualifiedRepository,
|
// resolves to the trusted ref/commit GitHub set for the triggering event, so
|
||||||
ref: result.ref,
|
// the fork-checkout guard only needs to run when the caller customized the
|
||||||
commit: result.commit,
|
// repository or ref.
|
||||||
allowUnsafePrCheckout: result.allowUnsafePrCheckout
|
const isDefaultCheckout = isWorkflowRepository && !core.getInput('ref')
|
||||||
})
|
if (!isDefaultCheckout) {
|
||||||
|
unsafePrCheckoutHelper.assertSafePrCheckout({
|
||||||
|
qualifiedRepository,
|
||||||
|
ref: result.ref,
|
||||||
|
commit: result.commit,
|
||||||
|
allowUnsafePrCheckout: result.allowUnsafePrCheckout
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue