Skip to content

Commit 096331d

Browse files
authored
fix ready-for-review label removal (#64)
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
1 parent c53dc9e commit 096331d

2 files changed

Lines changed: 106 additions & 20 deletions

File tree

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,46 @@
1-
name: Ready-for-review label
1+
name: Ready-for-review (collect)
22

3-
# When a pull-request changes state (closed, converted to draft) or a review is submitted/dismissed,
4-
# run the `manage-ready-for-review.yml` workflow, to remove the
5-
# "ready-for-review" label from a PR if its no longer needed.
3+
# Stage 1 of a two-stage pipeline that removes the "ready-for-review" label from
4+
# a pull request once it is no longer awaiting review.
65
#
7-
# `pull_request_target` (rather than `pull_request`) is required so that the job
8-
# has a read/write token for pull requests opened from forks. This is safe here
9-
# because the reusable workflow never checks out or executes pull-request code.
10-
#
11-
# The label removal workflow lives in hyperlight-dev's `.github` repository. To apply this workflow
12-
# to another repository, copy this file to that repo.
6+
# Pull-request and review events originating from FORKED repositories only ever
7+
# receive a read-only GITHUB_TOKEN, so a workflow triggered directly by them
8+
# cannot modify labels.
9+
# This stage therefore performs no privileged work: it
10+
# simply records the pull-request number and hands it to the privileged
11+
# "Ready-for-review (manage)" workflow, which is triggered via `workflow_run`
12+
# and runs with a read-write token. See
13+
# ready-for-review-manage.yml.
1314
on:
14-
pull_request_target:
15+
pull_request:
1516
types: [closed, converted_to_draft]
1617
pull_request_review:
1718
types: [submitted, dismissed]
1819

1920
# Serialise runs per pull request so that concurrent events cannot race.
2021
concurrency:
21-
group: ready-for-review-${{ github.event.pull_request.number }}
22+
group: ready-for-review-collect-${{ github.event.pull_request.number }}
2223
cancel-in-progress: false
23-
2424
permissions:
2525
contents: read
26-
pull-requests: read
27-
issues: write
26+
2827
jobs:
29-
manage-label:
30-
# Shared workflow in the org-wide `.github` repository, pinned to a commit SHA
31-
uses: hyperlight-dev/.github/.github/workflows/manage-ready-for-review.yml@55e0ed4457b40f371ec9b6f2828397b09a833a43
32-
with:
33-
pr-number: ${{ github.event.pull_request.number }}
28+
collect:
29+
runs-on: ubuntu-latest
30+
steps:
31+
- name: Record the pull-request number
32+
env:
33+
# Always a GitHub-provided integer; present on both the pull_request
34+
# and pull_request_review event payloads.
35+
PR_NUMBER: ${{ github.event.pull_request.number }}
36+
run: |
37+
set -euo pipefail
38+
mkdir -p pr
39+
printf '%s' "$PR_NUMBER" > pr/pr_number
40+
41+
- name: Upload the pull-request number
42+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
43+
with:
44+
name: ready-for-review-pr-number
45+
path: pr/
46+
retention-days: 1
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Ready-for-review (manage)
2+
3+
# Stage 2 of the two-stage "ready-for-review" label pipeline. It is triggered
4+
# when "Ready-for-review (collect)" completes and runs in the context of the
5+
# base repository's default branch, so it receives a read-write GITHUB_TOKEN
6+
# even when the originating event came from a fork. This is what lets us remove
7+
# the label from pull requests opened from forks. See ready-for-review-label.yml.
8+
#
9+
# SECURITY: the collect stage can run from untrusted fork code, so the artifact
10+
# it produces is UNTRUSTED. We therefore:
11+
# * download it into a temporary directory,
12+
# * never check out or execute any pull-request code, and
13+
# * strictly validate the pull-request number (digits only) before use.
14+
# The downstream reusable workflow only ever *removes* the label, and only when
15+
# the PR genuinely meets a removal condition, so the worst a spoofed-but-valid
16+
# number could achieve is removing a single, manually re-addable label from a PR
17+
# that already qualified for removal.
18+
on:
19+
workflow_run:
20+
workflows: ["Ready-for-review (collect)"]
21+
types: [completed]
22+
23+
# Best-effort per-source-branch serialisation. The real PR number is only known
24+
# after the artifact is read, and the reusable workflow already tolerates a
25+
# concurrent label removal (HTTP 404), so this is belt-and-braces.
26+
concurrency:
27+
group: ready-for-review-manage-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
28+
cancel-in-progress: false
29+
30+
permissions:
31+
actions: read # download the artifact from the collect run
32+
contents: read
33+
pull-requests: write # remove the label
34+
issues: write # labels are managed through the issues API
35+
36+
jobs:
37+
read-pr:
38+
runs-on: ubuntu-latest
39+
# Only act on a collect run that actually succeeded.
40+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
41+
outputs:
42+
pr_number: ${{ steps.read.outputs.pr_number }}
43+
steps:
44+
- name: Download the pull-request number
45+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
46+
with:
47+
name: ready-for-review-pr-number
48+
path: ${{ runner.temp }}/pr # temp dir, never the workspace
49+
run-id: ${{ github.event.workflow_run.id }}
50+
github-token: ${{ secrets.GITHUB_TOKEN }}
51+
52+
- name: Read and validate the pull-request number
53+
id: read
54+
env:
55+
ARTIFACT_DIR: ${{ runner.temp }}/pr
56+
run: |
57+
set -euo pipefail
58+
raw="$(cat "${ARTIFACT_DIR}/pr_number")"
59+
# Untrusted input from a potentially fork-triggered run: digits only.
60+
if [[ ! "$raw" =~ ^[0-9]+$ ]]; then
61+
echo "Refusing to act on non-numeric PR number" >&2
62+
printf 'Value was: %q\n' "$raw" >&2
63+
exit 1
64+
fi
65+
echo "pr_number=${raw}" >> "$GITHUB_OUTPUT"
66+
67+
manage-label:
68+
needs: read-pr
69+
# Shared workflow in the org-wide `.github` repository, pinned to a commit SHA.
70+
uses: hyperlight-dev/.github/.github/workflows/manage-ready-for-review.yml@e5e471d927d3a72676ab48433da8a99d15a32ad7
71+
with:
72+
# fromJSON turns the validated digit-string into a numeric input.
73+
pr-number: ${{ fromJSON(needs.read-pr.outputs.pr_number) }}

0 commit comments

Comments
 (0)