mirror of
https://github.com/pnpm/pnpm.git
synced 2026-07-23 14:13:09 -04:00
* ci(pacquet): fix all zizmor code-scanning findings Resolves the 90 alerts opened by zizmor against the imported pacquet-* workflows and shared composite actions: - unpinned-uses: pin every third-party action to a SHA + version comment (matching SHAs already used elsewhere in the repo where applicable; taiki-e/install-action collapsed onto v2.78.0 with explicit `tool:` input). - artipacked: add `persist-credentials: false` to every actions/checkout. - template-injection: pass `inputs.*` and `steps.*.outputs.*` through `env:` in binstall/rustup composite actions and pacquet-release-to-npm.yml. - excessive-permissions: add top-level `permissions: contents: read` to pacquet-release-to-npm.yml; move issues/pull-requests writes from the workflow level to the benchmark-compare job in pacquet-micro-benchmark.yml. - dangerous-triggers: keep workflow_run in pacquet-integrated-benchmark- comment.yml but suppress with a documented zizmor: ignore — the trigger is the recommended pattern for posting comments back to fork PRs. - superfluous-actions: keep softprops/action-gh-release with a zizmor: ignore (matches release.yml). Verified by running `zizmor .github` locally with no remaining findings. * ci(pacquet): point SHA pins at the patch-version tag Swatinem/rust-cache and montudor/action-zip were pinned to the SHA the major-version alias (`v2`, `v1`) resolves to, but the version comments claimed `v2.9.1` / `v1.0.0`. zizmor's online `ref-version-mismatch` audit flagged the inconsistency. Repoint at the SHAs the patch-version tags actually annotate so the pin and the comment agree.
134 lines
6.1 KiB
YAML
134 lines
6.1 KiB
YAML
name: Pacquet Integrated-Benchmark Comment
|
|
|
|
# Stage 2 of the benchmark pipeline. `pacquet-integrated-benchmark.yml` runs
|
|
# the benchmark on `pull_request` (read-only token on fork PRs) and uploads
|
|
# the report as an artifact. This workflow runs on `workflow_run`, which
|
|
# fires in the base repository's privilege context, so it can post the
|
|
# comment back to the PR even when the PR is from a fork. See
|
|
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
|
|
# for the security rationale.
|
|
|
|
on:
|
|
# zizmor: ignore[dangerous-triggers]
|
|
# `workflow_run` is intentional and required: this workflow runs in the
|
|
# base-repo privilege context so it can comment on fork PRs (the build
|
|
# workflow itself runs with a read-only token on fork PRs). The job-level
|
|
# `if` only proceeds on `success`, the PR number is resolved from the
|
|
# trusted `workflow_run` event payload (not from the fork-controlled
|
|
# artifact), and the artifact body is treated as untrusted markdown.
|
|
# See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
|
workflow_run:
|
|
workflows: ["Pacquet Integrated-Benchmark"]
|
|
types: [completed]
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
issues: write
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
comment:
|
|
name: Post benchmark comment
|
|
runs-on: ubuntu-latest
|
|
# Only post when the upstream benchmark ran on a PR and succeeded.
|
|
# Same gating as the original in-workflow comment, which only ran
|
|
# on the success path of the previous steps.
|
|
if: |
|
|
github.event.workflow_run.event == 'pull_request' &&
|
|
github.event.workflow_run.conclusion == 'success'
|
|
steps:
|
|
- name: Resolve PR number from workflow_run trigger
|
|
# `workflow_run.pull_requests` is empty for fork PRs (the case
|
|
# this workflow exists to fix), so fall back to listing open
|
|
# PRs in this repo and filtering by `head.sha`. The base repo's
|
|
# `commits/{sha}/pulls` endpoint *only* finds PRs whose head
|
|
# commit exists on the base repo — for fork PRs the head lives
|
|
# on the fork, so the lookup returns `[]`. Listing PRs and
|
|
# filtering works for both cases.
|
|
#
|
|
# `head_sha` is sourced from the `workflow_run` event payload,
|
|
# which GitHub fills in for us — not from the artifact, since
|
|
# the artifact is fork-controlled and could otherwise redirect
|
|
# the comment to an arbitrary PR.
|
|
id: meta
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
REPO: ${{ github.repository }}
|
|
TRIGGER_PR: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
shell: bash
|
|
run: |
|
|
set -eu
|
|
if [[ -n "${TRIGGER_PR:-}" ]]; then
|
|
# Same-repo PR: GitHub already gave us the number on the
|
|
# trigger payload. Trusted source, no API call needed.
|
|
pr="$TRIGGER_PR"
|
|
else
|
|
# Fork PR: walk every open PR and match by head.sha. The
|
|
# 40-char SHA is a unique identifier; multiple PRs sharing
|
|
# one is essentially impossible, but the count check below
|
|
# still flags it loudly if it ever happens.
|
|
#
|
|
# `--paginate --jq '.[]'` emits each PR object on its own
|
|
# line so `jq -s` can slurp the whole stream into a single
|
|
# array; using `--paginate --jq '[...]'` would apply the
|
|
# filter per-page and produce one array per page (broken
|
|
# past 100 open PRs). `--arg sha` keeps the head SHA out
|
|
# of the jq program text — defensive against any future
|
|
# change to where HEAD_SHA is sourced from.
|
|
pr=$(
|
|
gh api "repos/$REPO/pulls?state=open&per_page=100" --paginate --jq '.[]' \
|
|
| jq -s --arg sha "$HEAD_SHA" \
|
|
'[.[] | select(.head.sha == $sha) | .number] | unique'
|
|
)
|
|
count=$(echo "$pr" | jq 'length')
|
|
if [[ "$count" == "0" ]]; then
|
|
echo "::error::no open PR matches head_sha=$HEAD_SHA in $REPO"
|
|
exit 1
|
|
fi
|
|
if [[ "$count" != "1" ]]; then
|
|
echo "::error::ambiguous head_sha=$HEAD_SHA matches $count PRs: $pr"
|
|
exit 1
|
|
fi
|
|
pr=$(echo "$pr" | jq '.[0]')
|
|
fi
|
|
# Final sanity check: the resolved value must be a positive integer.
|
|
if ! [[ "$pr" =~ ^[1-9][0-9]*$ ]]; then
|
|
echo "::error::resolved PR number is not a positive integer: '$pr'"
|
|
exit 1
|
|
fi
|
|
echo "pr=$pr" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Download benchmark report
|
|
# `run-id` + `github-token` lets v8 pull artifacts from a different
|
|
# workflow run, which is exactly the workflow_run pattern.
|
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
|
with:
|
|
name: integrated-benchmark-report-ubuntu-latest
|
|
path: benchmark-artifact
|
|
run-id: ${{ github.event.workflow_run.id }}
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Find existing comment
|
|
# Match on the literal substring the report header carries.
|
|
# Updating the heading text in `integrated-benchmark.yml` (the
|
|
# `Integrated-Benchmark Report (${{ runner.os }})` line) needs
|
|
# to keep this matcher in sync, otherwise duplicate comments
|
|
# accrue across runs. Today the matrix only runs on Linux, so
|
|
# there is one fixed string to track.
|
|
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
|
|
id: fc
|
|
with:
|
|
issue-number: ${{ steps.meta.outputs.pr }}
|
|
comment-author: 'github-actions[bot]'
|
|
body-includes: 'Integrated-Benchmark Report (Linux)'
|
|
|
|
- name: Create or update comment
|
|
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
|
|
with:
|
|
issue-number: ${{ steps.meta.outputs.pr }}
|
|
edit-mode: replace
|
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
|
body-file: benchmark-artifact/SUMMARY.md
|