mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(ci): run PR LoC scripts from the default branch, not PR head (#15016)
The PR test LoC job fetched .github/scripts/pr-test-loc-*.mjs from pull/<n>/head and ran them with node while holding a GITHUB_TOKEN scoped pull-requests: write, so PR-authored code executed under a write token. Pin the fetch to the repository default branch. base.sha is not enough: for stacked PRs it is an unreviewed feature-branch commit any collaborator can push to, while main is gated by branch protection. Also pass event data via env instead of shell interpolation, and add set -euo pipefail so a failed download cannot leave a truncated script.
This commit is contained in:
@@ -15,6 +15,11 @@ import {
|
||||
|
||||
const projectDir = resolve(import.meta.dirname, '../..')
|
||||
const locScript = join(projectDir, '.github/scripts/pr-test-loc-summary.mjs')
|
||||
const locWorkflow = parse(
|
||||
readFileSync(join(projectDir, '.github/workflows/pr-test-loc.yml'), 'utf8')
|
||||
)
|
||||
const locJob = locWorkflow.jobs.loc
|
||||
const locStep = locJob.steps[0]
|
||||
const tempDirs = []
|
||||
|
||||
function runLoc(args, { env } = {}) {
|
||||
@@ -178,20 +183,36 @@ describe('PR test LoC summary', () => {
|
||||
})
|
||||
|
||||
it('is a no-checkout GitHub-hosted PR workflow', () => {
|
||||
const workflow = parse(
|
||||
readFileSync(join(projectDir, '.github/workflows/pr-test-loc.yml'), 'utf8')
|
||||
)
|
||||
const locJob = workflow.jobs.loc
|
||||
const serialized = JSON.stringify(workflow)
|
||||
|
||||
expect(locJob['runs-on']).toBe('ubuntu-latest')
|
||||
expect(locJob.steps).toHaveLength(1)
|
||||
expect(locJob.steps[0].run).toContain('gh api')
|
||||
expect(locJob.steps[0].run).toContain('pr-test-loc-table.mjs')
|
||||
expect(locJob.steps[0].run).toContain('pr-test-loc-summary.mjs')
|
||||
expect(locJob.steps[0].run).toContain('--update-pr')
|
||||
expect(workflow.permissions['pull-requests']).toBe('write')
|
||||
expect(serialized).not.toContain('actions/checkout')
|
||||
expect(serialized).not.toContain('self-hosted')
|
||||
expect(locStep.run).toContain('gh api')
|
||||
expect(locStep.run).toContain('pr-test-loc-table.mjs')
|
||||
expect(locStep.run).toContain('pr-test-loc-summary.mjs')
|
||||
expect(locStep.run).toContain('--update-pr')
|
||||
expect(locWorkflow.permissions['pull-requests']).toBe('write')
|
||||
expect(JSON.stringify(locWorkflow)).not.toContain('actions/checkout')
|
||||
expect(JSON.stringify(locWorkflow)).not.toContain('self-hosted')
|
||||
})
|
||||
|
||||
// The write-scoped GITHUB_TOKEN makes any PR-authored code a privilege escalation.
|
||||
it('executes only default-branch script code, never pull-request head code', () => {
|
||||
const serialized = JSON.stringify(locWorkflow)
|
||||
|
||||
expect(locStep.env.TRUSTED_REF).toBe('${{ github.event.repository.default_branch }}')
|
||||
expect(locStep.run).toContain('?ref=${TRUSTED_REF}')
|
||||
expect(serialized).not.toContain('pull_request_target')
|
||||
expect(serialized).not.toContain('pull/')
|
||||
expect(serialized).not.toContain('pull_request.head')
|
||||
expect(serialized).not.toContain('/merge')
|
||||
})
|
||||
|
||||
it('passes event data through env instead of interpolating it into the shell', () => {
|
||||
expect(locStep.env.PR_NUMBER).toBe('${{ github.event.pull_request.number }}')
|
||||
expect(locStep.run).toContain('--update-pr "$PR_NUMBER"')
|
||||
expect(locStep.run).not.toContain('${{')
|
||||
})
|
||||
|
||||
it('fails the step when a script download fails instead of running a truncated file', () => {
|
||||
expect(locStep.run).toContain('set -euo pipefail')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user