Skip to content

revert(ci): ci-approved fork PR trigger (security + stability) - #1175

Merged
slin1237 merged 2 commits into
mainfrom
slin/fix-ci
Apr 17, 2026
Merged

slin1237 merged 2 commits into
mainfrom
slin/fix-ci

Conversation

@slin1237

@slin1237 slin1237 commented Apr 17, 2026 •

Copy link
Copy Markdown
Member

Description

Problem

Two recently-merged CI changes — #1095 (ci: allow 'ci-approved' label to bypass fork PR approval gate) and its follow-up #1104 (ci: apply change detection to pull_request_target events) — are causing two serious problems on main and all open PRs.

1) Security: classic "pwn request" exposure.

pr-test-rust.yml (and claude-code-review.yml) were wired with:

pull_request_target:
  types: [labeled, synchronize]

plus a ci-approved label gate, and every job checks out github.event.pull_request.head.sha — i.e. the fork's code — while running with pull_request_target privileges (base-branch workflow context + access to repo secrets + self-hosted runner access).

Because synchronize is one of the trigger types, the exploit path is:

  1. External contributor opens a fork PR with innocent-looking code.
  2. Maintainer reviews the visible code and adds ci-approved.
  3. Attacker force-pushes malicious code to the fork branch.
  4. synchronize fires → label is still present → CI runs the new fork code on k8s-runner-cpu / k8s-runner-gpu with GITHUB_TOKEN and (via the Claude review workflow) ANTHROPIC_API_KEY.

Blast radius includes secret exfiltration plus potential pivot on the self-hosted runners. This is the pattern GitHub's Security Lab post specifically warns against.

2) CI instability on main and PRs.

Internal (non-fork) PRs now fire BOTH pull_request and pull_request_target into the same concurrency group:

concurrency:
  group: gateway-tests-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

The two event types race and cancel each other. Last 40 pr-test-rust.yml runs broke down as:

event success failure cancelled action_required in-progress
pull_request 1 6 7 5 2
pull_request_target 3 3 12 0 0
push 0 0 1 0 0

So ~10% of runs complete successfully; the rest are cancelled mid-flight or need manual approval. This blocks both landing on main and validating feature PRs.

Solution

Revert both PRs. The fork-PR CI convenience should be re-introduced later with a secure design (see Follow-up below) rather than patched in place.

Changes

Two revert commits:

  • revert(ci): apply change detection to pull_request_target events (#1104) — drops the 7 && github.event_name != 'pull_request_target' guards from e2e job conditions (dead code once the trigger is removed).
  • revert(ci): allow 'ci-approved' label to bypass fork PR approval gate (#1095) — removes the pull_request_target trigger, the ci-gate job and all needs: [ci-gate] edges, the per-job ref: ${{ github.event.pull_request.head.sha || github.sha }} overrides, and the equivalent changes in .github/workflows/claude-code-review.yml. Restores the original concurrency config.

Net diff: +6 / -51 lines across two workflow files. No source code touched.

Follow-up (NOT in this PR)

When we re-add fork-PR CI support, it must use one of these safer patterns:

  1. Two-workflow split. Privileged tests stay on pull_request (untrusted code cannot access secrets). A separate pull_request_target workflow runs only read-only steps (labeler, PR comment, etc.) with narrow permissions:.
  2. SHA-pinned approval. Record the approved head SHA in a comment or a store when ci-approved is added; only run CI for that exact SHA. Auto-remove the label on every new push so re-approval is required.
  3. Manual approval flow only (the current GitHub default) — accept the UX cost.

Test plan

  • YAML syntax validated locally for both workflow files
  • Post-revert grep confirms no pull_request_target / ci-approved / ci-gate references remain in either workflow
  • Revert applies cleanly (no conflicts with later commit 5319dc6e which added e2e-1gpu-completions)
  • After merge: confirm pull_request CI runs are no longer cancelled by a competing pull_request_target run
  • After merge: confirm main push runs stop racing with PR runs

Refs: #1095, #1104

Summary by CodeRabbit

  • Chores
    • Consolidated CI/CD workflow configuration to streamline pull request testing processes and improve execution consistency while maintaining comprehensive test coverage.

This reverts commit b776668.

Reverting as part of rolling back the ci-approved fork PR trigger
added in #1095. Once the pull_request_target workflow trigger is
removed, these e2e job conditions referring to
`github.event_name != 'pull_request_target'` become dead code and
would never evaluate, so they are reverted together.

Refs: #1095, #1104
Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
…#1095)

This reverts commit 381c5f6.

Reverted for two reasons:

1) Security exposure (classic "pwn request" pattern). The workflow
   used pull_request_target with `types: [labeled, synchronize]` and
   then checked out the fork head SHA. Once a maintainer applies the
   `ci-approved` label, any subsequent push from the fork triggers
   `synchronize` and runs the new fork code on self-hosted runners
   (k8s-runner-cpu / k8s-runner-gpu) with access to workflow secrets
   (GITHUB_TOKEN, and ANTHROPIC_API_KEY via the Claude Code Review
   workflow which applied the same pattern). An attacker can push
   benign code, wait for the label, then force-push malicious code
   that exfiltrates secrets or persists on the self-hosted runner.

2) CI instability on main and open PRs. Internal PRs now fire both
   `pull_request` and `pull_request_target` into the same concurrency
   group (`gateway-tests-${{ pr.number || ref }}` with
   `cancel-in-progress: true`), so the two event types race and
   cancel each other. Recent 40 runs: pull_request 1/21 success,
   pull_request_target 3/18 success; the rest are cancelled or
   action_required. This blocks both landing on main and reviewing
   feature PRs.

The fork-PR CI convenience should be reintroduced later with a
safer design: either split privileged and unprivileged jobs into two
workflows (pull_request_target runs only read-only steps, privileged
tests stay on pull_request), or pin the approved head SHA at
label-add time and auto-remove the label on push, or use a separate
repo-level approval token flow. The current implementation should
not be restored as-is.

Refs: #1095
Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 66f62d6a-ec84-473a-a88f-1461eba57e9c

📥 Commits

Reviewing files that changed from the base of the PR and between 09c9353 and 36cffd5.

📒 Files selected for processing (2)
  • .github/workflows/claude-code-review.yml
  • .github/workflows/pr-test-rust.yml

📝 Walkthrough

Walkthrough

Two GitHub Actions workflows are consolidated to run exclusively on pull_request events. The pull_request_target trigger pathway is removed from both workflows, simplifying job conditionals and checkout behavior. Concurrency handling is updated with event-based gating.

Changes

Cohort / File(s) Summary
Claude Code Review Workflow
.github/workflows/claude-code-review.yml
Removed pull_request_target trigger and ci-approved label-based gating. Simplified job conditional to check only pull_request event, repository match, non-dependabot actor, and non-fork PRs. Adjusted checkout to use default ref behavior.
Rust PR Test Workflow
.github/workflows/pr-test-rust.yml
Removed pull_request_target trigger, eliminated ci-gate job, and removed downstream job dependencies on it. Updated concurrency key to gateway-tests-${{ github.ref }} and made cancel-in-progress conditional on pull_request event. Removed pull_request_target references from job conditionals across detect-changes and multiple E2E jobs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

ci

Suggested reviewers

  • CatherineSue
  • key4ng
  • XinyueZhang369

Poem

🐰 No more split paths through GitHub's great halls,
Pull requests now travel one unified way,
No targets to aim at, no gatekeepers' calls,
The workflow flows simpler, hooray, hip-hooray! 🎉
Events consolidated, conditions made clear,
This rabbit approves—simplification is dear! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: reverting a CI configuration that introduced a fork PR trigger mechanism, with the security and stability rationale clearly highlighted in parentheses.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch slin/fix-ci

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the ci CI/CD configuration changes label Apr 17, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36cffd5242

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines 37 to 40
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pin checkout to PR head SHA for incremental review

Removing the ref from actions/checkout makes pull_request runs check out GitHub’s synthetic merge ref instead of the PR head commit, but this workflow’s prompt still relies on git diff ${{ github.event.before }}..HEAD to review only the latest push. On synchronize events for long-lived PRs, HEAD now includes merge-base updates from main, so Claude can re-review unrelated upstream changes and post noisy/incorrect inline comments. Keeping checkout pinned to github.event.pull_request.head.sha avoids that regression.

Useful? React with 👍 / 👎.

@slin1237
slin1237 merged commit 0cb89a4 into main Apr 17, 2026
76 of 79 checks passed
@slin1237
slin1237 deleted the slin/fix-ci branch April 17, 2026 13:14
CatherineSue added a commit that referenced this pull request Apr 17, 2026
Adds an if: condition on build-wheel that skips expensive GPU and paid-API
jobs for fork PRs unless they carry the 'ci-approved' label. Internal PRs
run unconditionally.

build-wheel is the first-tier expensive job; benchmarks, e2e-* (1/2/4-GPU),
e2e-vendor (paid Anthropic/OpenAI/xAI APIs), python-unit-tests,
go-unit-tests, and go-bindings-e2e all inherit the gate transitively
through their needs: build-wheel chain.

Does not reintroduce pull_request_target or the prior ci-gate job (both
reverted in #1175). To kick off expensive jobs on a fork PR after adding
the label: wait for the contributor's next push (synchronize event), or
click "Re-run all jobs" in the Actions UI.

Recommended companion setting (repo admin): Settings -> Actions -> General
-> Fork pull request workflows from outside collaborators: change to
"Require approval for first-time contributors" so returning fork
contributors don't need the manual approve-and-run click on every push.

Signed-off-by: Chang Su <chang.s.su@oracle.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD configuration changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant