-
Notifications
You must be signed in to change notification settings - Fork 94
Add review checklists workflow #899
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
41a3d01
Add review checklists workflow and action
LittleHuba 9078660
Split review-checklists workflow into unprivileged trigger + privileg…
LittleHuba cb8202a
Minimize stage1->stage2 data transfer in review-checklists split
LittleHuba 816c9dd
Fix PR-number resolution: gh api --jq does not accept --arg
LittleHuba 0572ce5
Drop stage1->stage2 action transfer; dismiss_sync self-determines no-op
LittleHuba 3218931
Resolve PR number by head branch, not head SHA, to avoid a fast-itera…
LittleHuba cb82f95
Disable the example checklist
LittleHuba 714236b
Move review-checklists action to tools/review-checklists; add README
LittleHuba f8281cb
Post checklist findings as file-level comments to support binary files
LittleHuba 881c163
Restrict compile_pip_requirements to linux
LittleHuba 155b003
Validate checklist evidence in merge queue instead of assuming it
LittleHuba 8339f6e
Transfer PR number from trigger to apply stage via artifact
LittleHuba c901cb5
Fix merge_group evidence validation never actually running
LittleHuba fc5ab66
Switch checklist path matching from fnmatch to pathspec (gitignore-st…
LittleHuba eb7fa1d
Reduce visibility
LittleHuba e0039ac
Fix stale copyright-checker srcs entry after actions/ -> tools/ move
LittleHuba 6834410
Add cancel-in-progress to review-checklists apply workflow concurrency
LittleHuba 0c12cba
Document why review-checklists action installs deps with pip, not Bazel
LittleHuba 1865c83
Clarify Otterdog status-check syntax for the review-checklists status
LittleHuba bbe339e
Deduplicate OK-reply lookup across review-checklists scripts
LittleHuba 05b053e
Use Bzlmod module name instead of hardcoded '_main' for Rlocation
LittleHuba 075c29f
Document why get_approving_reviewers' discard call is not redundant
LittleHuba 3d3caa7
Name the commit-status description length magic number
LittleHuba b66b6b2
Document why is_pr_in_merge_queue fails closed to False on error
LittleHuba 5f11541
Stay pending until every relevant checklist has been posted
LittleHuba 1908c66
Clarify why the merge-queue notice check is separate from merge_group…
LittleHuba b329e1d
Avoid single/two-letter abbreviations for checklist variables
LittleHuba 61b1e38
Improve remaining unclear variable names
LittleHuba ea54a07
Rename relevant_ids/affected_ids to posted_relevant_ids/posted_affect…
LittleHuba 1822060
Rename relevant/affected checklist-list variables for clarity
LittleHuba 15c6f1d
Add review checklists concept to CI.md
LittleHuba 1315cfe
Fix sync_skills.check false failure by removing .github/BUILD package…
LittleHuba 2a79786
Reformat review-checklists scripts with ruff
LittleHuba 4bd3483
Fix ruff F401 unused-import findings in helpers_test.py
LittleHuba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
|
|
||
| # Review checklists configuration. | ||
| # Each checklist has: | ||
| # id: Unique identifier (used in markers and tracking) | ||
| # name: Human-readable name shown in the PR conversation | ||
| # include: List of glob patterns; a file must match at least one to be considered | ||
| # exclude: (optional) List of glob patterns; a file matching any of these is excluded | ||
| # checklist: Markdown checklist body shown to reviewers | ||
|
|
||
| checklists: [] | ||
| # - id: example-review | ||
| # name: "Example checklist" | ||
| # include: | ||
| # - "**" | ||
| # exclude: | ||
| # - ".github/**" | ||
| # checklist: | | ||
| # - This is an example checklist item | ||
| # - Avoid checkmarks in the items since this makes it easy for users to accidentally modify the checklist | ||
| # - Modifying the checklist will reset all previous acknowledgments |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
|
|
||
| # Privileged apply stage for the review-checklists workflow. | ||
| # | ||
| # Triggered via `workflow_run` once "Review Checklists (Trigger)" completes. | ||
| # `workflow_run` always executes using the base repository's workflow file | ||
| # and permissions, regardless of which repository (including forks) raised | ||
| # the original event — this is what lets this job safely hold a | ||
| # pull-requests/statuses write token even though some of the original | ||
| # events (pull_request_review, pull_request_review_comment on fork PRs) | ||
| # would otherwise force a read-only GITHUB_TOKEN. | ||
| # | ||
| # This workflow does all the actual work: it derives the original event | ||
| # name/head SHA entirely from the `workflow_run` context and the GitHub | ||
| # API, and re-runs the checklist logic that the previous single-stage | ||
| # workflow used to run directly on the untrusted events. The only value | ||
| # carried over from the trigger stage is the PR number, downloaded from | ||
| # the artifact the trigger stage uploaded (see review_checklists_trigger.yml | ||
| # for why that value is safe to trust as-is). Nothing else is transferred | ||
| # — not even the original event's `action` (opened/reopened/synchronize/ | ||
| # edited): `dismiss_sync` is simply run on every pull_request_target event | ||
| # and self-determines whether anything actually changed (see below), so | ||
| # there is nothing else stage 2 needs stage 1 to hand it. | ||
| # | ||
| # Keep review-checklists up to date on pull requests and report whether all | ||
| # checklists have been acknowledged by every approving reviewer. | ||
| # | ||
| # Original events handled: | ||
| # pull_request_target (opened/reopened/synchronize/edited) | ||
| # -> Post or update checklist findings on the PR. | ||
| # -> Invalidate OKs for checklists affected by commits since the | ||
| # previous trigger run (dismiss_sync resolves the "before" SHA | ||
| # itself via run history and diffs against the current head; if | ||
| # the head SHA hasn't moved — e.g. on "edited"/"reopened" without | ||
| # a new push — the diff is empty and this is a no-op). | ||
| # -> On edited: refresh checklist evidence/notices after PR description changes. | ||
| # -> Re-check acknowledgements. | ||
| # pull_request_review_comment (created/edited/deleted) | ||
| # -> Restore checklist findings if they were tampered with or deleted. | ||
| # -> Re-check acknowledgements (this naturally also handles OK-comment | ||
| # edits/deletions — see check_acknowledgements.py). | ||
| # pull_request_review (submitted/dismissed) | ||
| # -> Re-check acknowledgements (approver set may have changed). | ||
| # merge_group (checks_requested) | ||
| # -> Resolve the originating PR (its number transferred from the | ||
| # trigger stage, parsed there from the merge-queue's synthetic head | ||
| # ref) and re-validate its checklist evidence from scratch against | ||
| # its current live state — not merely assumed OK because a required | ||
| # status check passed at some earlier point (see | ||
| # check_acknowledgements.py). | ||
| # | ||
| # When a PR is in merge queue, the "Check acknowledgements" step also | ||
| # ensures: | ||
| # - a persistent PR comment notice, and | ||
| # - a standalone PR-description notice, | ||
| # explaining that post-queue changes do not alter evidence recorded in git | ||
| # history by the merge commit evidence flow. | ||
|
|
||
| name: Review Checklists (Apply) | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: ["Review Checklists (Trigger)"] | ||
| types: [completed] | ||
|
|
||
| permissions: | ||
| pull-requests: write | ||
| statuses: write | ||
| actions: read | ||
|
|
||
| concurrency: | ||
| group: >- | ||
| review-checklists-apply-${{ github.event.workflow_run.head_sha || github.event.workflow_run.id }} | ||
| # Multiple trigger-stage runs for the same head SHA can complete in quick | ||
| # succession (e.g. several review comments posted back-to-back), so let a | ||
| # newer run cancel an older, now-superseded one. Safe because this job only | ||
| # recomputes idempotent PR state (comments/statuses) from scratch each time. | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| review-checklists: | ||
| name: Review Checklists | ||
| if: github.event.workflow_run.conclusion == 'success' | ||
| runs-on: ubuntu-24.04 | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6.0.2 | ||
|
|
||
| # Downloads the PR number from the artifact the trigger stage | ||
| # uploaded (see review_checklists_trigger.yml for why this value is | ||
| # safe to trust as-is). Requires actions: read to fetch artifacts | ||
| # from another workflow run via run-id. | ||
| # | ||
| # A missing/empty artifact (e.g. the trigger job failed before | ||
| # uploading, or ran before this artifact step existed) resolves to | ||
| # an empty pr_number, and downstream steps already tolerate that | ||
| # (they simply have nothing to act on). | ||
| - name: Download PR number | ||
| uses: actions/download-artifact@v4 | ||
| continue-on-error: true | ||
| with: | ||
| name: pr-number | ||
| path: pr-number | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| run-id: ${{ github.event.workflow_run.id }} | ||
|
|
||
| - name: Read PR number | ||
| id: resolve_pr | ||
| run: | | ||
| pr_number="$(cat pr-number/pr-number.txt 2>/dev/null || true)" | ||
| echo "Resolved PR number: ${pr_number}" | ||
| echo "pr_number=${pr_number}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| # Step 1: Post or update checklist findings. | ||
| # Runs on PR open/reopen/sync, on PR description edits, and on | ||
| # review comment events so tampered checklist findings and notices | ||
| # are restored. | ||
| - name: Post / update checklist findings | ||
| if: >- | ||
| github.event.workflow_run.event == 'pull_request_target' || | ||
| github.event.workflow_run.event == 'pull_request_review_comment' | ||
| uses: ./tools/review-checklists | ||
| with: | ||
| action: post | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| pr-number: ${{ steps.resolve_pr.outputs.pr_number }} | ||
|
|
||
| # Step 2: Invalidate stale OKs for commits since the previous push. | ||
| # dismiss_sync resolves the "before" SHA itself (via the previous | ||
| # Trigger-workflow run for this branch) and diffs it against the | ||
| # current head, so it doesn't need to know which pull_request_target | ||
| # sub-action fired: if the head SHA hasn't moved since the previous | ||
| # trigger run (e.g. "edited"/"reopened" without a new push), the | ||
| # diff is empty and this step is a no-op. | ||
| - name: Invalidate stale acknowledgements | ||
| if: github.event.workflow_run.event == 'pull_request_target' | ||
| uses: ./tools/review-checklists | ||
| with: | ||
| action: dismiss_sync | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| pr-number: ${{ steps.resolve_pr.outputs.pr_number }} | ||
| run-id: ${{ github.event.workflow_run.id }} | ||
| head-branch: ${{ github.event.workflow_run.head_branch }} | ||
|
|
||
| # Step 3: Always re-check acknowledgement status. | ||
| # The script sets the commit status context "review-checklists" | ||
| # to "pending"/"success"/"failure", and (as of this stateless | ||
| # redesign) also refreshes the merge-queue notice. It always | ||
| # re-scans the live comment state, so it naturally also picks up | ||
| # OK-comment edits/deletions (there's no dedicated "dismiss_edit" | ||
| # action anymore). For merge_group it resolves the originating PR | ||
| # (via pr-number, transferred from the trigger stage above) and | ||
| # re-validates that PR's checklist evidence from scratch — needing | ||
| # only the original event name, head SHA, and PR number. Commit statuses | ||
| # with the same context on the same SHA are deduplicated, so the | ||
| # latest result from any trigger always wins. This job always has | ||
| # write access (it only ever runs via workflow_run) — branch | ||
| # protection must require the commit status context (not the | ||
| # workflow check run) to gate merges. | ||
| - name: Check acknowledgements | ||
| uses: ./tools/review-checklists | ||
| with: | ||
| action: check | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| pr-number: ${{ steps.resolve_pr.outputs.pr_number }} | ||
| head-sha: ${{ github.event.workflow_run.head_sha }} | ||
| event-name: ${{ github.event.workflow_run.event }} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
|
|
||
| # Unprivileged trigger stage for the review-checklists workflow. | ||
| # | ||
| # This workflow reacts to every event that can affect checklist state, | ||
| # including events raised for pull requests from forked repositories | ||
| # (pull_request_review, pull_request_review_comment). For those events | ||
| # GitHub always issues a read-only GITHUB_TOKEN, no matter what the | ||
| # `permissions:` block requests, so this workflow must not (and does not) | ||
| # attempt to write anything. | ||
| # | ||
| # It performs no checkout and executes no repository/PR-supplied code. The | ||
| # only thing handed across the trust boundary to the privileged | ||
| # `review_checklists_apply.yml` workflow is the PR number, uploaded as a | ||
| # build artifact for the apply stage to download by run ID. This is safe | ||
| # to trust as-is: it comes straight from the trusted event payload | ||
| # (github.event.pull_request.number, or parsed from | ||
| # github.event.merge_group.head_ref for merge_group), is never | ||
| # attacker-influenced code or a value that steers which logic runs, and at | ||
| # worst a wrong number would just point the apply stage at the wrong | ||
| # already-public, same-repository PR. Everything else the apply stage | ||
| # needs (event name, head SHA, and even whether anything actually needs | ||
| # invalidating) is still derived natively from the `workflow_run` context / | ||
| # the GitHub API / a live diff against run history. This job's sole | ||
| # purpose beyond that is to exist and complete, so that `workflow_run` | ||
| # fires the apply stage, which always executes with the base repository's | ||
| # permissions regardless of where the triggering event originated. | ||
| # | ||
| # See "Preventing pwn requests" for background on this pattern: | ||
| # https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/ | ||
|
|
||
| name: Review Checklists (Trigger) | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, reopened, synchronize, edited] | ||
| branches: | ||
| - main | ||
| pull_request_review_comment: | ||
| types: [created, edited, deleted] | ||
| pull_request_review: | ||
| types: [submitted, dismissed] | ||
| merge_group: | ||
| types: [checks_requested] | ||
|
|
||
| permissions: {} | ||
|
|
||
| jobs: | ||
| trigger-apply: | ||
| name: Trigger apply stage | ||
| runs-on: ubuntu-24.04 | ||
| steps: | ||
| # Resolve the PR number directly from the trusted event payload. | ||
| # | ||
| # For merge_group there is no github.event.pull_request; the number | ||
| # is instead parsed out of the synthetic queue ref name, which | ||
| # GitHub generates as `gh-readonly-queue/<base-branch>/pr-<number>-<sha>`. | ||
| - name: Resolve PR number | ||
| id: resolve_pr | ||
| env: | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| MERGE_GROUP_REF: ${{ github.event.merge_group.head_ref }} | ||
| run: | | ||
| if [ "${EVENT_NAME}" = "merge_group" ]; then | ||
| pr_number="$(echo "${MERGE_GROUP_REF}" | grep -oP '(?<=/pr-)[0-9]+' || true)" | ||
| else | ||
| pr_number="${PR_NUMBER}" | ||
| fi | ||
| echo "Resolved PR number: ${pr_number}" | ||
| mkdir -p pr-number | ||
| echo -n "${pr_number}" > pr-number/pr-number.txt | ||
|
|
||
| # Upload it for the privileged apply stage to pick up by run ID. | ||
| # This is the only piece of data transferred across the trust | ||
| # boundary; see the file-level comment above for why it's safe. | ||
| - name: Upload PR number | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: pr-number | ||
| path: pr-number/pr-number.txt | ||
| retention-days: 1 | ||
|
|
||
| # No-op beyond the above: this job's completion is what fires the | ||
| # `workflow_run`-triggered apply stage. | ||
| - name: Signal apply stage | ||
| run: echo "Triggering privileged apply stage via workflow_run." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
| load("@rules_python//python:pip.bzl", "compile_pip_requirements") | ||
|
|
||
| compile_pip_requirements( | ||
| name = "requirements", | ||
| src = "requirements.txt.in", | ||
| exec_compatible_with = ["@platforms//os:linux"], | ||
| requirements_txt = "requirements.txt", | ||
| target_compatible_with = ["@platforms//os:linux"], | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are missing here a "cancel-in-progress" option? Or do we say this is so short running, that it does not make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the cancel-in-progress does not hurt. So I added it. But in general this is quite fast (given GitHub schedules the runs fast).