View on GitHub

Agentic Workflows — Field Guide

A field guide to using GitHub Workflows and Agentic Workflows

← Previous: issue_comment / slash_command: Common Triggers Next: pull_request_review_comment →

pull_request_review

⚠️ Use with caution

“A review was submitted” is not “the PR was approved” — but workflows conflate the two. The event fires for any review type, including COMMENT-type reviews that any read-role user (or any drive-by GitHub account) can submit. Event gating on event.review.state == 'approved' doesn’t suffice because actor authorization is independent of review state.

Concurrency twist: pull_request_review is rarely the only trigger on a PR-handling workflow; it usually shares a workflow file with pull_request and issue_comment. If they share concurrency.group: pr-$ with cancel-in-progress: true, a stray comment or a reviewer dismissing an old review can cancel a half-finished APPROVE-handling run — the activation passed, the agent is doing real work, then a benign comment kills it mid-flight, leaving the PR in an indeterminate state (label half-applied, status check half-posted). Without cancel-in-progress, two near-simultaneous reviewers stack runs and post duplicate comments or apply duplicate labels. There is no group key that gets this right for all three triggers in one workflow.


Scenarios

Why ⚠️: “A review was submitted” is not “the PR was approved.” The event fires for any review type including COMMENT-type reviews that any read-role user can submit. This trigger is rarely standalone; it usually shares a workflow with pull_request and issue_comment, creating a multi-trigger concurrency nightmare.

Recommended alternatives:

Profile

Dimension Recommendation
on.roles: [admin, maintainer, write] (default). triage excluded by default — add only if triage-role reviews should trigger automation. Acceptable to set all if the workflow is safe processing reviews from any contributor — same considerations as issues or issue_comment.
Activity types [submitted] for approval-gated workflows. Add dismissed if you need to react to approval revocation. Avoid edited — same time-bomb as issue_comment.edited (editing an old review fires today with today’s secrets).
Concurrency $-$. Use cancel-in-progress: false — if this trigger shares a workflow with pull_request or issue_comment, a stray comment or review dismissal can cancel a half-finished approval-handling run. There is no group key that gets this right for all three triggers in one workflow — prefer separate workflows per trigger.
Idempotency Required. Two near-simultaneous reviewers stack runs that post duplicate comments or apply duplicate labels.
Fork posture Apply if: $ to prevent running within a user’s fork.
Approval gate Not directly subject to the “Approve and run workflows” button (that’s on pull_request/pull_request_target). However, if the workflow also subscribes to pull_request, the gate applies to those events.
Copilot events See Bot Filtering and Skip Bots.
Sanitize payload? Yes, always in pre-agent steps. Review body is user-controlled; use steps.sanitized.outputs.text, never raw $. Acceptable to handle unsanitized payload within the agent job (sandboxed), coupled with proper safe-outputs.
Safe-outputs add-labels, add-comment for post-approval workflows. Avoid push-to-pull-request-branch or create-pull-request — over-broad for review-driven automation.
Integrity filtering approved. unapproved or none when intentionally consuming community review content — must pair with tight safe-outputs. See standard guidance.

← Previous: issue_comment / slash_command: Common Triggers Next: pull_request_review_comment →