Skip to content

Review Labels (apply) #373

Review Labels (apply)

Review Labels (apply) #373

Workflow file for this run

name: Review Labels (apply)
# Runs after "Review Labels (trigger)" completes. Because workflow_run runs
# in the base-repo context, github.token is writable even for PRs from
# forks -- so the actual label edits happen here.
on:
workflow_run:
workflows: ["Review Labels (trigger)"]
types: [completed]
jobs:
apply:
runs-on: ubuntu-latest
# Only act on successful runs of the trigger workflow that were started
# by one of the events we expect. Anything else is ignored outright.
if: >-
github.event.workflow_run.conclusion == 'success' &&
(github.event.workflow_run.event == 'pull_request_review' ||
github.event.workflow_run.event == 'pull_request_target')
permissions:
pull-requests: write
issues: write
steps:
- name: Download task artifact
id: download
uses: actions/download-artifact@v8
with:
name: label-task
path: ./label-task
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
continue-on-error: true
- name: Apply labels
if: steps.download.outcome == 'success'
env:
GH_TOKEN: ${{ github.token }}
run: |
task_file="./label-task/task.txt"
if [ ! -f "$task_file" ]; then
echo "No task artifact; nothing to do."
exit 0
fi
pr_number=$(grep '^pr_number=' "$task_file" | cut -d= -f2-)
action=$(grep '^action=' "$task_file" | cut -d= -f2-)
repo="${{ github.repository }}"
if [ -z "$pr_number" ] || [ -z "$action" ]; then
echo "Incomplete task; nothing to do."
exit 0
fi
# --- Security hardening (workflow_run trust boundary) ---
# The artifact comes from a workflow that can be triggered by fork
# PRs. Validate everything before acting so a forged/malformed task
# cannot be used to mislabel an arbitrary PR or inject gh arguments.
# pr_number must be a plain positive integer.
if ! printf '%s' "$pr_number" | grep -Eq '^[1-9][0-9]*$'; then
echo "Invalid pr_number: '$pr_number'; aborting."
exit 0
fi
# action must be one of the known values.
case "$action" in
changes_requested|new_commits) ;;
*) echo "Invalid action: '$action'; aborting."; exit 0 ;;
esac
# The artifact's PR must match the head SHA that the triggering
# workflow_run actually ran on. This binds the task to the run that
# produced it, so a fork run cannot hand off a different PR's number.
run_sha="${{ github.event.workflow_run.head_sha }}"
pr_sha=$(gh pr view "$pr_number" --repo "$repo" \
--json headRefOid --jq '.headRefOid' 2>/dev/null || true)
if [ -n "$run_sha" ] && [ "$pr_sha" != "$run_sha" ]; then
echo "PR #$pr_number head ($pr_sha) does not match triggering run ($run_sha); aborting."
exit 0
fi
echo "PR #$pr_number, action: $action"
case "$action" in
changes_requested)
# A reviewer requested changes -> flag the PR.
gh pr edit "$pr_number" --repo "$repo" \
--add-label "review issues"
gh pr edit "$pr_number" --repo "$repo" \
--remove-label "new review needed" 2>/dev/null || true
;;
new_commits)
# New commits pushed -> only swap labels if the PR was
# previously flagged with "review issues". Otherwise PRs that
# were never reviewed would wrongly get "new review needed".
has_label=$(gh pr view "$pr_number" --repo "$repo" \
--json labels --jq '.labels[].name | select(. == "review issues")')
if [ -z "$has_label" ]; then
echo "PR does not have \"review issues\"; nothing to do."
exit 0
fi
gh pr edit "$pr_number" --repo "$repo" \
--add-label "new review needed"
gh pr edit "$pr_number" --repo "$repo" \
--remove-label "review issues" 2>/dev/null || true
;;
*)
echo "Unknown action: $action"
;;
esac