diff --git a/.github/scripts/pr-labeler.test.cjs b/.github/scripts/pr-labeler.test.cjs index 71afd7836c..1c61937542 100644 --- a/.github/scripts/pr-labeler.test.cjs +++ b/.github/scripts/pr-labeler.test.cjs @@ -165,8 +165,15 @@ describe("pr-labeler workflow", () => { it("keeps trusted default-branch checkout, concurrency cancel, and minimal permissions", () => { assert.match(workflow, /ref:\s*\$\{\{\s*github\.event\.repository\.default_branch\s*\}\}/); assert.match(workflow, /cancel-in-progress:\s*true/); - assert.match(workflow, /pull-requests:\s*read/); assert.match(workflow, /issues:\s*write/); - assert.doesNotMatch(workflow, /pull-requests:\s*write/); + // The issues label endpoints are shared with pull requests: writing a label + // onto a PR number needs pull_requests=write alongside issues=write, which + // GitHub reports as `issues=write; pull_requests=write`. Pinning this to + // read made the workflow fail closed on the first PR that actually needed a + // label applied (#565), so write is the minimum here, not an escalation. + assert.match(workflow, /pull-requests:\s*write/); + // contents stays read — the labeler never pushes. + assert.match(workflow, /contents:\s*read/); + assert.doesNotMatch(workflow, /contents:\s*write/); }); }); diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 8bc529b51f..348620fca7 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -17,8 +17,14 @@ concurrency: permissions: contents: read - # pulls.get only needs read; label mutations use the issues API. - pull-requests: read + # pulls.get only needs read, but the issues label endpoints are shared with + # pull requests: adding or removing a label on a PR number is rejected with + # "Resource not accessible by integration" unless the token also carries + # pull_requests=write (the API reports `issues=write; pull_requests=write` + # in x-accepted-github-permissions). Read-only here silently worked while + # every run happened to be a no-op sync, and failed on the first PR that + # actually needed a label written. + pull-requests: write issues: write jobs: