Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
0db76a4
CI: use pull_request_target so review-checklist runs on fork PRs
brtnfld Jun 6, 2026
e83156d
CI: replace pull_request_target with safe two-workflow pattern for fo…
brtnfld Jun 8, 2026
70a1a1b
review-checklist: fix prAuthor crash and stale comment for workflow_r…
brtnfld Jun 8, 2026
32c43d0
CI: revert to pull_request_target, drop two-workflow pattern
brtnfld Jun 8, 2026
4f0d6ba
CI: add zizmor workflow for GitHub Actions security analysis
brtnfld Jun 8, 2026
f841e32
CI: run zizmor via pip instead of third-party action
brtnfld Jun 8, 2026
8add688
CI: fix codeql-action pin to commit SHA (was tag object SHA)
brtnfld Jun 8, 2026
29d99d6
CI: add persist-credentials: false to review-checklist checkout
brtnfld Jun 8, 2026
2199d6f
CI: hash-pin zizmor pip install; suppress expected pull-request-targe…
brtnfld Jun 8, 2026
af25267
CI: update actions to Node.js 24 ahead of June 16 deprecation
brtnfld Jun 8, 2026
5a20031
CI: fix pip hash-pinning syntax — hash must be in requirements file
brtnfld Jun 8, 2026
219303b
CI: zizmor step continue-on-error so SARIF upload always runs
brtnfld Jun 8, 2026
4d7ddc5
review-checklist: skip pull_request_review on fork PRs (read-only token)
brtnfld Jun 8, 2026
82e2541
review-checklist: route reviews through workflow_run for fork PR support
brtnfld Jun 8, 2026
d08bb8a
review-checklist: simplify to pull_request_target only, drop gather w…
brtnfld Jun 8, 2026
492721e
review-checklist: auto-check approval boxes on review via workflow_run
brtnfld Jun 9, 2026
2da8bc9
Merge branch 'develop' into fix/review-checklist-fork-prs
hyoklee Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions .github/scripts/review-checklist.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,27 @@ function buildBody(touchedAreas, approvedUsers, confirmedRequested) {

module.exports = async function run({ github, context, core }) {
const { owner, repo } = context.repo;
const pr_number = context.payload.pull_request.number;
let pr_number;

if (context.eventName === 'workflow_run') {
// workflow_run.pull_requests is empty for fork PRs — look up by head SHA instead.
const headSha = context.payload.workflow_run.head_sha;
const openPRs = await github.paginate(github.rest.pulls.list, {
owner, repo, state: 'open', per_page: 100,
});
const pr = openPRs.find(p => p.head.sha === headSha);
if (!pr) {
core.info('No open PR found matching this workflow_run — skipping');
return;
}
if (pr.base.ref !== 'develop') {
core.info(`PR #${pr.number} targets ${pr.base.ref}, not develop — skipping`);
return;
}
pr_number = pr.number;
} else {
pr_number = context.payload.pull_request.number;
}

// ----------------------------------------------------------------
// Configuration
Expand All @@ -202,10 +222,6 @@ module.exports = async function run({ github, context, core }) {
// Covers: hdf5.h (umbrella), H5*public.h / H5*develop.h (per-module),
// VFD driver headers included by hdf5.h, and VOL connector headers.
//
// NOTE: Fork PRs (head.repo != base.repo) are intentionally excluded.
// They run with a read-only token and cannot post comments or request
// reviewers. Fork coverage would require a pull_request_target job.
//
// NOTE: Team owners (@org/team) in CODEOWNERS are not supported.
// Only individual GitHub logins are handled. If teams are added,
// extend parsing and reviewer requests to use team_reviewers.
Expand Down Expand Up @@ -349,8 +365,8 @@ module.exports = async function run({ github, context, core }) {
// ----------------------------------------------------------------
// 6. Auto-assign reviewers (pull_request events only, not reviews).
// ----------------------------------------------------------------
if (context.eventName !== 'pull_request_review') {
const prAuthor = context.payload.pull_request.user.login;
if (context.eventName !== 'pull_request_review' && context.eventName !== 'workflow_run') {
const prAuthor = prData.user.login;

// Assign the PR author only if they are a code owner.
if (allCodeOwners.has(prAuthor)) {
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/review-checklist-gather.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Review Checklist (gather)

# Minimal signal workflow: fires on pull_request_review so that the
# privileged review-checklist.yml (triggered via workflow_run) can
# update the checklist with the latest approval state.
#
# This workflow intentionally does nothing except complete — its only
# purpose is to unblock the workflow_run trigger in review-checklist.yml.
#
# Requires the repo "Fork pull request workflows from outside collaborators"
# setting to be "Require approval for first-time contributors" (not all
# outside collaborators) so regular fork contributors' reviews fire this
# immediately without a maintainer approval gate.

on:
pull_request_review:
types: [submitted]

permissions: {}

jobs:
signal:
runs-on: ubuntu-latest
if: github.event.pull_request.base.ref == 'develop'
steps:
- run: echo "Review submitted on PR ${{ github.event.pull_request.number }}"
42 changes: 27 additions & 15 deletions .github/workflows/review-checklist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,32 @@ name: Review Checklist
#
# Reviewer lists are derived entirely from .github/CODEOWNERS — no duplication.
# To add an area or change owners, edit only CODEOWNERS.
#
# Uses pull_request_target so the workflow runs with the base repo's full token
# even for fork PRs. The checkout and script execution always use the base
# branch (develop), never the fork's code — this is the safe posture for
# pull_request_target.
#
# Approval boxes are also updated immediately when a review is submitted, via
# a two-workflow pattern: review-checklist-gather.yml fires on pull_request_review
# (read-only token) and this workflow fires on its completion via workflow_run
# (full write token, no fork approval gate). Requires the repo setting
# "Fork pull request workflows from outside collaborators" to be
# "Require approval for first-time contributors".

on:
pull_request:
# zizmor: ignore[pull-request-target]
# Safe: checkout has no ref: override so the base branch (develop) is always
# used — the fork's code is never checked out or executed.
pull_request_target:
types: [opened, synchronize, reopened]
branches: [develop]
pull_request_review:
types: [submitted]
workflow_run:
workflows: ["Review Checklist (gather)"]
types: [completed]

concurrency:
group: review-checklist-${{ github.event.pull_request.number }}
group: review-checklist-${{ github.event.pull_request.number || github.event.workflow_run.head_sha }}
cancel-in-progress: true

permissions:
Expand All @@ -25,18 +41,14 @@ permissions:
jobs:
checklist:
runs-on: ubuntu-latest
# Only run on PRs targeting develop from within the same repo (not forks).
# For review events, only run on approvals targeting develop.
if: |
github.event.pull_request.base.ref == 'develop' &&
github.event.pull_request.head.repo.full_name == github.repository &&
(github.event_name == 'pull_request' ||
(github.event_name == 'pull_request_review' &&
github.event.review.state == 'approved'))

if: >
(github.event_name == 'pull_request_target' && github.event.pull_request.base.ref == 'develop') ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
persist-credentials: false
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const run = require('./.github/scripts/review-checklist.js');
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: zizmor

# Static security analysis for GitHub Actions workflows.
# Findings appear as inline annotations on PRs and in the Security tab.
# Runs zizmor directly via pip to avoid a third-party action dependency.

on:
push:
branches: [develop]
paths: ['.github/**']
pull_request:
branches: [develop]
paths: ['.github/**']

permissions: {}

jobs:
zizmor:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
persist-credentials: false
- run: |
echo 'zizmor==1.25.2 --hash=sha256:c4246f1344d8dbeffc044d7bb11b131773a7db7eb57d9073c45942dfd3543a1f' > /tmp/zizmor-req.txt
pip install --require-hashes -r /tmp/zizmor-req.txt
- run: zizmor --format sarif . > zizmor-results.sarif
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
if: always()
with:
sarif_file: zizmor-results.sarif
category: zizmor
Loading