From b8d38d0c51ad40b474abc81bbed4248f0a2d9e2b Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 21 Jul 2026 19:38:24 +0000 Subject: [PATCH 1/2] Run benchmark workflows on pull_request instead of pull_request_target actions/checkout v6.1.0 (published 2026-07-20, with backports v5.1.0 and v4.4.0) refuses to check out fork pull-request code from workflows running in the trusted pull_request_target context: Refusing to check out fork pull request code from a 'pull_request_target' workflow. [...] Fetching and executing a fork's code in that trusted context commonly leads to "pwn request" vulnerabilities. Since the floating v6 tag moved to v6.1.0, the label-gated benchmark jobs (invoked from extra_jobs.yml, which runs on pull_request_target because the auto-labeler needs write permissions) fail at their checkout step for every pull request from a fork: they check out and then build and execute the proposed code, which is exactly the pattern the new default blocks. Pushes to main are unaffected since the same workflows then compare trusted before/after refs. Rather than opting out via allow-unsafe-pr-checkout, move the benchmark invocations to a new workflow triggered by plain pull_request events, where fork code runs in the untrusted, fork-scoped context as GitHub recommends. Gating still uses the Z-EndToEndBenchCI and Z-CompilerBenchCI labels, now read from the event payload instead of the labeler job's outputs. One behavioral difference: labels added by the auto-labeler do not re-trigger workflows (events created with the default GITHUB_TOKEN never do), so on freshly opened pull requests the benchmarks only start with the next push to the pull request, or when a label is added manually. Subsequent pushes to labeled pull requests (the common case) behave as before. Co-authored-by: Kiro --- .github/workflows/bench-compiler.yml | 4 +-- .github/workflows/bench-e2e.yml | 2 +- .github/workflows/bench-pr.yml | 40 ++++++++++++++++++++++++++++ .github/workflows/extra_jobs.yml | 16 ++++------- 4 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/bench-pr.yml diff --git a/.github/workflows/bench-compiler.yml b/.github/workflows/bench-compiler.yml index f94195479cc8..9743ef50f52f 100644 --- a/.github/workflows/bench-compiler.yml +++ b/.github/workflows/bench-compiler.yml @@ -21,7 +21,7 @@ jobs: echo "NEW_REF=${{ github.event.after}}" | tee -a "$GITHUB_ENV" echo "OLD_REF=${{ github.event.before }}" | tee -a "$GITHUB_ENV" - name: Save pull request HEAD and base to environment variables - if: ${{ contains(fromJSON('["pull_request", "pull_request_target"]'), github.event_name) }} + if: ${{ github.event_name == 'pull_request' }} run: | echo "OLD_REF=${{ github.event.pull_request.base.sha }}" | tee -a "$GITHUB_ENV" echo "NEW_REF=${{ github.event.pull_request.head.sha }}" | tee -a "$GITHUB_ENV" @@ -84,7 +84,7 @@ jobs: echo "NEW_REF=${{ github.event.after}}" | tee -a "$GITHUB_ENV" echo "OLD_REF=${{ github.event.before }}" | tee -a "$GITHUB_ENV" - name: Save pull request HEAD and base to environment variables - if: ${{ contains(fromJSON('["pull_request", "pull_request_target"]'), github.event_name) }} + if: ${{ github.event_name == 'pull_request' }} run: | echo "OLD_REF=${{ github.event.pull_request.base.sha }}" | tee -a "$GITHUB_ENV" echo "NEW_REF=${{ github.event.pull_request.head.sha }}" | tee -a "$GITHUB_ENV" diff --git a/.github/workflows/bench-e2e.yml b/.github/workflows/bench-e2e.yml index 987420379afc..0be1880a195b 100644 --- a/.github/workflows/bench-e2e.yml +++ b/.github/workflows/bench-e2e.yml @@ -26,7 +26,7 @@ jobs: echo "OLD_REF=${{ github.event.before }}" | tee -a "$GITHUB_ENV" - name: Save pull request HEAD and base to environment variables - if: ${{ contains(fromJSON('["pull_request", "pull_request_target"]'), github.event_name) }} + if: ${{ github.event_name == 'pull_request' }} run: | echo "OLD_REF=${{ github.event.pull_request.base.sha }}" | tee -a "$GITHUB_ENV" echo "NEW_REF=${{ github.event.pull_request.head.sha }}" | tee -a "$GITHUB_ENV" diff --git a/.github/workflows/bench-pr.yml b/.github/workflows/bench-pr.yml new file mode 100644 index 000000000000..d68534a54ffb --- /dev/null +++ b/.github/workflows/bench-pr.yml @@ -0,0 +1,40 @@ +# Copyright Kani Contributors +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# Run the performance benchmark workflows for pull requests that carry the +# corresponding Z-*BenchCI label (applied automatically by the labeler in +# extra_jobs.yml based on the changed files, or manually). +# +# This runs on `pull_request` (not `pull_request_target`) on purpose: the +# benchmark workflows build and execute the code proposed in the pull +# request, which must not happen in the trusted `pull_request_target` +# context (actions/checkout v6.1.0/v5.1.0/v4.4.0 refuse to do so; see +# https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/). +# +# Note on the `labeled` trigger: labels added by the auto-labeler do not +# re-trigger this workflow (events created with the default GITHUB_TOKEN +# never trigger new workflow runs), so on freshly opened pull requests the +# benchmarks only start with the next push to the pull request. Manually +# adding the label triggers them immediately. + +name: Kani Benchmarks +permissions: + contents: read +on: + pull_request: + types: [opened, synchronize, reopened, labeled] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + end-to-end-bench: + name: End-to-End Benchmarks + if: ${{ contains(github.event.pull_request.labels.*.name, 'Z-EndToEndBenchCI') }} + uses: ./.github/workflows/bench-e2e.yml + + compiler-bench: + name: Compiler Benchmarks + if: ${{ contains(github.event.pull_request.labels.*.name, 'Z-CompilerBenchCI') }} + uses: ./.github/workflows/bench-compiler.yml diff --git a/.github/workflows/extra_jobs.yml b/.github/workflows/extra_jobs.yml index 352d6ded22df..b6c8600de45c 100644 --- a/.github/workflows/extra_jobs.yml +++ b/.github/workflows/extra_jobs.yml @@ -44,14 +44,8 @@ jobs: with: dot: true - end-to-end-bench: - name: End-to-End Benchmarks - needs: auto-label - if: ${{ contains(needs.auto-label.outputs.all-labels, 'Z-EndToEndBenchCI') && github.event_name != 'merge_group' }} - uses: ./.github/workflows/bench-e2e.yml - - compiler-bench: - name: Compiler Benchmarks - needs: auto-label - if: ${{ contains(needs.auto-label.outputs.all-labels, 'Z-CompilerBenchCI') && github.event_name != 'merge_group' }} - uses: ./.github/workflows/bench-compiler.yml + # Note: the label-gated benchmark workflows (bench-pr.yml) used to be + # invoked from here, but they build and run the code proposed in the pull + # request, which must not happen in this workflow's trusted + # `pull_request_target` context. They now trigger on `pull_request` + # events directly. From 36ced2e64a1a0c42a515778491d0ed831065a622 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 21 Jul 2026 19:47:33 +0000 Subject: [PATCH 2/2] Clarify caller-context semantics of PR-ref conditions In reusable workflows, github.event_name and github.event are those of the caller workflow ('workflow_call' is never a runtime event name), so the pull_request condition holds when invoked from bench-pr.yml. Add a comment to preempt confusion. Co-authored-by: Kiro --- .github/workflows/bench-compiler.yml | 6 ++++++ .github/workflows/bench-e2e.yml | 3 +++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/bench-compiler.yml b/.github/workflows/bench-compiler.yml index 9743ef50f52f..0b30110c6ad5 100644 --- a/.github/workflows/bench-compiler.yml +++ b/.github/workflows/bench-compiler.yml @@ -20,6 +20,9 @@ jobs: run: | echo "NEW_REF=${{ github.event.after}}" | tee -a "$GITHUB_ENV" echo "OLD_REF=${{ github.event.before }}" | tee -a "$GITHUB_ENV" + # Note: in reusable workflows, github.event_name and github.event are + # those of the caller; when invoked from bench-pr.yml this is a + # pull_request event. - name: Save pull request HEAD and base to environment variables if: ${{ github.event_name == 'pull_request' }} run: | @@ -83,6 +86,9 @@ jobs: run: | echo "NEW_REF=${{ github.event.after}}" | tee -a "$GITHUB_ENV" echo "OLD_REF=${{ github.event.before }}" | tee -a "$GITHUB_ENV" + # Note: in reusable workflows, github.event_name and github.event are + # those of the caller; when invoked from bench-pr.yml this is a + # pull_request event. - name: Save pull request HEAD and base to environment variables if: ${{ github.event_name == 'pull_request' }} run: | diff --git a/.github/workflows/bench-e2e.yml b/.github/workflows/bench-e2e.yml index 0be1880a195b..bc2db84b52fb 100644 --- a/.github/workflows/bench-e2e.yml +++ b/.github/workflows/bench-e2e.yml @@ -25,6 +25,9 @@ jobs: echo "NEW_REF=${{ github.event.after}}" | tee -a "$GITHUB_ENV" echo "OLD_REF=${{ github.event.before }}" | tee -a "$GITHUB_ENV" + # Note: in reusable workflows, github.event_name and github.event are + # those of the caller; when invoked from bench-pr.yml this is a + # pull_request event. - name: Save pull request HEAD and base to environment variables if: ${{ github.event_name == 'pull_request' }} run: |