You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(cors): allow eliewm team-scope Vercel previews across all CORS surfaces (#4248)
* fix(cors): allow eliewm team-scope Vercel previews
Preview deployments moved from the personal Vercel scope
(worldmonitor-*-elie-<hash>) to the "eliewm" team scope
(worldmonitor-git-<branch>-eliewm.vercel.app and
worldmonitor-<hash>-eliewm.vercel.app). Both CORS twins still pinned the
dead personal-scope pattern, so the browser's Origin header on
POST /api/wm-session was rejected by isDisallowedOrigin — the anonymous
session could never be minted and every session-authed call 401'd on
previews (dashboard + /welcome teasers stayed dark).
Replace the dead pattern with the eliewm team-scope pattern in
server/cors.ts and api/_cors.js, kept tight (no bare *.vercel.app, this
is a security allowlist). Add isAllowedOrigin tests covering the
git-branch alias URL, hash deployment URL, and non-worldmonitor
rejection against both twins, plus a source twin-parity guard, and
update the gateway CDN origin-policy preview origin to eliewm.
* fix(cors): extend eliewm preview scope to the Cloudflare Worker + guard the superset invariant
The api-cors-preflight Cloudflare Worker is the third CORS twin and short-
circuits OPTIONS preflights at the edge, so its allowlist must be a superset
of api/_cors.js. PR #4248 moved the functions to the eliewm team scope but
left the Worker pinned to the dead -elie- personal scope — making the Worker
strictly NARROWER than the functions. Result: eliewm preview preflights echo
the canonical worldmonitor.app fallback and the browser blocks the request
before it ever reaches Vercel, so previews stay dark even though the function
would accept the origin.
Worse, this was invisible to CI: the Worker's own test lives outside the
test:data glob (it only runs in deploy-worker.yml on workers/** changes), and
both the Worker and its test still pinned the old literal, so they were
internally consistent and green while drifting from the function.
- workers/api-cors-preflight/src/index.js: replace the dead -elie- pattern
with the eliewm team-scope pattern (kept tight, no bare *.vercel.app).
- workers/api-cors-preflight/index.test.mjs: update the preview-deploy
assertions to the eliewm shape (git-branch alias + hash), and assert foreign
team / non-worldmonitor / retired personal scope stay rejected.
- tests/cors-fail-closed.test.mts: add the Worker to the source twin-parity
guard (now a three-twin check) AND a gate-resident behavioral superset test
that imports both the function and Worker predicates and asserts the Worker
allows every origin the function allows. This always-run check is what
catches function<->Worker drift (the gap that left this bug invisible).
* fix(widget): allow eliewm team-scope previews to mount PRO widgets
The widget postMessage sandbox (public/wm-widget-sandbox.html) gated parent
origins on a stale Vercel hostname shape — `worldmonitor-<branch>-<team>-<hash>`
with the team slug followed by a trailing hash — and slug `elie`. Real Vercel
preview URLs put the team scope as the LAST segment
(worldmonitor-git-<branch>-eliewm.vercel.app / worldmonitor-<hash>-eliewm.vercel.app),
so the regex could never match an eliewm preview regardless of the slug value.
Net effect: PRO widgets stayed dark on every preview deployment.
Fix the regex shape to treat the team slug as the final hostname segment and
set the slug to `eliewm`, matching the same tight shape now used by
server/cors.ts, api/_cors.js, and the api-cors-preflight Worker (still no bare
*.vercel.app — the team-slug gate remains the load-bearing invariant).
Update tests/widget-builder.test.mjs: the hand-mirrored matcher shape, the
slug assertion, the vm-driven sandbox behavior test, and the look-alike
rejections (foreign team, suffix spoof, xeliewm prefix collision, and the
retired personal scope worldmonitor-*-elie-<hash>).
---------
Co-authored-by: e <e@e.co>
0 commit comments