|
| 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