Repository navigation
Review every PR with Claude, including from authors without write access - #2043
Conversation
The review prompt only reads prepared inputs -- the diff, the changed-file list, the bounded context directory and three docs -- and writes one file, .claude-review/output.md, which a later step publishes. It never needed to run commands, so grant Read/Write/Glob/Grep instead of Bash and drop --dangerously-skip-permissions. The two prompt steps that said "cat" now say "Read". This is worth having on its own, and it is a precondition for opening the review to authors without write access: shell access in a job holding the OAuth token is the payload a prompt injection in a PR diff would want.
claude-code-action refuses to run when the triggering actor lacks write
access ("Actor does not have write permissions to the repository"), so
outside contributors' PRs got no review -- just the fallback comment
saying the review produced no output. MFlowCode#2038 and MFlowCode#1926 are both in that
state.
Set allowed_non_write_users: "*", the action's supported way to lift
that check. It only takes effect because github_token is already passed
below it. allowed_bots is left at its default, so bots still cannot
trigger a review.
The action's docs call this bypass risky and ask that it be paired with
a limited permission scope, which is why the preceding commit took the
shell away: Claude now has Read/Write/Glob/Grep, cannot reach the token
or the GitHub API, and only writes .claude-review/output.md for a later
step to publish. The checkout stays on the base ref, so a PR's code is
never executed here.
Note this opens the OAuth token's budget to anyone who opens a PR.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bb9621fe0e
ℹ️ 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".
| --max-turns 40 | ||
| --allowedTools | ||
| "Bash" | ||
| "Read,Write,Glob,Grep" |
There was a problem hiding this comment.
Stop persisting the token before accepting untrusted prompts
When a non-write user opens a fork PR, this workflow feeds their diff and context into Claude; the CLI reference describes --allowedTools as allowing tools “without prompting for permission” (Claude Code CLI reference), so the bare Read permission is not confined to the prepared inputs. The checkout at .github/workflows/claude-code-review.yml:67-70 leaves persist-credentials at its default, which this repository itself documents as storing GITHUB_TOKEN in an http.extraheader (coverage-refresh.yml:29-35); a prompt-injected diff can therefore have Claude read .git/config and copy this job's pull-request/issues-write token into the subsequently published output.md. Disable checkout credential persistence or isolate Claude in a tokenless job before accepting these prompts.
AGENTS.md reference: AGENTS.md:L4-L6
Useful? React with 👍 / 👎.
| # otherwise stops on "Actor does not have write permissions"; it needs | ||
| # github_token above to honour this. allowed_bots stays empty, so bots still | ||
| # cannot trigger a review. | ||
| allowed_non_write_users: "*" |
There was a problem hiding this comment.
Keep arbitrary commenters from spending review budget
The existing issue_comment arm at .github/workflows/claude-code-review.yml:24-28 accepts @claude full review from any commenter, and this wildcard removes the action's non-write-user gate for that event as well as for PR creation. On any public PR, a non-bot account that neither authored nor maintains the PR can now post the phrase repeatedly and start a separate 40-turn OAuth-backed review each time, with no association, label, or rate check. Restrict the manual trigger to maintainers or authorized author associations, or separate its authorization policy from automatic PR reviews.
Useful? React with 👍 / 👎.
|
Claude Code Review Head SHA: bb9621f Files changed:
Findings:
|
Outside contributors get no Claude review today.
claude-code-actionstops withand because the step is
continue-on-error, the job goes green and the fallback posts "The review produced no output (Claude step: failure)" — which reads like a Claude bug rather than a policy. #2038 (BCKim55) and #1926 (thierrydaoud) are both in that state; both authors haveread.The check is on the triggering actor, not the PR author, so it only bites when the contributor themselves opens the PR. A maintainer commenting
@claude full reviewalready works — but that is manual, and every new PR from a contributor still gets the confusing comment first.Changes
1. Review PRs without a shell. The prompt only reads prepared inputs (the diff, the changed-file list, the bounded context directory, three docs) and writes
.claude-review/output.mdfor the existing publish step — it already says "Do not post GitHub comments yourself." So--allowedTools "Bash"and--dangerously-skip-permissionsbecome--allowedTools "Read,Write,Glob,Grep", and the two prompt steps that saidcatnow sayRead. Worth doing regardless of the gate.2.
allowed_non_write_users: "*". The action's supported way to lift the check. It takes effect only becausegithub_tokenis already passed;allowed_botsstays at its default, so bots still cannot trigger a review.Why this is safe to open up
The action's docs call this bypass risky and ask that it be paired with a limited permission scope. With the shell gone:
ref:override), so a PR's code is never executed in this privileged context — the thingpull_request_targetactually gets wrong when it goes wrong.github.event.*field is interpolated into anyrun:block, so there is no script-injection surface.The residual risk is prompt injection steering the text of a review comment. That is content, not privilege.
Tradeoff, stated plainly
"*"means anyone who opens a PR spends the OAuth token's budget. That is the intended effect — every PR gets a review — but it is a real cost/abuse surface on a public repo. An explicit username list is the conservative alternative if that becomes a problem.Testing
pull_request_targetruns the workflow from the base branch, so this cannot exercise itself on this PR — it takes effect once merged. Verified by inspection instead: YAML parses, theclaudestep's inputs areallowed_non_write_users,claude_args,claude_code_oauth_token,github_token,prompt, andclaude_argsis--max-turns 40 --allowedTools "Read,Write,Glob,Grep"../mfc.sh precheckpasses.First PR from a
read-access contributor after merge is the real check. If the review comes back thin, the tool allowlist is the first thing to look at —Read,Write,Glob,Grepshould cover the prompt, but it is the one behavioural change here.Follow-up, deliberately not in this PR
The job still holds
pull-requests: write/issues: writewhile Claude runs. Splitting it into an unprivileged review job and a privileged publish job would be tidier, but with the shell removed Claude cannot reach those permissions, so the marginal gain is small next to the risk of breaking publishing in a workflow that cannot be tested before merge.