Skip to content

fix(ci): let the PR labeler actually write labels - #566

Merged
lidge-jun merged 2 commits into
devfrom
codex/pr-labeler-pulls-write
Jul 27, 2026
Merged

fix(ci): let the PR labeler actually write labels#566
lidge-jun merged 2 commits into
devfrom
codex/pr-labeler-pulls-write

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Problem

The PR Labeler workflow fails with a 403 whenever it actually needs to write a label:

##[error]Unhandled error: HttpError: Resource not accessible by integration
POST /repos/lidge-jun/opencodex/issues/565/labels
body: {"labels":["enhancement"]}

Observed on #565 (runs 30292169466 and 30292826165).

Cause

The job token was granted exactly what the workflow asked for:

Contents: read
Issues: write
Metadata: read
PullRequests: read

But GitHub's own rejection names a wider requirement:

x-accepted-github-permissions: 'issues=write; pull_requests=write'

The issues label endpoints are shared with pull requests. Writing a label onto a
PR number needs pull_requests=write as well, so pull-requests: read cannot
satisfy POST /issues/{number}/labels even with issues: write.

This stayed invisible because almost every run is a no-op: the title already
matches the current label, planTypeLabelSync returns a skip, and no write is
attempted. Runs on #512, #447, and #528 all "passed" this way. #565 was the
first PR in a while that genuinely needed a label applied, so it was the first
to surface the misconfiguration.

Fix

Raise pull-requests to write in the workflow's top-level permissions, with a
comment recording why the read-only value looked sufficient but is not.

No script or logic change: planTypeLabelSync and the sticky human-override
behaviour are untouched, so the labeler still refuses to overwrite a maintainer's
manual type label.

Note on scope

This is a workflow permission increase, so it falls under the security-review
boundary in MAINTAINERS.md. The added scope is the minimum the API demands for
the write the workflow already performs; it grants no new capability beyond
label mutation on pull requests.

pull_request_target workflows load from the default branch (main), so this
does not take effect on live PRs until it is promoted there.

Verification

  • pre-push bun scripts/test.ts → 5070 pass / 0 fail
  • bun run privacy:scan → pass

Summary by CodeRabbit

  • Bug Fixes
    • Updated the pull request labeling workflow to request the correct permission level so label updates succeed reliably.
  • Tests
    • Adjusted the workflow test coverage to match the new permission expectations, including validation that content access remains read-only.
  • Chores
    • Added clarifying inline documentation explaining why the workflow needs write access for label mutations.

@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner July 27, 2026 18:23
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request labeler workflow now requests pull-requests: write, documents the requirement for label mutations, and updates permission tests to verify write access while keeping contents read-only.

Changes

Pull request labeler permissions

Layer / File(s) Summary
Enable pull request label mutations
.github/workflows/pr-labeler.yml, .github/scripts/pr-labeler.test.cjs
Changes pull-requests permission from read to write, updates the explanatory comments, and verifies issues: write, pull-requests: write, and contents: read without contents: write.

Estimated code review effort: 1 (Trivial) | ~3 minutes

Possibly related PRs

Suggested labels: bug

Suggested reviewers: ingwannu, wibias

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: enabling the PR labeler workflow to write labels by raising pull-requests permission to write.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/pr-labeler-pulls-write

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/pr-labeler.yml:
- Around line 20-27: Move the pull-requests: write permission from
workflow-level permissions into only the job invoking addLabels, removeLabel,
and createLabel. Keep unrelated jobs read-only or without this permission,
preserving the labeler job’s ability to mutate labels.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 37b5db43-0c11-464d-a2ec-415ff96c79aa

📥 Commits

Reviewing files that changed from the base of the PR and between f348166 and 9933017.

📒 Files selected for processing (1)
  • .github/workflows/pr-labeler.yml

Comment on lines +20 to +27
# 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scope pull-requests: write to the labeler job.

The write permission is required for the label mutations, but granting it at workflow scope gives every job and future step a token capable of modifying pull requests. Move this permission under only the job that calls addLabels, removeLabel, and createLabel, while keeping unrelated jobs read-only or without the permission.

Proposed fix
 permissions:
-  pull-requests: write

 jobs:
   <labeler-job>:
+    permissions:
+      pull-requests: write
🧰 Tools
🪛 zizmor (1.26.1)

[error] 27-27: overly broad permissions (excessive-permissions): pull-requests: write is overly broad at the workflow level

(excessive-permissions)


[warning] 27-27: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment

(undocumented-permissions)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pr-labeler.yml around lines 20 - 27, Move the
pull-requests: write permission from workflow-level permissions into only the
job invoking addLabels, removeLabel, and createLabel. Keep unrelated jobs
read-only or without this permission, preserving the labeler job’s ability to
mutate labels.

Sources: Path instructions, Linters/SAST tools

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9933017e0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the minimal-permissions regression test

Changing this permission to write leaves .github/scripts/pr-labeler.test.cjs:165-170 explicitly requiring pull-requests: read and rejecting pull-requests: write. The checked .github/workflows/issue-quality-tests.yml is path-triggered by this workflow and runs that test, so node --test .github/scripts/pr-labeler.test.cjs now fails. Update the regression test to expect the intentional write permission; otherwise this change cannot get green CI.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/pr-labeler.test.cjs:
- Around line 174-177: Update the workflow permission assertions in the relevant
test to inspect the effective top-level permissions map rather than matching
arbitrary YAML text. Parse the workflow or isolate its top-level permissions
block, then assert exactly contents: read, pull-requests: write, and issues:
write, while rejecting contents: write; do not rely on comments or job-level
permissions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1e450641-fffc-4922-88d9-969075b4789f

📥 Commits

Reviewing files that changed from the base of the PR and between 9933017 and 8efa677.

📒 Files selected for processing (1)
  • .github/scripts/pr-labeler.test.cjs

Comment on lines +174 to +177
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/);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Assert the effective top-level permissions map, not arbitrary workflow text.

The unanchored regexes search the entire YAML document, so a comment or unrelated job-level block could satisfy pull-requests: write and contents: read without proving the labeler job receives those permissions. Conversely, an unrelated contents: write occurrence could fail the test. Parse the workflow or extract its top-level permissions block and assert the exact contract: contents: read, pull-requests: write, and issues: write, with no contents: write.

As per path instructions, .github/** is a security boundary and workflow permission changes require explicit security review.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/pr-labeler.test.cjs around lines 174 - 177, Update the
workflow permission assertions in the relevant test to inspect the effective
top-level permissions map rather than matching arbitrary YAML text. Parse the
workflow or isolate its top-level permissions block, then assert exactly
contents: read, pull-requests: write, and issues: write, while rejecting
contents: write; do not rely on comments or job-level permissions.

Source: Path instructions

@lidge-jun
lidge-jun merged commit 5f76d58 into dev Jul 27, 2026
5 of 7 checks passed
lidge-jun added a commit that referenced this pull request Jul 27, 2026
* fix(ci): let the PR labeler actually write labels

* test(ci): pin the labeler to the permissions the API demands
lidge-jun added a commit that referenced this pull request Jul 27, 2026
* fix(ci): let the PR labeler actually write labels

* test(ci): pin the labeler to the permissions the API demands
@lidge-jun
lidge-jun deleted the codex/pr-labeler-pulls-write branch July 27, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant