Skip to content

feat(ci): auto-comment shareable preview links on PRs - #19031

Draft
sfanahata wants to merge 2 commits into
masterfrom
feat/preview-share-links
Draft

feat(ci): auto-comment shareable preview links on PRs#19031
sfanahata wants to merge 2 commits into
masterfrom
feat/preview-share-links

Conversation

@sfanahata

Copy link
Copy Markdown
Contributor

DESCRIBE YOUR PR

Preview deployments are now behind Vercel Deployment Protection (to stop bots/crawlers hitting old builds and generating Sentry noise + accidental indexing). That protection also blocks contractors who legitimately need to preview PRs, and minting a shareable link by hand per deployment is a bottleneck.

This adds an automated, hardened flow that posts a shareable preview link as a sticky PR comment — without exposing the Vercel bypass secret publicly.

What's added

  • app/api/preview-share/route.ts — a public redirect endpoint served from docs.sentry.io. It verifies an HMAC signature + 30-day expiry + host allowlist, then 302-redirects to the preview origin with Vercel's bypass params (x-vercel-protection-bypass + x-vercel-set-bypass-cookie=true), which sets a bypass cookie so the whole preview is browsable. The bypass secret lives only in server env vars — never in the PR comment. Fails closed, noindex/no-store, constant-time signature check.
  • .github/workflows/preview-share-link.yml — on deployment_status success for a preview (production skipped), resolves the PR from the commit SHA, signs a 30-day link, and upserts one sticky PR comment. Runs in the base-repo context, so it works for fork PRs too.
  • Covers both docs projects (sentry-docs + develop-docs) via host-based routing to the correct project's bypass secret.
  • app/api/preview-share/route.test.ts — 10 vitest cases (valid redirects, tampered/expired/disallowed-host rejections, fail-closed).

Bare preview URLs stay protected; only signed, expiring links grant access.

Required config (not in code) — see app/api/preview-share/README.md:

  • Vercel Protection Bypass secret created on both docs projects.
  • On the sentry-docs project (Production only): SHARE_LINK_SIGNING_KEY, BYPASS_SECRET_USER_DOCS, BYPASS_SECRET_DEVELOP_DOCS.
  • GitHub Actions secret SHARE_LINK_SIGNING_KEY (same value) + variable SHARE_BASE_URL=https://docs.sentry.io.

Note: the endpoint goes live only once this merges to master, so this PR's own preview link won't work until then (one-time bootstrap).

IS YOUR CHANGE URGENT?

  • Urgent deadline (GA date, etc.):
  • Other deadline:
  • None: Not urgent, can wait up to 1 week+

PRE-MERGE CHECKLIST

  • Checked Vercel preview for correctness, including links
  • PR was reviewed and approved by any necessary SMEs (subject matter experts)
  • PR was reviewed and approved by a member of the Sentry docs team

LEGAL BOILERPLATE

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.

EXTRA RESOURCES

Contractors need to preview PR deployments, but Vercel Deployment
Protection now gates all preview URLs (to stop bots/crawlers hitting old
builds and creating Sentry noise). Manually minting a shareable link per
deployment is a bottleneck.

This adds an automated, hardened flow:

- app/api/preview-share/route.ts: a public redirect endpoint served from
  docs.sentry.io. It verifies an HMAC signature + 30-day expiry + host
  allowlist, then 302-redirects to the preview origin with Vercel's
  bypass params (x-vercel-protection-bypass + x-vercel-set-bypass-cookie),
  which sets a bypass cookie so the whole preview is browsable. The Vercel
  bypass secret lives only in server env vars, never in the PR comment.

- .github/workflows/preview-share-link.yml: on deployment_status success
  for a preview (production skipped), resolves the PR from the commit SHA,
  signs a 30-day link, and upserts a single sticky PR comment. Runs in the
  base-repo context so it works for fork PRs.

- Covers both docs projects (sentry-docs + develop-docs) via host-based
  routing to the correct project's bypass secret.

Bare preview URLs stay protected; only signed, expiring links grant access.

Setup/rotation steps and required secrets are documented in
app/api/preview-share/README.md.
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
develop-docs Ready Ready Preview Aug 12, 2026 9:27pm
sentry-docs Ready Ready Preview Aug 12, 2026 9:27pm

Request Review

- robots.txt: Disallow /api/preview-share (belt-and-suspenders on top of the
  existing X-Robots-Tag: noindex on every response).
- Endpoint: hard-reject the production `git-master` build alias, so even a
  valid signature can never redirect to the production build URL. The workflow
  already only signs non-production deployments and the signature binds each
  link to a specific host; this is defense-in-depth for the production lockdown.
- Add a regression test for the master-alias guard.
- README: clarify the endpoint is a redirector (no preview content on
  docs.sentry.io), harmless without a valid link, hidden from nav/sitemap, and
  cannot mint links to production URLs.
Comment on lines +141 to +145
const redirectTarget = new URL('/', target.origin);
redirectTarget.searchParams.set('x-vercel-protection-bypass', bypassSecret);
redirectTarget.searchParams.set('x-vercel-set-bypass-cookie', 'true');

const response = NextResponse.redirect(redirectTarget.toString(), 302);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Vercel bypass secret exposed in redirect Location header

Any valid public share link returns the project-wide x-vercel-protection-bypass secret in the HTTP Location header, so one curl -I against a PR comment URL recovers a durable secret that bypasses protection for all previews (not only the signed deployment) until rotation.

Evidence
  • After HMAC/expiry/host checks, the handler builds redirectTarget with x-vercel-protection-bypass set to process.env.BYPASS_SECRET_USER_DOCS or BYPASS_SECRET_DEVELOP_DOCS and returns NextResponse.redirect(...).
  • Those share URLs are posted publicly on PRs by .github/workflows/preview-share-link.yml; callers do not need to follow the redirect to read Location.
  • Vercel’s automation bypass secret is project-scoped, so the leaked value works on arbitrary protected deployments for that project, not only the origin bound in u.
  • This undercuts the design goal of keeping the bypass secret out of public PR comments and re-enables bot/unauthenticated access once any share link is observed.

Identified by Warden · security-review · W37-SNK

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant