Skip to content

fix(ci): use pull_request_target in readme-pr-check so fork PRs work#3840

Open
yoryocoruxo-ai wants to merge 1 commit intomodelcontextprotocol:mainfrom
yoryocoruxo-ai:fix/readme-pr-check-fork-permissions
Open

fix(ci): use pull_request_target in readme-pr-check so fork PRs work#3840
yoryocoruxo-ai wants to merge 1 commit intomodelcontextprotocol:mainfrom
yoryocoruxo-ai:fix/readme-pr-check-fork-permissions

Conversation

@yoryocoruxo-ai
Copy link
Copy Markdown

@yoryocoruxo-ai yoryocoruxo-ai commented Apr 5, 2026

Summary

The README PR Check workflow is currently failing on every PR opened from a fork (which is the vast majority of contributions to this repo). Example failed runs from the last couple of days: #24010860831, #24010684932, #24007350839, #24003674827, and many more — the full list on the workflow page shows the pattern: anything from a fork is red, only the one internal-branch run is green.

All of them fail the same way:

HttpError: Resource not accessible by integration
POST /repos/modelcontextprotocol/servers/issues/{n}/labels
status: 403
x-accepted-github-permissions: issues=write; pull_requests=write

Root cause

The workflow triggers on pull_request. When a pull_request event comes from a fork, the GITHUB_TOKEN is read-only regardless of the permissions: block in the job — that is the documented GitHub Actions security model. So addLabels / createComment can never succeed for the 99% case this workflow was written for.

Fix

  1. Switch the trigger to pull_request_target. This runs the workflow in the context of the base repo, so the permissions: block is actually honored and the token can write labels/comments.
  2. Add issues: write next to pull-requests: write, since addLabels and createComment both hit the /issues/ endpoint (the 403 response header even tells us: x-accepted-github-permissions: issues=write; pull_requests=write).
  3. Update the if: guard on check-readme-only to match the new event name.

Why pull_request_target is safe here

pull_request_target is normally dangerous because it runs with write privileges against github.event.pull_request.head.ref — i.e. attacker-controlled code. This workflow never does a checkout and never executes anything from the PR. It only calls octokit (pulls.listFiles, issues.addLabels, issues.createComment) which read metadata and write labels/comments. There is no code-execution surface from the fork.

Test plan

  • Merge and confirm the next fork PR against README.md gets labeled readme: pending and commented instead of erroring
  • Confirm /i-promise-this-is-not-a-new-server still swaps labels correctly (the handle-confirmation job was already fine — it runs on issue_comment which doesn't have the fork-token problem — but I added issues: write there too for consistency since it calls addLabels / removeLabel)
  • Confirm non-README PRs are still skipped (the files.length !== 1 || files[0].filename !== 'README.md' check is unchanged)

The README PR Check workflow triggers on 'pull_request', which gives the
GITHUB_TOKEN read-only permissions when the PR comes from a fork. This
caused every fork PR (the vast majority) to fail with:

  HttpError: Resource not accessible by integration (403)
  POST /repos/.../issues/{n}/labels

Switch to 'pull_request_target' so the workflow runs in the base repo
context with the permissions declared in the job. This is safe here
because the workflow never checks out PR code — it only calls the GitHub
REST/GraphQL API to add a label and post a comment.

Also add 'issues: write' alongside 'pull-requests: write' since
addLabels/createComment use the issues endpoint internally.
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