Skip to content

Fix Vercel preview workflow for fork PRs#535

Merged
samkim merged 2 commits intomainfrom
fix/vercel-preview-fork-prs
Mar 30, 2026
Merged

Fix Vercel preview workflow for fork PRs#535
samkim merged 2 commits intomainfrom
fix/vercel-preview-fork-prs

Conversation

@samkim
Copy link
Copy Markdown
Member

@samkim samkim commented Mar 30, 2026

Summary

  • Fixes the Vercel preview deployment workflow failing with a 403 on PRs from forks
  • Allows maintainers to trigger preview deployments for fork PRs via workflow re-run
  • Fixes a critical code injection vulnerability (code scanning alert Nov dependabot updates #8)

Problem

When an external contributor opens a PR from a fork, the workflow fails at the "Post no-permission comment" step with:

RequestError [HttpError]: Resource not accessible by integration (403)

This happens because the pull_request event restricts the GITHUB_TOKEN to read-only permissions for fork PRs, regardless of what permissions are declared in the workflow. The bot can't even post the "deployment skipped" comment.

Additionally, the "re-run this workflow" link in that comment doesn't actually help — re-running produces the same result because the permission check only looks at the PR author, who still lacks write access.

Failing run: https://github.com/authzed/docs/actions/runs/23755123905/job/69223406040?pr=529

Expected workflow after this fix

Fork PR from external contributor:

  1. Contributor opens PR from a fork
  2. Workflow runs, detects the author lacks write access
  3. Bot posts a comment: "Preview deployment skipped — @author does not have write access" with a link to the workflow run
  4. A maintainer reviews the PR code, then clicks "Re-run all jobs" from the linked workflow run
  5. On re-run, github.actor is now the maintainer. The permission check sees the maintainer has write access and allows the deployment
  6. Preview is deployed and the comment updates with the preview URL

PR from a collaborator with write access:
No change — works exactly as before.

Technical details

Four changes to .github/workflows/vercel-preview.yml:

  1. pull_requestpull_request_target: Runs the workflow in the base repo's context so the GITHUB_TOKEN gets the declared pull-requests: write permission, even for fork PRs. This is the core fix for the 403.

  2. Reordered steps — permission check before checkout: The permission check and comment-finding steps now run before actions/checkout. This is important for security with pull_request_target: untrusted fork code is never checked out unless the permission gate passes. The checkout step is now conditional on steps.permission.outputs.result == 'true' and explicitly references github.event.pull_request.head.sha (since pull_request_target defaults to checking out the base branch).

  3. Permission check also inspects github.actor: On a re-run, github.actor changes to the person who triggered the re-run. The updated check allows deployment if either the PR author has write access OR the triggering actor (distinct from the author) has write access. This makes the "re-run this workflow" link in the no-permission comment functional.

  4. Fix code injection via github.head_ref (resolves code scanning alert Nov dependabot updates #8): With pull_request_target, github.head_ref is attacker-controlled. It was previously interpolated directly into a run: shell step via ${{ github.head_ref }}, allowing arbitrary command execution through crafted branch names. Fixed by passing it through an environment variable (HEAD_REF) and referencing it as $HEAD_REF in the shell.

🤖 Generated with Claude Code

The workflow failed on fork PRs because `pull_request` events restrict
the GITHUB_TOKEN to read-only, preventing the bot from posting PR
comments. Switch to `pull_request_target` so the token retains the
declared `pull-requests: write` permission.

Also allow maintainers to trigger preview deployments for fork PRs by
checking `github.actor` (the re-run initiator) in addition to the PR
author.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@samkim samkim requested a review from miparnisari March 30, 2026 18:32
@miparnisari miparnisari enabled auto-merge (squash) March 30, 2026 18:44
@miparnisari miparnisari disabled auto-merge March 30, 2026 18:45
With pull_request_target, github.head_ref is controlled by the fork
author. Passing it through an environment variable instead of inline
expression syntax prevents shell injection via crafted branch names.

Resolves code scanning alert #8.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@samkim samkim merged commit c13ae3b into main Mar 30, 2026
10 of 11 checks passed
@samkim samkim deleted the fix/vercel-preview-fork-prs branch March 30, 2026 19:02
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants