Skip to content

feat(dev): staging-pinned tailnet previews - #92

Merged
Programcode merged 4 commits into
mainfrom
feat/tailnet-staging-preview
Oct 2, 2026
Merged

Programcode merged 4 commits into
mainfrom
feat/tailnet-staging-preview

Conversation

@Programcode

Copy link
Copy Markdown
Owner

Why

npm run dev uses the production Supabase project unless the browser toggle says staging. A preview opened from Adam's phone or Mac over Tailscale could therefore read and write real user data, and sign-in on a preview origin failed anyway.

What

  • npm run dev:preview binds to 127.0.0.1 and sets VITE_STAGING_PREVIEW=true.
  • In that mode resolveSupabaseConfig pins staging, ignores the toggle, and uses <origin>/__staging-supabase as the Supabase URL. Vite proxies that path to the staging project (server.proxy and preview.proxy), so every Supabase call is same-origin: no Edge Function CORS changes, nothing in production changes.
  • The staging strip shows without "Switch to Production", and the Settings environment switcher is hidden, since a pinned build cannot switch.
  • Project URLs and anon keys move to a side-effect-free src/lib/supabase/projects.ts so vite.config.ts can import them.
  • The proxy path is not /supabase: Vite serves supabase/functions/_shared at /supabase/... in dev and the frontend imports from there. The first attempt broke the app exactly that way.
  • Docs: "Preview on the tailnet" in docs/development.md, a pointer in AGENTS.md, and the staging sign-in note in docs/operations.md.

Remote change already made (staging only)

Staging Auth uri_allow_list gained https://codex-remote.tailab0ab3.ts.net:91*/** so Google sign-in can return to a preview. Production Auth was read, not changed. The previous value is saved on the VPS (~/.codex/backups/debatelab-staging-auth-*/) with undo steps.

Evidence

Phone Desktop
Mobile: staging preview login Desktop: staging preview login

Against a live preview on the tailnet (https://codex-remote.tailab0ab3.ts.net:9100):

  • /__staging-supabase/auth/v1/settings through the proxy returns byte-identical JSON to staging's own endpoint.
  • Browser run over /, /login, /app: staging strip present, no switch button, 0 requests to the production project, 0 direct requests to staging, no failed requests.
  • Submitting an invalid demo code from the login page: POST /__staging-supabase/functions/v1/demo-code-login reached the staging function and returned its real "Demo code not found." reply.
  • The dev server listens on 127.0.0.1:9201 only.
  • Not proven: a full Google or email sign-in (needs a staging account); Adam will try it from his phone.

Checks

  • npm run lint, npm run typecheck, tsc -p tsconfig.node.json, npm run docs:check: pass.
  • Affected unit tests (env resolver, switcher, banner, settings): 39 pass, including new staging-preview cases.
  • Full npm run verify: result posted as a comment below.

🤖 Generated with Claude Code

`npm run dev` talks to production unless the browser toggle says staging, so a
preview opened from another device could read and write real user data.

`npm run dev:preview` binds to 127.0.0.1 and sets VITE_STAGING_PREVIEW=true.
The app is then pinned to staging and calls Supabase at /__staging-supabase on
its own origin, which Vite proxies to the staging project. Requests stay
same-origin, so Edge Function CORS lists need no preview entries and nothing
in production changes. The staging strip shows without the switch to
production, and the Settings environment switcher is hidden, since a pinned
build cannot switch.

The project URLs and anon keys move to a side-effect-free projects.ts so
vite.config.ts can import them. The proxy path avoids /supabase because Vite
serves supabase/functions/_shared there in dev and the frontend imports it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 14:36
@vercel

vercel Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
debate-navigator Ready Ready Preview Oct 2, 2026 2:54pm UTC

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Next included review available in 35 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: abed574e-1d7a-4a94-a208-411edf7618a7

📥 Commits

Reviewing files that changed from the base of the PR and between d68e9c8 and 63627eb.

📒 Files selected for processing (14)
  • AGENTS.md
  • docs/development.md
  • docs/operations.md
  • package.json
  • src/components/StagingBanner.tsx
  • src/components/features/settings/EnvironmentSwitcher.tsx
  • src/lib/supabase/env.ts
  • src/lib/supabase/projects.ts
  • src/lib/supabase/switch-env.ts
  • src/test/components/EnvironmentSwitcher.test.tsx
  • src/test/pages/SettingsAdminNavigation.test.tsx
  • src/test/supabase/local-preview-env.test.ts
  • src/vite-env.d.ts
  • vite.config.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing.

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

@Programcode

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Started directly with `npm run dev:preview` and then exposed through
`tailscale serve`, Vite rejected the forwarded tailnet Host with 403. Only the
preview helper's own launcher set the host allowance. vite.config.ts now
allows `.ts.net` hosts whenever VITE_STAGING_PREVIEW is on, and only then.

Found by the Codex review.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Programcode

Copy link
Copy Markdown
Owner Author

Local verification at fb8a677: full npm run verify passed: docs, lint, typecheck, 1226 unit tests, collaboration, 341 edge tests, build, service worker, and 249 Playwright tests. One Playwright test (admin-announcements deactivate/delete) failed once and passed on retry; run alone 3× on desktop Chromium with retries off it passed 9/9, so it is a pre-existing flake, not this change.

Review: Copilot is out of quota and CodeRabbit hit its hourly limit, so the Codex reviewer (gpt-6.1-sol, high) reviewed fb8a677. One finding, P2: started directly with npm run dev:preview and exposed with tailscale serve, Vite rejected the tailnet Host with 403. Reproduced (403), fixed in the next commit by allowing .ts.net hosts in staging preview mode only, and checked: preview mode now returns 200 for the tailnet host while plain npm run dev still returns 403. Re-reviewing the new head.

The dev server listens on 9200-9299 locally, but the browser and staging Auth
see the tailnet HTTPS port the preview helper publishes (9100-9149). Say so,
and say to publish on 9100-9199 when running `tailscale serve` by hand, since
staging Auth only allows `:91*` redirects.

Found by the Codex review.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Programcode

Copy link
Copy Markdown
Owner Author

Codex re-review of 3b90731: one P2, that previews on 9200-9299 would fail the staging :91* redirect allowlist. Partly a misreading: 9200-9299 is the dev server's local port, and the preview helper publishes it on tailnet HTTPS 9100-9149, which is the origin the browser and Auth see (Codex's own live check confirmed :9101/app is accepted). The docs did blur the two, so b20ee30 separates them and says to publish on 9100-9199 when using tailscale serve by hand. Allowlist unchanged.

With VITE_STAGING_PREVIEW=true in an .env file, the client pinned itself to
the proxy path while vite.config.ts, which only read process.env, installed
no proxy, so Auth calls got the SPA HTML. The config now resolves the flag
with loadEnv, the same way the client sees it.

Found by the Codex review.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Programcode

Copy link
Copy Markdown
Owner Author

Codex review of b20ee30: one P2. With VITE_STAGING_PREVIEW=true set in an .env file, the client pinned to the proxy path but vite.config.ts (reading only process.env) installed no proxy. Valid. 63627eb resolves the flag with loadEnv. Checked three ways: flag in .env.local and npm run dev:preview both return staging Auth JSON through the proxy for the tailnet host; plain vite without the flag still blocks the tailnet host and has no proxy.

@Programcode

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Programcode

Copy link
Copy Markdown
Owner Author

Codex review (gpt-6.1-sol, high) of 63627eb: no actionable findings. All three earlier findings are addressed above.

@Programcode
Programcode merged commit 918b58d into main Oct 2, 2026
8 checks passed
@Programcode
Programcode deleted the feat/tailnet-staging-preview branch October 2, 2026 15:24

This branch was successfully deployed

1 active deployment
Preview — 63627eb9 Deployed Oct 2, 2026 by vercel[bot]
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.

2 participants