Skip to content

Keep the workers.dev trigger when publishing custom domains - #1016

Merged
kody-bot merged 13 commits into
mainfrom
cursor/track-1-package-app-domain-isolation-102f
Jul 29, 2026
Merged

kody-bot merged 13 commits into
mainfrom
cursor/track-1-package-app-domain-isolation-102f

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 29, 2026 •

Copy link
Copy Markdown
Owner

Second-order fallout from the custom-domain work in #1013, found while verifying the recovered production deploy.

What broke

Publishing routes flips Wrangler's workers_dev to false. Comparing deploy trigger output:

before (958407f8):  Deployed kody-production triggers
                      https://kody-production.kody-a99.workers.dev
after  (9cc849e9):  Deployed kody-production triggers
                      heykody.dev (custom domain)
                      kodyapps.dev (custom domain)

https://kody-production.kody-a99.workers.dev/health answered with Cloudflare error 1042 (workers.dev disabled for this Worker). That hostname is a documented access path, not incidental: docs/contributing/architecture/request-lifecycle.md notes MCP clients may connect through a workers.dev host and that resource metadata is derived from the inbound origin for exactly that reason, and deploy.yml falls back to scraping a *.workers.dev URL out of the deploy log when APP_BASE_URL is unset.

The fix

writeGeneratedWranglerConfig sets workers_dev: true in the same place it publishes the custom-domain routes, so attaching a domain cannot silently remove the workers.dev trigger. Preview and test are untouched (they publish no routes, so they keep whatever triggers they had). tools/ci/resource-utils.node.test.ts asserts workers_dev: true for production and absent for preview; docs/contributing/setup-manifest.md records the interaction.

Verified in production (deploy of f661e3f)

The deploy published all three triggers and every post-deploy step passed, including the healthcheck, execute smoke check, and Vectorize reindex that the previous failed deploy had skipped:

🧱 Ensure production resources   Custom domain routes: hey***.dev (APP_BASE_URL), ***apps.dev (PACKAGE_APP_BASE_URL); workers.dev trigger kept
☁️ Deploy to Cloudflare Workers  Deployed ***-production triggers (3.09 sec)
                                   https://***-production.***-a99.workers.dev
                                   hey***.dev (custom domain)
                                   ***apps.dev (custom domain)
🩺 Healthcheck (production)      healthcheck-ok { ok: true, commitSha: 'f661e3f5...' }
🧪 Execute smoke check           execute-smoke-ok { result: 42, ok: true }

Live check of all three:

heykody.dev/health            -> 200  {"ok":true,"commitSha":"f661e3f5..."}
kody-production...workers.dev -> 200  {"ok":true,"commitSha":"f661e3f5..."}
kodyapps.dev/                 -> 302 to https://heykody.dev/

Conductor Report

Open in Web Open in Cursor 

Summary by CodeRabbit

  • Bug Fixes
    • Preserved the default workers.dev hostname when custom-domain routes are published.
    • Prevented loss of the backup workers.dev access path in production environments.
  • Documentation
    • Clarified setup guidance for custom-domain routes and local development behavior.
  • Tests
    • Added coverage confirming workers.dev remains enabled in production and unset for previews.

cursoragent and others added 13 commits July 29, 2026 13:07
Package apps execute author-supplied code. Serving them on the app origin
made that code same-site with kody_session: the owner's cookie was
forwarded into the package worker (and into the realtime connect hook),
and package browser code could call first-party endpoints with the
owner's credentials.

- PACKAGE_APP_BASE_URL selects a separate registrable domain for hosted
  package apps; unset keeps today's same-origin path-based behavior for
  local dev, preview, and tests.
- Requests handed to package code are stripped of Cookie, Authorization,
  Proxy-Authorization, and X-Kody-* headers unconditionally.
- The app origin mints a 60s single-use signed handoff token; the
  package-app origin exchanges it for a host-scoped kody_pkg_session
  cookie (distinct name, distinct derived secret, distinct payload) and
  serves nothing else.
Verified against a real wrangler dev server with a second local origin:

- Swapping origins by assigning URL.protocol/host keeps the original
  port, so the app origin redirected to https://kodyapps.dev:8787.
  Build the target with the URL constructor instead, and give the
  workers test different ports so the regression cannot hide.
- npm run dev runs the production wrangler env, so the committed
  PACKAGE_APP_BASE_URL reached local dev and would have sent local
  package-app traffic to the real domain. Local dev now honors only an
  origin it can answer on (localhost / *.localhost), so
  PACKAGE_APP_BASE_URL=http://packages.localhost:<port> in .env still
  exercises the two-origin flow.
- Drop the custom_domain route from wrangler.jsonc: with a route
  configured, wrangler dev resolves every local request as
  http://kodyapps.dev/..., which broke canonical URLs, OAuth resource
  metadata, and redirects locally. The domain is attached to the Worker
  out-of-band like heykody.dev; docs say how.
The deploy now provisions the kodyapps.dev Workers custom domain (DNS +
edge cert) instead of needing a manual attach: the generated deploy
config derives routes: [{ pattern: <PACKAGE_APP_BASE_URL host>,
custom_domain: true }] from that environment's var, so the host the
Worker routes on and the domain the deploy attaches cannot drift.

The route stays out of wrangler.jsonc on purpose. Wrangler resolves local
dev request URLs against the first configured route, so a committed route
made every npm run dev request arrive as http://kodyapps.dev/... —
canonical URLs, OAuth resource metadata, and login redirects all left
localhost. dev.host can override that host but drops (or hardcodes) the
port, and pinning it to localhost would break the Playwright suite, which
runs on 127.0.0.1.

Preview and test have no PACKAGE_APP_BASE_URL, so they get no route.
… gate

- Extract isSessionInvalidatedByStoredPasswordChange so browser and
  package-app session resolution cannot drift on a security-critical
  fail-closed check.
- Gate the local-dev package-app-origin override on WRANGLER_IS_LOCAL_DEV
  === 'true' (matching isNonProductionRuntime), so no other value can pull
  package apps back onto the app origin in a real deployment.
- Rewrite a request that still carries __kody_handoff before serving, so a
  stale or forged token never reaches package code.
- Docs: stop claiming the redirect makes the token unusable from history or
  a referrer; expiry and single-use are what bound a leak.
…e-app-domain-isolation-102f

# Conflicts:
#	packages/worker/src/app/request-auth-cache.ts
#	packages/worker/src/app/username.ts
A signature-valid token aimed at another package path was consumed and
then rejected, so a mistyped URL cost the owner a handoff they still
held. consumePackageAppHandoffToken now takes the expected
{username, kodyId} and verifies the binding before the replay burn.

Also corrects the shared password-change docstring: the missing-issuedAt
fail-closed only applies once an account has a stored password_changed_at.
Accounts that never changed a password keep pre-issuedAt cookies, which is
the documented tradeoff in security.md, not an oversight.
Wrangler treats a configured routes list as the Worker's complete
custom-domain set, not an addition to it. The previous deploy published
only kodyapps.dev, which detached heykody.dev and deleted its DNS record —
production returned Cloudflare 530 until this deploy republishes both.

The generator now derives one custom_domain route per base-URL var
(APP_BASE_URL and PACKAGE_APP_BASE_URL), and fails the deploy when
PACKAGE_APP_BASE_URL is set without APP_BASE_URL instead of shipping a
partial set. Covered by a test asserting both routes and the fail-closed
guard.
…e-app-domain-isolation-102f

# Conflicts:
#	docs/contributing/setup-manifest.md
#	tools/ci/resource-utils.node.test.ts
#	tools/ci/resource-utils.ts
…e-app-domain-isolation-102f

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Publishing routes flips workers_dev to false, so the previous deploy
silently dropped kody-production.kody-a99.workers.dev (Cloudflare now
answers it with error 1042). That hostname is a documented access path —
MCP clients can be pointed at it and the deploy's URL fallback looks for
it — so the generator now asks for it explicitly alongside the routes.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5661a84e-7183-4cc9-9539-4c801281c445

📥 Commits

Reviewing files that changed from the base of the PR and between 9cc849e and 2f0bc40.

📒 Files selected for processing (3)
  • docs/contributing/setup-manifest.md
  • tools/ci/resource-utils.node.test.ts
  • tools/ci/resource-utils.ts

📝 Walkthrough

Walkthrough

Custom-domain route generation now preserves the workers.dev trigger by setting workers_dev: true. Tests verify production and preview configuration values, and setup documentation describes the behavior.

Changes

Custom route access

Layer / File(s) Summary
Preserve workers.dev during route generation
tools/ci/resource-utils.ts
Custom-domain route publishing sets workers_dev to true and updates the log message.
Validate generated configuration and document behavior
tools/ci/resource-utils.node.test.ts, docs/contributing/setup-manifest.md
Tests assert production and preview workers_dev values, while the setup manifest documents route publishing and hostname behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 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 clearly matches the main change: preserving the workers.dev trigger when publishing custom domains.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/track-1-package-app-domain-isolation-102f

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-1016.kody-a99.workers.dev

Worker: kody-pr-1016
D1: kody-pr-1016-db
KV: kody-pr-1016-oauth-kv

Mocks:

@kody-bot
kody-bot merged commit f661e3f into main Jul 29, 2026
10 checks passed
@kody-bot
kody-bot deleted the cursor/track-1-package-app-domain-isolation-102f branch July 29, 2026 16:19
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.

3 participants