Skip to content

ci(repo): replace labeler pull_request_target with workflow_run handshake#8859

Open
jacekradko wants to merge 2 commits into
mainfrom
jacek/sdk-80-replace-labeler-workflow-drop-pull_request_target
Open

ci(repo): replace labeler pull_request_target with workflow_run handshake#8859
jacekradko wants to merge 2 commits into
mainfrom
jacek/sdk-80-replace-labeler-workflow-drop-pull_request_target

Conversation

@jacekradko

@jacekradko jacekradko commented Jun 14, 2026

Copy link
Copy Markdown
Member

Removes the repo's only pull_request_target (in labeler.yml). Labeling is now a two-step handshake: an untrusted pull_request trigger that just writes the PR number to an artifact with no secrets and a read-only token, and a privileged labeler-apply.yml on workflow_run that validates the number, sparse-checks-out only the trusted base .github/labeler.yml, and runs actions/labeler@v6 with pr-number. Fork PRs keep getting labeled, which is the reason pull_request_target was there in the first place.

The piece worth a close look is the trust boundary in labeler-apply.yml: it runs the base-branch copy of the workflow (PRs can't alter it), grants pull-requests: write only in that job, and never checks out PR-head code. The label rules in .github/labeler.yml are unchanged.

One caveat on verification: workflow_run always executes the default-branch version of a workflow, so the apply leg can't actually fire for PRs until this is on main. On this PR you'll only see the "Labeler / Collect PR metadata" run upload the artifact; I'll confirm a same-repo PR gets labeled (then a fork PR) right after merge.

Refs SDK-80.

Summary by CodeRabbit

  • Chores
    • Refactored pull request labeling to a safer, two-stage process, reducing permission exposure by separating untrusted label collection from trusted label application.
    • Added a follow-up labeling workflow that validates the target pull request details before applying labels.
    • Introduced an accompanying changeset entry for this workflow update.

…hake

The repo's only pull_request_target lived in labeler.yml. Split labeling into
an untrusted trigger (pull_request, read-only, no secrets) that records the PR
number to an artifact, and a privileged labeler-apply.yml (workflow_run) that
validates the number, checks out only the trusted base .github/labeler.yml, and
applies labels via actions/labeler driven by pr-number. Fork-PR labeling is
preserved without the pull_request_target footgun.

Refs SDK-80.
@changeset-bot

changeset-bot Bot commented Jun 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbb0b6b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jun 14, 2026 6:21pm
swingset Ready Ready Preview, Comment Jun 14, 2026 6:21pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: c9420997-d9ee-4c2c-b2ea-02fa126d9c31

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa6d4a and fbb0b6b.

📒 Files selected for processing (1)
  • .github/workflows/labeler-apply.yml

📝 Walkthrough

Walkthrough

The labeler GitHub Actions workflow is refactored from a single privileged pull_request_target job into two separate workflows: an untrusted pull_request-triggered collect job that saves the PR number as an artifact, and a new trusted labeler-apply.yml workflow triggered via workflow_run that validates the artifact and applies labels with minimal permissions. A changeset file is also added.

Changes

Labeler Workflow Security Split

Layer / File(s) Summary
Untrusted collect half
.github/workflows/labeler.yml
Trigger changed from pull_request_target to pull_request, workflow-level permissions set to {}, triage job removed, and a new collect job added that writes the PR number to ./pr/number and uploads it as the pr-number artifact with 1-day retention.
Trusted apply half
.github/workflows/labeler-apply.yml, .changeset/sdk-80-labeler-workflow.md
New workflow triggered on successful workflow_run completion of Labeler; downloads and numerically validates the pr-number artifact, sparse-checks out .github/labeler.yml without persisting credentials, and applies labels via actions/labeler with pull-requests: write scoped to the job only.

Sequence Diagram

sequenceDiagram
    participant PR as Pull Request (fork)
    participant Collect as labeler.yml (collect)
    participant Store as Artifact Store
    participant Apply as labeler-apply.yml (apply)
    participant Labeler as actions/labeler

    PR->>Collect: pull_request event (no write token)
    Collect->>Store: upload pr-number artifact
    Store-->>Apply: workflow_run completed (success)
    Apply->>Store: download pr-number artifact
    Apply->>Apply: validate numeric PR number
    Apply->>Apply: sparse checkout .github/labeler.yml
    Apply->>Labeler: apply labels (pull-requests: write)
    Labeler-->>PR: labels applied
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop hop, the rabbit splits the path in two,
One trail untrusted, the other brand new.
The PR number tucked in an artifact chest,
Then fetched by a workflow that's fully blessed.
No secrets spilled on the fork's risky road —
A safer labeler, a lighter load! 🏷️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: replacing the pull_request_target trigger with a workflow_run handshake pattern for improved security in the labeler workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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


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

@pkg-pr-new

pkg-pr-new Bot commented Jun 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8859

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8859

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8859

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8859

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8859

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8859

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8859

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8859

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8859

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8859

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8859

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8859

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8859

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8859

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8859

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8859

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8859

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8859

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8859

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8859

commit: fbb0b6b

The PR number comes from the untrusted pull_request leg, so a malicious PR
could upload another open PR's number and redirect the privileged labeler at
it. Before labeling, verify via API that the claimed PR's head SHA and head
repository match github.event.workflow_run (head_sha / head_repository), and
fail closed otherwise. This preserves fork-PR labeling (workflow_run.pull_requests
is empty for forks, so it can't be used for the binding).

Refs SDK-80.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant