Skip to content

examples/claude-code-review.yml: dispatch-on-comment reads a PR without declaring pull-requests: read #612

Description

@d-morrison

Summary

examples/claude-code-review.yml's dispatch-on-comment job declares two permission scopes and then reads a pull request, which needs a third it does not declare.

    permissions:
      actions: write        # dispatch this workflow via `gh workflow run`
      issues: write         # acknowledge the /review comment

The step below it does:

          PR_JSON=$(gh api "repos/$REPO/pulls/$PR_NUMBER")
          PR_BRANCH=$(jq -r '.head.ref' <<< "$PR_JSON")
          PR_HEAD_REPO=$(jq -r '.head.repo.full_name' <<< "$PR_JSON")

Declaring any permissions: block sets every unlisted scope to no-access (metadata excepted), so pull-requests is explicitly denied here rather than defaulted.

Why it does not fail loudly today

Most consumers of this stub are public repos, where an under-scoped installation token can generally still read public pull-request metadata. So the call succeeds and the gap stays invisible.

That makes it a latent rather than a live bug, and worth fixing for two reasons:

  1. A private consumer would break, at the gh api call, with a 404 that reads like a bad PR number rather than a permissions problem. set -euo pipefail is active, so the job dies there and the /review comment is never acknowledged --- the user sees nothing.
  2. The stub is the documented copy-paste artifact. Every repo that adopts /review inherits the gap, and the permissions: blocks in examples/ are exactly what the README tells people to copy as-is ("The stubs in examples/ already include the right permissions: blocks -- copy them as-is").

Suggested fix

One line in examples/claude-code-review.yml:

    permissions:
      actions: write        # dispatch this workflow
      issues: write         # acknowledge the /review comment
      pull-requests: read   # read the PR's head branch and head repo

Worth a sweep of the other example stubs for the same shape while in there --- any stub whose job declares a permissions: block and then calls gh api repos/.../pulls/... or gh pr view has the same latent gap.

Provenance

Found by an adversarial review of a consumer migration adopting this stub (UCD-SERG/ucd-serg.github.io#110). Fixed consumer-side there; filing upstream so the next adopter does not inherit it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions