From c866b7db3971b337828976c841ad8169771a3797 Mon Sep 17 00:00:00 2001 From: Rhys Sullivan <39114868+RhysSullivan@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:49:38 -0700 Subject: [PATCH 1/4] Test v2 marketing, telemetry proxies and v1's terms on executor.sh --- apps/cloud/src/edge/marketing.test.ts | 400 ++++++++++++++---- apps/cloud/src/edge/production-config.test.ts | 11 + 2 files changed, 337 insertions(+), 74 deletions(-) diff --git a/apps/cloud/src/edge/marketing.test.ts b/apps/cloud/src/edge/marketing.test.ts index 66645162dd..9c77fbfd9b 100644 --- a/apps/cloud/src/edge/marketing.test.ts +++ b/apps/cloud/src/edge/marketing.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from "@effect/vitest"; import { isMarketingPath, isSignUpPath, + isV2MarketingPath, isV2Path, marketingProxyRequest, parseV2Edge, @@ -11,88 +12,38 @@ import { type V2Service, } from "./marketing"; -// On executor.sh the marketing middleware proxies an allow-list of paths to the -// `executor-marketing` worker; everything else falls through to the auth-gated -// cloud app (the sign-in page). `/blog` and `/llms.txt` are public content, so -// they must be on the allow-list: without it an unauthenticated visit redirects -// to `/login?returnTo=...` and the reader bounces. +// On executor.sh only v1's terms of service (and their asset root) still go to +// v1's `executor-marketing` worker; v2 serves the rest of marketing. describe("isMarketingPath", () => { - const marketing = [ + const v1Marketing = ["/terms", "/terms/", "/_v1-marketing/Layout.css", "/_v1-marketing/_ph/e"]; + for (const pathname of v1Marketing) { + it(`sends ${pathname} to v1's marketing worker`, () => { + expect(isMarketingPath(pathname)).toBe(true); + }); + } + + const notV1Marketing = [ + "/", "/home", "/privacy", - "/terms", "/pricing", - "/about-executor", - "/google-oauth", - "/google-workspace", "/blog", - "/blog/", - "/blog/some-post", - "/llms.txt", - "/index.md", - "/setup-prompt.md", - "/pricing.md", - "/og-image.png", "/_astro/app.css", - // The blog author card loads its avatar from marketing's public/authors; - // without this the pfp 404s on every post. - "/authors/rhys-sullivan.png", + "/_astro/_ph/e", + "/termsandconditions", + "/_v1-marketingx", + "/login", ]; - for (const pathname of marketing) { - it(`proxies ${pathname} to marketing`, () => { - expect(isMarketingPath(pathname)).toBe(true); - }); - } - - // App-owned routes must reach the Effect handler, not marketing. `/blogger` - // guards against a bare `startsWith("/blog")` swallowing unrelated words. - const notMarketing = ["/", "/login", "/cloud", "/mcp", "/dashboard", "/blogger"]; - for (const pathname of notMarketing) { - it(`leaves ${pathname} alone`, () => { + for (const pathname of notV1Marketing) { + it(`does not send ${pathname} to v1's marketing worker`, () => { expect(isMarketingPath(pathname)).toBe(false); }); } }); describe("marketingProxyRequest", () => { - it("routes a signed-out homepage request", () => { - const request = new Request("https://executor.sh/?source=test"); - - const proxied = marketingProxyRequest(request); - - expect(proxied?.url).toBe("https://executor.sh/?source=test"); - }); - - it("leaves the signed-in homepage with the cloud application", () => { - const request = new Request("https://executor.sh/", { - headers: { cookie: "other=value; wos-session=sealed" }, - }); - - expect(marketingProxyRequest(request)).toBeNull(); - }); - - it("routes public content even when a session cookie is present", () => { - const request = new Request("https://executor.sh/blog/post", { - headers: { cookie: "wos-session=sealed" }, - }); - - expect(marketingProxyRequest(request)?.url).toBe("https://executor.sh/blog/post"); - }); - - it("routes /pricing to the marketing worker", () => { - const request = new Request("https://executor.sh/pricing"); - - expect(marketingProxyRequest(request)?.url).toBe("https://executor.sh/pricing"); - }); - - it("rewrites the public home alias to the marketing root", () => { - const request = new Request("https://executor.sh/home?source=test"); - - expect(marketingProxyRequest(request)?.url).toBe("https://executor.sh/?source=test"); - }); - - it("preserves the request method, headers, and body", async () => { - const request = new Request("https://executor.sh/_astro/_ph/capture", { + it("routes v1's terms, method, headers and body unchanged", async () => { + const request = new Request("https://executor.sh/_v1-marketing/_ph/capture?ip=1", { method: "POST", headers: { "content-type": "application/json", "x-request-id": "request-1" }, body: JSON.stringify({ event: "test" }), @@ -100,14 +51,23 @@ describe("marketingProxyRequest", () => { const proxied = marketingProxyRequest(request); + expect(proxied?.url).toBe("https://executor.sh/_v1-marketing/_ph/capture?ip=1"); expect(proxied?.method).toBe("POST"); expect(proxied?.headers.get("x-request-id")).toBe("request-1"); await expect(proxied?.json()).resolves.toEqual({ event: "test" }); + expect(marketingProxyRequest(new Request("https://executor.sh/terms"))?.url).toBe( + "https://executor.sh/terms", + ); }); - it("does not proxy non-production hosts or app-owned paths", () => { - expect(marketingProxyRequest(new Request("http://executor-cloud.localhost/"))).toBeNull(); - expect(marketingProxyRequest(new Request("https://executor.sh/login"))).toBeNull(); + it("leaves the homepage and v2's marketing to the v2 edge", () => { + expect(marketingProxyRequest(new Request("https://executor.sh/"))).toBeNull(); + expect(marketingProxyRequest(new Request("https://executor.sh/home"))).toBeNull(); + expect(marketingProxyRequest(new Request("https://executor.sh/pricing"))).toBeNull(); + }); + + it("does not proxy non-production hosts", () => { + expect(marketingProxyRequest(new Request("http://executor-cloud.localhost/terms"))).toBeNull(); }); }); @@ -152,9 +112,9 @@ describe("isV2Path", () => { "/github", "/.well-known/agent-skills", "/.well-known/agent-skillset/index.json", - // The connected-account callback goes by its state, not its path. + // The connected-account callback goes by its state, not its path, and + // marketing has its own list. "/api/oauth/callback", - // Not yet: marketing. "/pricing", // v1 dashboard, org pages and MCP, including org slugs that look similar. "/", @@ -190,6 +150,7 @@ describe("parseV2Edge", () => { V2: service, V2_SIGN_UP_URL: "https://app.executor.sh/login?mode=signup", V2_OAUTH_STATE_PREFIX: "x2.", + V2_TELEMETRY_PATHS: "/api/0123456789abcdef,/api/fedcba9876543210", }; it("is off when no setting is present", () => { @@ -200,6 +161,7 @@ describe("parseV2Edge", () => { expect(typeof parseV2Edge({ ...settings, V2: undefined })).toBe("string"); expect(typeof parseV2Edge({ ...settings, V2_SIGN_UP_URL: undefined })).toBe("string"); expect(typeof parseV2Edge({ ...settings, V2_OAUTH_STATE_PREFIX: undefined })).toBe("string"); + expect(typeof parseV2Edge({ ...settings, V2_TELEMETRY_PATHS: undefined })).toBe("string"); expect(typeof parseV2Edge({ V2_OAUTH_STATE_PREFIX: "x2." })).toBe("string"); }); @@ -220,24 +182,52 @@ describe("parseV2Edge", () => { } }); + it("refuses telemetry roots outside /api/<16 hex>", () => { + for (const paths of [ + "", + "/api/0123456789abcde", + "/api/0123456789abcdef0", + "/api/0123456789ABCDEF", + "/api/0123456789abcdef/", + "/api/0123456789abcdef/submit", + "/api/connections", + "/0123456789abcdef", + "/api/0123456789abcdef,", + "/api/0123456789abcdef;/api/fedcba9876543210", + ]) { + expect(typeof parseV2Edge({ ...settings, V2_TELEMETRY_PATHS: paths })).toBe("string"); + } + }); + it("parses all settings", () => { const edge = parseV2Edge(settings); if (edge === null || typeof edge === "string") return expect.unreachable("settings must parse"); expect(edge.signUpUrl.href).toBe("https://app.executor.sh/login?mode=signup"); expect(edge.oauthStatePrefix).toBe("x2."); + expect(edge.telemetryPaths).toEqual(["/api/0123456789abcdef", "/api/fedcba9876543210"]); expect(typeof parseV2Edge({ ...settings, V2_OAUTH_STATE_PREFIX: "v2~" })).toBe("object"); + const spaced = parseV2Edge({ + ...settings, + V2_TELEMETRY_PATHS: " /api/0123456789abcdef , /api/fedcba9876543210 ", + }); + if (spaced === null || typeof spaced === "string") { + return expect.unreachable("settings must parse"); + } + expect(spaced.telemetryPaths).toEqual(["/api/0123456789abcdef", "/api/fedcba9876543210"]); }); }); describe("v2EdgeResponse", () => { const SIGN_UP_URL = "https://v2.executor.sh/login?mode=signup"; const STATE_PREFIX = "x2."; + const TELEMETRY_PATHS = "/api/0123456789abcdef"; /** The edge's settings with `service` as v2's Worker. */ const settings = (service: V2Service, signUpUrl = SIGN_UP_URL): V2EdgeEnv => ({ V2: service, V2_SIGN_UP_URL: signUpUrl, V2_OAUTH_STATE_PREFIX: STATE_PREFIX, + V2_TELEMETRY_PATHS: TELEMETRY_PATHS, }); /** A v2 service that records what it receives and answers with `respond`. */ @@ -440,6 +430,7 @@ describe("v2EdgeResponse connected-account callback", () => { V2: service, V2_SIGN_UP_URL: "https://app.executor.sh/login?mode=signup", V2_OAUTH_STATE_PREFIX: "x2.", + V2_TELEMETRY_PATHS: "/api/0123456789abcdef", }); const recordingService = () => { @@ -571,3 +562,264 @@ describe("v2EdgeResponse connected-account callback", () => { expect(received).toHaveLength(0); }); }); + +// v2's marketing site answers executor.sh: the landing page without a v1 +// session, its pages, files, assets and docs, and its telemetry proxies. +describe("isV2MarketingPath", () => { + const v2Marketing = [ + "/home", + "/about-executor", + "/blog", + "/blog/", + "/blog/some-post", + "/pricing", + "/privacy", + "/google-oauth", + "/google-workspace", + "/index.md", + "/llms.txt", + "/pricing.md", + "/setup-prompt.md", + "/_astro/app.Cld-QA3g.css", + "/authors/author.png", + "/og-image.png", + "/pattern-graph-paper.svg", + "/docs", + "/docs/", + "/docs/quickstart", + "/docs/llms.txt", + ]; + for (const pathname of v2Marketing) { + it(`sends ${pathname} to v2`, () => { + expect(isV2MarketingPath(pathname)).toBe(true); + }); + } + + const v1Owned = [ + // The homepage depends on the session; see v2EdgeResponse. + "/", + // v2 marketing paths that are unreserved v1 organization slugs. + "/apps", + "/apps/acme/tools", + "/demo", + "/demo/workflows", + "/experiments/hero/b", + // v1's terms, and its dashboard's favicons. + "/terms", + "/favicon.ico", + "/favicon-32.png", + "/apple-touch-icon.png", + // Lookalikes and v1 routes. + "/blogger", + "/docsearch", + "/_astrox/app.css", + "/home-team/policies", + "/pricing-team/mcp", + "/setup", + "/login", + "/api/docs", + "/acme/docs", + ]; + for (const pathname of v1Owned) { + it(`leaves ${pathname} with v1`, () => { + expect(isV2MarketingPath(pathname)).toBe(false); + }); + } +}); + +describe("v2EdgeResponse marketing", () => { + const settings = (service: V2Service): V2EdgeEnv => ({ + V2: service, + V2_SIGN_UP_URL: "https://app.executor.sh/login?mode=signup", + V2_OAUTH_STATE_PREFIX: "x2.", + V2_TELEMETRY_PATHS: "/api/0123456789abcdef,/api/fedcba9876543210", + }); + + const recordingService = (respond: () => Response = () => new Response("v2")) => { + const received: Request[] = []; + const service: V2Service = { + fetch: async (request) => { + received.push(request); + return respond(); + }, + }; + return { received, service }; + }; + + it("sends the signed-out homepage to v2 with the URL unchanged", async () => { + const { received, service } = recordingService(); + + const response = await v2EdgeResponse( + new Request("https://executor.sh/?hero=b&utm_source=x"), + settings(service), + ); + + expect(await response?.text()).toBe("v2"); + expect(received[0]?.url).toBe("https://executor.sh/?hero=b&utm_source=x"); + expect(received[0]?.redirect).toBe("manual"); + }); + + it("keeps the signed-in homepage with v1's dashboard", () => { + const { received, service } = recordingService(); + + expect( + v2EdgeResponse( + new Request("https://executor.sh/", { + headers: { cookie: "executor_visitor=v; wos-session=sealed" }, + }), + settings(service), + ), + ).toBeNull(); + expect(received).toHaveLength(0); + }); + + it("passes only v2's visitor cookie, never v1's session", async () => { + const { received, service } = recordingService(); + + await v2EdgeResponse( + new Request("https://executor.sh/blog/post", { + headers: { + cookie: + "ph_id=1; executor_visitor=0f1e2d3c-4b5a-4987-a6b5-c4d3e2f1a0b9; wos-session=sealed", + "x-forwarded-host": "attacker.example", + }, + }), + settings(service), + ); + await v2EdgeResponse( + new Request("https://executor.sh/", { headers: { cookie: "ph_id=1; executor_hero=x" } }), + settings(service), + ); + + expect(received[0]?.headers.get("cookie")).toBe( + "executor_visitor=0f1e2d3c-4b5a-4987-a6b5-c4d3e2f1a0b9", + ); + expect(received[0]?.headers.has("x-forwarded-host")).toBe(false); + expect(received[1]?.headers.has("cookie")).toBe(false); + }); + + it("serves /home, docs and assets from v2 without rewriting the path", async () => { + const { received, service } = recordingService(); + + for (const url of [ + "https://executor.sh/home?ref=x", + "https://executor.sh/docs/quickstart", + "https://executor.sh/_astro/app.css", + "https://executor.sh/llms.txt", + ]) { + await v2EdgeResponse(new Request(url), settings(service)); + } + + expect(received.map((request) => request.url)).toEqual([ + "https://executor.sh/home?ref=x", + "https://executor.sh/docs/quickstart", + "https://executor.sh/_astro/app.css", + "https://executor.sh/llms.txt", + ]); + }); + + it("returns v2's response unchanged, its cookies included", async () => { + const upstream = new Response("", { + status: 200, + headers: { + "content-type": "text/html", + "set-cookie": "executor_visitor=v; Path=/; SameSite=Lax; Secure", + vary: "Cookie", + }, + }); + const { service } = recordingService(() => upstream); + + expect(await v2EdgeResponse(new Request("https://executor.sh/"), settings(service))).toBe( + upstream, + ); + }); + + it("answers marketing with a 500 on broken settings", async () => { + const { received, service } = recordingService(); + + const response = await v2EdgeResponse(new Request("https://executor.sh/pricing"), { + ...settings(service), + V2_TELEMETRY_PATHS: "/api/nothex", + }); + + expect(response?.status).toBe(500); + expect(received).toHaveLength(0); + }); + + it("is off without settings and off executor.sh", () => { + const { received, service } = recordingService(); + + expect(v2EdgeResponse(new Request("https://executor.sh/"), {})).toBeNull(); + expect(v2EdgeResponse(new Request("https://executor.sh/pricing"), {})).toBeNull(); + expect( + v2EdgeResponse(new Request("http://executor-cloud.localhost/"), settings(service)), + ).toBeNull(); + expect( + v2EdgeResponse(new Request("http://executor-cloud.localhost/docs"), settings(service)), + ).toBeNull(); + expect(received).toHaveLength(0); + }); + + it("forwards v2's telemetry proxies without cookies, body and method intact", async () => { + const { received, service } = recordingService(); + + await v2EdgeResponse( + new Request("https://executor.sh/api/0123456789abcdef/e/?ip=1", { + method: "POST", + headers: { cookie: "wos-session=sealed", "content-type": "text/plain" }, + body: "event", + }), + settings(service), + ); + await v2EdgeResponse( + new Request("https://executor.sh/api/fedcba9876543210/submit", { method: "POST" }), + settings(service), + ); + await v2EdgeResponse( + new Request("https://executor.sh/api/0123456789abcdef"), + settings(service), + ); + + expect(received.map((request) => request.url)).toEqual([ + "https://executor.sh/api/0123456789abcdef/e/?ip=1", + "https://executor.sh/api/fedcba9876543210/submit", + "https://executor.sh/api/0123456789abcdef", + ]); + expect(received[0]?.method).toBe("POST"); + expect(received[0]?.headers.has("cookie")).toBe(false); + expect(await received[0]?.text()).toBe("event"); + }); + + const v1Api = [ + // Another 16-hex root, and v1's own PostHog proxy (8 hex). + "https://executor.sh/api/aaaaaaaaaaaaaaaa/e/", + "https://executor.sh/api/0a1b2c3d/e/", + // Lookalikes of a configured root. + "https://executor.sh/api/0123456789abcdef0/e/", + "https://executor.sh/api/0123456789abcdefx", + "https://executor.sh/0123456789abcdef/e/", + "https://executor.sh/acme/api/0123456789abcdef/e/", + // v1's API. + "https://executor.sh/api/connections", + "https://executor.sh/api/docs", + ]; + for (const url of v1Api) { + it(`leaves ${new URL(url).pathname} with v1`, () => { + const { received, service } = recordingService(); + expect(v2EdgeResponse(new Request(url), settings(service))).toBeNull(); + expect(received).toHaveLength(0); + }); + } + + it("leaves telemetry roots with v1 when the settings are broken", () => { + const { received, service } = recordingService(); + + expect( + v2EdgeResponse(new Request("https://executor.sh/api/0123456789abcdef/e/"), { + ...settings(service), + V2_SIGN_UP_URL: "/relative", + }), + ).toBeNull(); + expect(received).toHaveLength(0); + }); +}); diff --git a/apps/cloud/src/edge/production-config.test.ts b/apps/cloud/src/edge/production-config.test.ts index 5ec0621d0d..e2b737b000 100644 --- a/apps/cloud/src/edge/production-config.test.ts +++ b/apps/cloud/src/edge/production-config.test.ts @@ -29,6 +29,7 @@ const shipped: V2EdgeEnv = { V2: standIn, V2_SIGN_UP_URL: stringVar("V2_SIGN_UP_URL"), V2_OAUTH_STATE_PREFIX: stringVar("V2_OAUTH_STATE_PREFIX"), + V2_TELEMETRY_PATHS: stringVar("V2_TELEMETRY_PATHS"), }; describe("production v2 edge settings", () => { @@ -50,4 +51,14 @@ describe("production v2 edge settings", () => { if (edge === null || typeof edge === "string") return expect.unreachable("settings must parse"); expect(edge.oauthStatePrefix).toBe("x2."); }); + + it("ships v2's analytics and error-reporting proxy roots", () => { + const edge = parseV2Edge(shipped); + if (edge === null || typeof edge === "string") return expect.unreachable("settings must parse"); + expect(edge.telemetryPaths).toHaveLength(2); + }); + + it("keeps the MARKETING binding for v1's terms", () => { + expect(config.services.filter((service) => service.binding === "MARKETING")).toHaveLength(1); + }); }); From 9b317658d2a562011292a675795f101d5c47811c Mon Sep 17 00:00:00 2001 From: Rhys Sullivan <39114868+RhysSullivan@users.noreply.github.com> Date: Thu, 8 Oct 2026 06:39:01 -0700 Subject: [PATCH 2/4] Test v1's edge against v2's pinned edge contract --- .oxfmtrc.json | 3 +- apps/cloud/src/edge/marketing.test.ts | 131 +++++++++++++----- apps/cloud/src/edge/production-config.test.ts | 87 +++++++++++- apps/cloud/src/edge/v2-edge-contract.json | 107 ++++++++++++++ 4 files changed, 286 insertions(+), 42 deletions(-) create mode 100644 apps/cloud/src/edge/v2-edge-contract.json diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 73f7255814..5662270268 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -14,6 +14,7 @@ "executor-*.tgz", "**/routeTree.gen.ts", "**/smoke-harness-bundle.gen.ts", - "apps/cloud/src/services/executor-schema.ts" + "apps/cloud/src/services/executor-schema.ts", + "apps/cloud/src/edge/v2-edge-contract.json" ] } diff --git a/apps/cloud/src/edge/marketing.test.ts b/apps/cloud/src/edge/marketing.test.ts index 9c77fbfd9b..a61f393524 100644 --- a/apps/cloud/src/edge/marketing.test.ts +++ b/apps/cloud/src/edge/marketing.test.ts @@ -12,10 +12,18 @@ import { type V2Service, } from "./marketing"; -// On executor.sh only v1's terms of service (and their asset root) still go to -// v1's `executor-marketing` worker; v2 serves the rest of marketing. +// On executor.sh only v1's legal pages (terms, privacy policy and Google OAuth +// disclosure) and their asset root still go to v1's `executor-marketing` +// worker; v2 serves the rest of marketing. describe("isMarketingPath", () => { - const v1Marketing = ["/terms", "/terms/", "/_v1-marketing/Layout.css", "/_v1-marketing/_ph/e"]; + const v1Marketing = [ + "/terms", + "/terms/", + "/privacy", + "/google-oauth", + "/_v1-marketing/Layout.css", + "/_v1-marketing/_ph/e", + ]; for (const pathname of v1Marketing) { it(`sends ${pathname} to v1's marketing worker`, () => { expect(isMarketingPath(pathname)).toBe(true); @@ -25,12 +33,14 @@ describe("isMarketingPath", () => { const notV1Marketing = [ "/", "/home", - "/privacy", "/pricing", "/blog", + "/google-workspace", "/_astro/app.css", "/_astro/_ph/e", "/termsandconditions", + "/privacy-team/mcp", + "/google-oauthx", "/_v1-marketingx", "/login", ]; @@ -55,9 +65,11 @@ describe("marketingProxyRequest", () => { expect(proxied?.method).toBe("POST"); expect(proxied?.headers.get("x-request-id")).toBe("request-1"); await expect(proxied?.json()).resolves.toEqual({ event: "test" }); - expect(marketingProxyRequest(new Request("https://executor.sh/terms"))?.url).toBe( - "https://executor.sh/terms", - ); + for (const path of ["/terms", "/privacy", "/google-oauth"]) { + expect(marketingProxyRequest(new Request(`https://executor.sh${path}`))?.url).toBe( + `https://executor.sh${path}`, + ); + } }); it("leaves the homepage and v2's marketing to the v2 edge", () => { @@ -150,7 +162,8 @@ describe("parseV2Edge", () => { V2: service, V2_SIGN_UP_URL: "https://app.executor.sh/login?mode=signup", V2_OAUTH_STATE_PREFIX: "x2.", - V2_TELEMETRY_PATHS: "/api/0123456789abcdef,/api/fedcba9876543210", + V2_ANALYTICS_PROXY_PATH: "/api/0123456789abcdef", + V2_ERROR_TUNNEL_PATH: "/api/fedcba9876543210/submit", }; it("is off when no setting is present", () => { @@ -161,7 +174,8 @@ describe("parseV2Edge", () => { expect(typeof parseV2Edge({ ...settings, V2: undefined })).toBe("string"); expect(typeof parseV2Edge({ ...settings, V2_SIGN_UP_URL: undefined })).toBe("string"); expect(typeof parseV2Edge({ ...settings, V2_OAUTH_STATE_PREFIX: undefined })).toBe("string"); - expect(typeof parseV2Edge({ ...settings, V2_TELEMETRY_PATHS: undefined })).toBe("string"); + expect(typeof parseV2Edge({ ...settings, V2_ANALYTICS_PROXY_PATH: undefined })).toBe("string"); + expect(typeof parseV2Edge({ ...settings, V2_ERROR_TUNNEL_PATH: undefined })).toBe("string"); expect(typeof parseV2Edge({ V2_OAUTH_STATE_PREFIX: "x2." })).toBe("string"); }); @@ -182,8 +196,8 @@ describe("parseV2Edge", () => { } }); - it("refuses telemetry roots outside /api/<16 hex>", () => { - for (const paths of [ + it("refuses an analytics proxy path other than /api/<16 lowercase hex>", () => { + for (const path of [ "", "/api/0123456789abcde", "/api/0123456789abcdef0", @@ -192,10 +206,27 @@ describe("parseV2Edge", () => { "/api/0123456789abcdef/submit", "/api/connections", "/0123456789abcdef", - "/api/0123456789abcdef,", - "/api/0123456789abcdef;/api/fedcba9876543210", + " /api/0123456789abcdef", + "/api/0123456789abcdef,/api/fedcba9876543210", + ]) { + expect(typeof parseV2Edge({ ...settings, V2_ANALYTICS_PROXY_PATH: path })).toBe("string"); + } + }); + + it("refuses an error tunnel path other than /api/<16 lowercase hex>/submit", () => { + for (const path of [ + "", + "/api/fedcba9876543210", + "/api/fedcba9876543210/", + "/api/fedcba9876543210/submit/", + "/api/fedcba9876543210/submitx", + "/api/FEDCBA9876543210/submit", + "/api/fedcba987654321/submit", + "/api/fedcba9876543210/e", + "/fedcba9876543210/submit", + " /api/fedcba9876543210/submit", ]) { - expect(typeof parseV2Edge({ ...settings, V2_TELEMETRY_PATHS: paths })).toBe("string"); + expect(typeof parseV2Edge({ ...settings, V2_ERROR_TUNNEL_PATH: path })).toBe("string"); } }); @@ -204,30 +235,23 @@ describe("parseV2Edge", () => { if (edge === null || typeof edge === "string") return expect.unreachable("settings must parse"); expect(edge.signUpUrl.href).toBe("https://app.executor.sh/login?mode=signup"); expect(edge.oauthStatePrefix).toBe("x2."); - expect(edge.telemetryPaths).toEqual(["/api/0123456789abcdef", "/api/fedcba9876543210"]); + expect(edge.analyticsProxyPath).toBe("/api/0123456789abcdef"); + expect(edge.errorTunnelPath).toBe("/api/fedcba9876543210/submit"); expect(typeof parseV2Edge({ ...settings, V2_OAUTH_STATE_PREFIX: "v2~" })).toBe("object"); - const spaced = parseV2Edge({ - ...settings, - V2_TELEMETRY_PATHS: " /api/0123456789abcdef , /api/fedcba9876543210 ", - }); - if (spaced === null || typeof spaced === "string") { - return expect.unreachable("settings must parse"); - } - expect(spaced.telemetryPaths).toEqual(["/api/0123456789abcdef", "/api/fedcba9876543210"]); }); }); describe("v2EdgeResponse", () => { const SIGN_UP_URL = "https://v2.executor.sh/login?mode=signup"; const STATE_PREFIX = "x2."; - const TELEMETRY_PATHS = "/api/0123456789abcdef"; /** The edge's settings with `service` as v2's Worker. */ const settings = (service: V2Service, signUpUrl = SIGN_UP_URL): V2EdgeEnv => ({ V2: service, V2_SIGN_UP_URL: signUpUrl, V2_OAUTH_STATE_PREFIX: STATE_PREFIX, - V2_TELEMETRY_PATHS: TELEMETRY_PATHS, + V2_ANALYTICS_PROXY_PATH: "/api/0123456789abcdef", + V2_ERROR_TUNNEL_PATH: "/api/fedcba9876543210/submit", }); /** A v2 service that records what it receives and answers with `respond`. */ @@ -430,7 +454,8 @@ describe("v2EdgeResponse connected-account callback", () => { V2: service, V2_SIGN_UP_URL: "https://app.executor.sh/login?mode=signup", V2_OAUTH_STATE_PREFIX: "x2.", - V2_TELEMETRY_PATHS: "/api/0123456789abcdef", + V2_ANALYTICS_PROXY_PATH: "/api/0123456789abcdef", + V2_ERROR_TUNNEL_PATH: "/api/fedcba9876543210/submit", }); const recordingService = () => { @@ -564,7 +589,8 @@ describe("v2EdgeResponse connected-account callback", () => { }); // v2's marketing site answers executor.sh: the landing page without a v1 -// session, its pages, files, assets and docs, and its telemetry proxies. +// session, its pages, files, assets and docs, and its telemetry proxies. A +// pattern is exact, or `/x/*` for everything that starts with `/x/`. describe("isV2MarketingPath", () => { const v2Marketing = [ "/home", @@ -573,8 +599,6 @@ describe("isV2MarketingPath", () => { "/blog/", "/blog/some-post", "/pricing", - "/privacy", - "/google-oauth", "/google-workspace", "/index.md", "/llms.txt", @@ -588,6 +612,12 @@ describe("isV2MarketingPath", () => { "/docs/", "/docs/quickstart", "/docs/llms.txt", + // `apps` and `experiments` are reserved v1 organization slugs. + "/apps", + "/apps/", + "/apps/detail", + "/experiments/", + "/experiments/hero/b", ]; for (const pathname of v2Marketing) { it(`sends ${pathname} to v2`, () => { @@ -598,19 +628,31 @@ describe("isV2MarketingPath", () => { const v1Owned = [ // The homepage depends on the session; see v2EdgeResponse. "/", - // v2 marketing paths that are unreserved v1 organization slugs. - "/apps", - "/apps/acme/tools", + // `/demo` is an unreserved v1 organization slug; v2 publishes nothing at + // a bare `/experiments`. "/demo", "/demo/workflows", - "/experiments/hero/b", - // v1's terms, and its dashboard's favicons. + "/experiments", + // Exact pages match only themselves, and directories only what is below + // them. + "/pricing/extra", + "/home/extra", + "/home/", + "/llms.txt/x", + "/_astro", + "/authors", + "/google-workspace/x", + // v1's legal pages, and its dashboard's favicons. "/terms", + "/privacy", + "/google-oauth", "/favicon.ico", "/favicon-32.png", "/apple-touch-icon.png", // Lookalikes and v1 routes. "/blogger", + "/appsmith", + "/experimentsx/a", "/docsearch", "/_astrox/app.css", "/home-team/policies", @@ -632,7 +674,8 @@ describe("v2EdgeResponse marketing", () => { V2: service, V2_SIGN_UP_URL: "https://app.executor.sh/login?mode=signup", V2_OAUTH_STATE_PREFIX: "x2.", - V2_TELEMETRY_PATHS: "/api/0123456789abcdef,/api/fedcba9876543210", + V2_ANALYTICS_PROXY_PATH: "/api/0123456789abcdef", + V2_ERROR_TUNNEL_PATH: "/api/fedcba9876543210/submit", }); const recordingService = (respond: () => Response = () => new Response("v2")) => { @@ -737,12 +780,17 @@ describe("v2EdgeResponse marketing", () => { it("answers marketing with a 500 on broken settings", async () => { const { received, service } = recordingService(); - const response = await v2EdgeResponse(new Request("https://executor.sh/pricing"), { + const brokenAnalytics = await v2EdgeResponse(new Request("https://executor.sh/pricing"), { ...settings(service), - V2_TELEMETRY_PATHS: "/api/nothex", + V2_ANALYTICS_PROXY_PATH: "/api/nothex", + }); + const brokenTunnel = await v2EdgeResponse(new Request("https://executor.sh/pricing"), { + ...settings(service), + V2_ERROR_TUNNEL_PATH: "/api/fedcba9876543210", }); - expect(response?.status).toBe(500); + expect(brokenAnalytics?.status).toBe(500); + expect(brokenTunnel?.status).toBe(500); expect(received).toHaveLength(0); }); @@ -793,6 +841,13 @@ describe("v2EdgeResponse marketing", () => { const v1Api = [ // Another 16-hex root, and v1's own PostHog proxy (8 hex). "https://executor.sh/api/aaaaaaaaaaaaaaaa/e/", + "https://executor.sh/api/aaaaaaaaaaaaaaaa/submit", + // The error tunnel is forwarded exactly: not its root or other subpaths. + "https://executor.sh/api/fedcba9876543210", + "https://executor.sh/api/fedcba9876543210/", + "https://executor.sh/api/fedcba9876543210/e/", + "https://executor.sh/api/fedcba9876543210/submit/", + "https://executor.sh/api/fedcba9876543210/submit/x", "https://executor.sh/api/0a1b2c3d/e/", // Lookalikes of a configured root. "https://executor.sh/api/0123456789abcdef0/e/", diff --git a/apps/cloud/src/edge/production-config.test.ts b/apps/cloud/src/edge/production-config.test.ts index e2b737b000..c9dac4cc9f 100644 --- a/apps/cloud/src/edge/production-config.test.ts +++ b/apps/cloud/src/edge/production-config.test.ts @@ -1,3 +1,4 @@ +import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "@effect/vitest"; @@ -29,7 +30,8 @@ const shipped: V2EdgeEnv = { V2: standIn, V2_SIGN_UP_URL: stringVar("V2_SIGN_UP_URL"), V2_OAUTH_STATE_PREFIX: stringVar("V2_OAUTH_STATE_PREFIX"), - V2_TELEMETRY_PATHS: stringVar("V2_TELEMETRY_PATHS"), + V2_ANALYTICS_PROXY_PATH: stringVar("V2_ANALYTICS_PROXY_PATH"), + V2_ERROR_TUNNEL_PATH: stringVar("V2_ERROR_TUNNEL_PATH"), }; describe("production v2 edge settings", () => { @@ -52,13 +54,92 @@ describe("production v2 edge settings", () => { expect(edge.oauthStatePrefix).toBe("x2."); }); - it("ships v2's analytics and error-reporting proxy roots", () => { + it("ships v2's analytics proxy root and error tunnel", () => { const edge = parseV2Edge(shipped); if (edge === null || typeof edge === "string") return expect.unreachable("settings must parse"); - expect(edge.telemetryPaths).toHaveLength(2); + expect(edge.analyticsProxyPath).toBe("/api/00e2e1f082a6ef17"); + expect(edge.errorTunnelPath).toBe("/api/fd6fab1fbb4883e1/submit"); }); it("keeps the MARKETING binding for v1's terms", () => { expect(config.services.filter((service) => service.binding === "MARKETING")).toHaveLength(1); }); }); + +// v2 publishes the exact set of executor.sh requests v1's edge forwards to it. +// `v2-edge-contract.json` is a verbatim copy of v2's edge contract; update it +// only together with v2's contract, never by hand here. Every case runs +// through v1's real edge decision with the shipped settings. +const EdgeContract = Schema.Struct({ + origin: Schema.String, + oauthStatePrefix: Schema.String, + telemetry: Schema.Struct({ analyticsProxy: Schema.String, errorTunnel: Schema.String }), + cases: Schema.Array( + Schema.Struct({ method: Schema.String, target: Schema.String, forwards: Schema.Boolean }), + ), +}); +const contract = Schema.decodeUnknownSync(Schema.fromJsonString(EdgeContract))( + readFileSync(fileURLToPath(new URL("./v2-edge-contract.json", import.meta.url)), "utf8"), +); + +const SIGN_UP_TARGETS: ReadonlySet = new Set(["/sign-up", "/signup"]); + +/** Run one contract case through v1's edge with the shipped settings and a + * stand-in for v2's Worker that records every call. */ +const runCase = async (method: string, target: string) => { + const calls: Request[] = []; + const v2: V2Service = { + fetch: (request) => { + calls.push(request); + return Promise.resolve(new Response("v2")); + }, + }; + const request = new Request(`${contract.origin}${target}`, { method }); + const response = await v2EdgeResponse(request, { ...shipped, V2: v2 }); + return { request, calls, response }; +}; + +const forwarded = contract.cases.filter((c) => c.forwards); +const signUps = contract.cases.filter((c) => !c.forwards && SIGN_UP_TARGETS.has(c.target)); +const kept = contract.cases.filter((c) => !c.forwards && !SIGN_UP_TARGETS.has(c.target)); + +describe("v2's edge contract", () => { + it("pins the telemetry paths and state prefix v1 ships", () => { + expect(contract.origin).toBe("https://executor.sh"); + expect(contract.oauthStatePrefix).toBe(stringVar("V2_OAUTH_STATE_PREFIX")); + expect(contract.telemetry.analyticsProxy).toBe(stringVar("V2_ANALYTICS_PROXY_PATH")); + expect(contract.telemetry.errorTunnel).toBe(stringVar("V2_ERROR_TUNNEL_PATH")); + }); + + for (const { method, target } of forwarded) { + it(`forwards ${method} ${target} to v2`, async () => { + const { request, calls, response } = await runCase(method, target); + expect(calls).toHaveLength(1); + expect(calls[0]?.url).toBe(request.url); + expect(calls[0]?.method).toBe(method); + expect(await response?.text()).toBe("v2"); + }); + } + + for (const { method, target } of kept) { + it(`keeps ${method} ${target} with v1`, async () => { + const { calls, response } = await runCase(method, target); + expect(calls).toHaveLength(0); + expect(response).toBeNull(); + }); + } + + // Sign-up is not forwarded: the edge redirects it to v2's sign-up page. + it("lists both sign-up paths as not forwarded", () => { + expect(signUps.map((c) => c.target).toSorted()).toEqual(["/sign-up", "/signup"]); + }); + + for (const { method, target } of signUps) { + it(`redirects ${method} ${target} to v2's sign-up page without forwarding`, async () => { + const { calls, response } = await runCase(method, target); + expect(calls).toHaveLength(0); + expect(response?.status).toBe(302); + expect(response?.headers.get("location")).toBe(stringVar("V2_SIGN_UP_URL")); + }); + } +}); diff --git a/apps/cloud/src/edge/v2-edge-contract.json b/apps/cloud/src/edge/v2-edge-contract.json new file mode 100644 index 0000000000..c6080f276f --- /dev/null +++ b/apps/cloud/src/edge/v2-edge-contract.json @@ -0,0 +1,107 @@ +{ + "source": "UsefulSoftwareCo/executor-next apps/hosted/cloud/src/contracts/edge-contract.json, generated from edgeForwards in apps/hosted/cloud/src/contracts/edge-paths.ts", + "origin": "https://executor.sh", + "oauthStatePrefix": "x2.", + "telemetry": { + "analyticsProxy": "/api/00e2e1f082a6ef17", + "errorTunnel": "/api/fd6fab1fbb4883e1/submit" + }, + "rules": [ + "/.well-known/oauth-authorization-server/api/auth", + "/api/auth/callback/", + "/api/oauth/callback, when state starts with x2.", + "/git/*", + "/ (without a v1 session)", + "/home", + "/pricing", + "/pricing.md", + "/index.md", + "/setup-prompt.md", + "/llms.txt", + "/about-executor", + "/google-workspace", + "/blog", + "/blog/*", + "/docs", + "/docs/*", + "/apps", + "/apps/*", + "/experiments/*", + "/_astro/*", + "/authors/*", + "/og-image.png", + "/pattern-graph-paper.svg", + "/.well-known/agent-skills/*", + "/api/00e2e1f082a6ef17, /api/00e2e1f082a6ef17/*", + "/api/fd6fab1fbb4883e1/submit" + ], + "cases": [ + { "method": "GET", "target": "/.well-known/oauth-authorization-server/api/auth", "forwards": true }, + { "method": "GET", "target": "/api/auth/callback/google?code=c&state=s", "forwards": true }, + { "method": "GET", "target": "/api/auth/callback/github", "forwards": true }, + { "method": "GET", "target": "/api/oauth/callback?code=c&state=x2.abc", "forwards": true }, + { "method": "GET", "target": "/git/acme/site.git/info/refs?service=git-upload-pack", "forwards": true }, + { "method": "POST", "target": "/git/acme/site.git/git-receive-pack", "forwards": true }, + { "method": "GET", "target": "/", "forwards": true }, + { "method": "GET", "target": "/home", "forwards": true }, + { "method": "GET", "target": "/pricing", "forwards": true }, + { "method": "GET", "target": "/pricing.md", "forwards": true }, + { "method": "GET", "target": "/index.md", "forwards": true }, + { "method": "GET", "target": "/setup-prompt.md", "forwards": true }, + { "method": "GET", "target": "/llms.txt", "forwards": true }, + { "method": "GET", "target": "/about-executor", "forwards": true }, + { "method": "GET", "target": "/google-workspace", "forwards": true }, + { "method": "GET", "target": "/blog", "forwards": true }, + { "method": "GET", "target": "/blog/a-post", "forwards": true }, + { "method": "GET", "target": "/docs", "forwards": true }, + { "method": "GET", "target": "/docs/quickstart", "forwards": true }, + { "method": "GET", "target": "/apps", "forwards": true }, + { "method": "GET", "target": "/apps/detail", "forwards": true }, + { "method": "GET", "target": "/experiments/hero/a", "forwards": true }, + { "method": "GET", "target": "/experiments/demo/posthog", "forwards": true }, + { "method": "GET", "target": "/_astro/page.abc123.js", "forwards": true }, + { "method": "GET", "target": "/authors/author.png", "forwards": true }, + { "method": "GET", "target": "/og-image.png", "forwards": true }, + { "method": "GET", "target": "/pattern-graph-paper.svg", "forwards": true }, + { "method": "GET", "target": "/.well-known/agent-skills/index.json", "forwards": true }, + { "method": "GET", "target": "/api/00e2e1f082a6ef17", "forwards": true }, + { "method": "POST", "target": "/api/00e2e1f082a6ef17/e/?ip=0", "forwards": true }, + { "method": "GET", "target": "/api/00e2e1f082a6ef17/static/array.js", "forwards": true }, + { "method": "POST", "target": "/api/fd6fab1fbb4883e1/submit", "forwards": true }, + + { "method": "GET", "target": "/api/auth/.well-known/openid-configuration", "forwards": false }, + { "method": "GET", "target": "/.well-known/oauth-authorization-server", "forwards": false }, + { "method": "GET", "target": "/.well-known/oauth-protected-resource", "forwards": false }, + { "method": "GET", "target": "/api/auth/callback?code=c&state=s", "forwards": false }, + { "method": "GET", "target": "/api/auth/callback/google/extra", "forwards": false }, + { "method": "GET", "target": "/api/auth/login", "forwards": false }, + { "method": "GET", "target": "/api/oauth/callback?code=c&state=abc", "forwards": false }, + { "method": "GET", "target": "/api/oauth/callback?code=c", "forwards": false }, + { "method": "GET", "target": "/oauth/client-metadata.json", "forwards": false }, + { "method": "GET", "target": "/oauth/client-id-metadata.json", "forwards": false }, + { "method": "GET", "target": "/git", "forwards": false }, + { "method": "GET", "target": "/gitlab/repo", "forwards": false }, + { "method": "GET", "target": "/demo", "forwards": false }, + { "method": "GET", "target": "/demo/posthog", "forwards": false }, + { "method": "GET", "target": "/experiments", "forwards": false }, + { "method": "GET", "target": "/privacy", "forwards": false }, + { "method": "GET", "target": "/terms", "forwards": false }, + { "method": "GET", "target": "/google-oauth", "forwards": false }, + { "method": "GET", "target": "/_v1-marketing/style.css", "forwards": false }, + { "method": "GET", "target": "/favicon-32.png", "forwards": false }, + { "method": "GET", "target": "/favicon-192.png", "forwards": false }, + { "method": "GET", "target": "/apple-touch-icon.png", "forwards": false }, + { "method": "GET", "target": "/favicon.ico", "forwards": false }, + { "method": "GET", "target": "/pricing/extra", "forwards": false }, + { "method": "GET", "target": "/home/extra", "forwards": false }, + { "method": "GET", "target": "/login", "forwards": false }, + { "method": "GET", "target": "/sign-up", "forwards": false }, + { "method": "GET", "target": "/signup", "forwards": false }, + { "method": "POST", "target": "/mcp", "forwards": false }, + { "method": "POST", "target": "/acme/mcp", "forwards": false }, + { "method": "GET", "target": "/acme", "forwards": false }, + { "method": "GET", "target": "/api/fd6fab1fbb4883e1", "forwards": false }, + { "method": "GET", "target": "/api/0123456789abcdef/e/", "forwards": false }, + { "method": "POST", "target": "/api/webhooks/workos", "forwards": false } + ] +} From c506cd21dd2ccd8939e5e20d288046ddd80131c4 Mon Sep 17 00:00:00 2001 From: Rhys Sullivan <39114868+RhysSullivan@users.noreply.github.com> Date: Thu, 8 Oct 2026 06:50:49 -0700 Subject: [PATCH 3/4] Test the analytics proxy root stays with v1 and update the pinned contract --- apps/cloud/src/edge/marketing.test.ts | 8 +- apps/cloud/src/edge/v2-edge-contract.json | 406 ++++++++++++++++++---- 2 files changed, 339 insertions(+), 75 deletions(-) diff --git a/apps/cloud/src/edge/marketing.test.ts b/apps/cloud/src/edge/marketing.test.ts index a61f393524..a9761f578b 100644 --- a/apps/cloud/src/edge/marketing.test.ts +++ b/apps/cloud/src/edge/marketing.test.ts @@ -823,15 +823,9 @@ describe("v2EdgeResponse marketing", () => { new Request("https://executor.sh/api/fedcba9876543210/submit", { method: "POST" }), settings(service), ); - await v2EdgeResponse( - new Request("https://executor.sh/api/0123456789abcdef"), - settings(service), - ); - expect(received.map((request) => request.url)).toEqual([ "https://executor.sh/api/0123456789abcdef/e/?ip=1", "https://executor.sh/api/fedcba9876543210/submit", - "https://executor.sh/api/0123456789abcdef", ]); expect(received[0]?.method).toBe("POST"); expect(received[0]?.headers.has("cookie")).toBe(false); @@ -842,6 +836,8 @@ describe("v2EdgeResponse marketing", () => { // Another 16-hex root, and v1's own PostHog proxy (8 hex). "https://executor.sh/api/aaaaaaaaaaaaaaaa/e/", "https://executor.sh/api/aaaaaaaaaaaaaaaa/submit", + // The analytics proxy is forwarded below its root, not the root itself. + "https://executor.sh/api/0123456789abcdef", // The error tunnel is forwarded exactly: not its root or other subpaths. "https://executor.sh/api/fedcba9876543210", "https://executor.sh/api/fedcba9876543210/", diff --git a/apps/cloud/src/edge/v2-edge-contract.json b/apps/cloud/src/edge/v2-edge-contract.json index c6080f276f..b85420b8d5 100644 --- a/apps/cloud/src/edge/v2-edge-contract.json +++ b/apps/cloud/src/edge/v2-edge-contract.json @@ -1,5 +1,5 @@ { - "source": "UsefulSoftwareCo/executor-next apps/hosted/cloud/src/contracts/edge-contract.json, generated from edgeForwards in apps/hosted/cloud/src/contracts/edge-paths.ts", + "source": "Executor v2: apps/hosted/cloud/src/contracts/edge-contract.json, generated by apps/hosted/cloud/scripts/edge-contract.ts from productionEdgeForwards", "origin": "https://executor.sh", "oauthStatePrefix": "x2.", "telemetry": { @@ -32,76 +32,344 @@ "/og-image.png", "/pattern-graph-paper.svg", "/.well-known/agent-skills/*", - "/api/00e2e1f082a6ef17, /api/00e2e1f082a6ef17/*", + "/api/00e2e1f082a6ef17/*", "/api/fd6fab1fbb4883e1/submit" ], "cases": [ - { "method": "GET", "target": "/.well-known/oauth-authorization-server/api/auth", "forwards": true }, - { "method": "GET", "target": "/api/auth/callback/google?code=c&state=s", "forwards": true }, - { "method": "GET", "target": "/api/auth/callback/github", "forwards": true }, - { "method": "GET", "target": "/api/oauth/callback?code=c&state=x2.abc", "forwards": true }, - { "method": "GET", "target": "/git/acme/site.git/info/refs?service=git-upload-pack", "forwards": true }, - { "method": "POST", "target": "/git/acme/site.git/git-receive-pack", "forwards": true }, - { "method": "GET", "target": "/", "forwards": true }, - { "method": "GET", "target": "/home", "forwards": true }, - { "method": "GET", "target": "/pricing", "forwards": true }, - { "method": "GET", "target": "/pricing.md", "forwards": true }, - { "method": "GET", "target": "/index.md", "forwards": true }, - { "method": "GET", "target": "/setup-prompt.md", "forwards": true }, - { "method": "GET", "target": "/llms.txt", "forwards": true }, - { "method": "GET", "target": "/about-executor", "forwards": true }, - { "method": "GET", "target": "/google-workspace", "forwards": true }, - { "method": "GET", "target": "/blog", "forwards": true }, - { "method": "GET", "target": "/blog/a-post", "forwards": true }, - { "method": "GET", "target": "/docs", "forwards": true }, - { "method": "GET", "target": "/docs/quickstart", "forwards": true }, - { "method": "GET", "target": "/apps", "forwards": true }, - { "method": "GET", "target": "/apps/detail", "forwards": true }, - { "method": "GET", "target": "/experiments/hero/a", "forwards": true }, - { "method": "GET", "target": "/experiments/demo/posthog", "forwards": true }, - { "method": "GET", "target": "/_astro/page.abc123.js", "forwards": true }, - { "method": "GET", "target": "/authors/author.png", "forwards": true }, - { "method": "GET", "target": "/og-image.png", "forwards": true }, - { "method": "GET", "target": "/pattern-graph-paper.svg", "forwards": true }, - { "method": "GET", "target": "/.well-known/agent-skills/index.json", "forwards": true }, - { "method": "GET", "target": "/api/00e2e1f082a6ef17", "forwards": true }, - { "method": "POST", "target": "/api/00e2e1f082a6ef17/e/?ip=0", "forwards": true }, - { "method": "GET", "target": "/api/00e2e1f082a6ef17/static/array.js", "forwards": true }, - { "method": "POST", "target": "/api/fd6fab1fbb4883e1/submit", "forwards": true }, - - { "method": "GET", "target": "/api/auth/.well-known/openid-configuration", "forwards": false }, - { "method": "GET", "target": "/.well-known/oauth-authorization-server", "forwards": false }, - { "method": "GET", "target": "/.well-known/oauth-protected-resource", "forwards": false }, - { "method": "GET", "target": "/api/auth/callback?code=c&state=s", "forwards": false }, - { "method": "GET", "target": "/api/auth/callback/google/extra", "forwards": false }, - { "method": "GET", "target": "/api/auth/login", "forwards": false }, - { "method": "GET", "target": "/api/oauth/callback?code=c&state=abc", "forwards": false }, - { "method": "GET", "target": "/api/oauth/callback?code=c", "forwards": false }, - { "method": "GET", "target": "/oauth/client-metadata.json", "forwards": false }, - { "method": "GET", "target": "/oauth/client-id-metadata.json", "forwards": false }, - { "method": "GET", "target": "/git", "forwards": false }, - { "method": "GET", "target": "/gitlab/repo", "forwards": false }, - { "method": "GET", "target": "/demo", "forwards": false }, - { "method": "GET", "target": "/demo/posthog", "forwards": false }, - { "method": "GET", "target": "/experiments", "forwards": false }, - { "method": "GET", "target": "/privacy", "forwards": false }, - { "method": "GET", "target": "/terms", "forwards": false }, - { "method": "GET", "target": "/google-oauth", "forwards": false }, - { "method": "GET", "target": "/_v1-marketing/style.css", "forwards": false }, - { "method": "GET", "target": "/favicon-32.png", "forwards": false }, - { "method": "GET", "target": "/favicon-192.png", "forwards": false }, - { "method": "GET", "target": "/apple-touch-icon.png", "forwards": false }, - { "method": "GET", "target": "/favicon.ico", "forwards": false }, - { "method": "GET", "target": "/pricing/extra", "forwards": false }, - { "method": "GET", "target": "/home/extra", "forwards": false }, - { "method": "GET", "target": "/login", "forwards": false }, - { "method": "GET", "target": "/sign-up", "forwards": false }, - { "method": "GET", "target": "/signup", "forwards": false }, - { "method": "POST", "target": "/mcp", "forwards": false }, - { "method": "POST", "target": "/acme/mcp", "forwards": false }, - { "method": "GET", "target": "/acme", "forwards": false }, - { "method": "GET", "target": "/api/fd6fab1fbb4883e1", "forwards": false }, - { "method": "GET", "target": "/api/0123456789abcdef/e/", "forwards": false }, - { "method": "POST", "target": "/api/webhooks/workos", "forwards": false } + { + "method": "GET", + "target": "/.well-known/oauth-authorization-server/api/auth", + "forwards": true + }, + { + "method": "GET", + "target": "/api/auth/callback/google?code=c&state=s", + "forwards": true + }, + { + "method": "GET", + "target": "/api/auth/callback/github", + "forwards": true + }, + { + "method": "GET", + "target": "/api/oauth/callback?code=c&state=x2.abc", + "forwards": true + }, + { + "method": "GET", + "target": "/git/acme/site.git/info/refs?service=git-upload-pack", + "forwards": true + }, + { + "method": "POST", + "target": "/git/acme/site.git/git-receive-pack", + "forwards": true + }, + { + "method": "GET", + "target": "/", + "forwards": true + }, + { + "method": "GET", + "target": "/home", + "forwards": true + }, + { + "method": "GET", + "target": "/pricing", + "forwards": true + }, + { + "method": "GET", + "target": "/pricing.md", + "forwards": true + }, + { + "method": "GET", + "target": "/index.md", + "forwards": true + }, + { + "method": "GET", + "target": "/setup-prompt.md", + "forwards": true + }, + { + "method": "GET", + "target": "/llms.txt", + "forwards": true + }, + { + "method": "GET", + "target": "/about-executor", + "forwards": true + }, + { + "method": "GET", + "target": "/google-workspace", + "forwards": true + }, + { + "method": "GET", + "target": "/blog", + "forwards": true + }, + { + "method": "GET", + "target": "/blog/a-post", + "forwards": true + }, + { + "method": "GET", + "target": "/docs", + "forwards": true + }, + { + "method": "GET", + "target": "/docs/quickstart", + "forwards": true + }, + { + "method": "GET", + "target": "/apps", + "forwards": true + }, + { + "method": "GET", + "target": "/apps/detail", + "forwards": true + }, + { + "method": "GET", + "target": "/experiments/hero/a", + "forwards": true + }, + { + "method": "GET", + "target": "/experiments/demo/posthog", + "forwards": true + }, + { + "method": "GET", + "target": "/_astro/page.abc123.js", + "forwards": true + }, + { + "method": "GET", + "target": "/authors/author.png", + "forwards": true + }, + { + "method": "GET", + "target": "/og-image.png", + "forwards": true + }, + { + "method": "GET", + "target": "/pattern-graph-paper.svg", + "forwards": true + }, + { + "method": "GET", + "target": "/.well-known/agent-skills/index.json", + "forwards": true + }, + { + "method": "POST", + "target": "/api/00e2e1f082a6ef17/e/?ip=0", + "forwards": true + }, + { + "method": "GET", + "target": "/api/00e2e1f082a6ef17/static/array.js", + "forwards": true + }, + { + "method": "POST", + "target": "/api/fd6fab1fbb4883e1/submit", + "forwards": true + }, + { + "method": "GET", + "target": "/api/auth/.well-known/openid-configuration", + "forwards": false + }, + { + "method": "GET", + "target": "/.well-known/oauth-authorization-server", + "forwards": false + }, + { + "method": "GET", + "target": "/.well-known/oauth-protected-resource", + "forwards": false + }, + { + "method": "GET", + "target": "/api/auth/callback?code=c&state=s", + "forwards": false + }, + { + "method": "GET", + "target": "/api/auth/callback/google/extra", + "forwards": false + }, + { + "method": "GET", + "target": "/api/auth/login", + "forwards": false + }, + { + "method": "GET", + "target": "/api/oauth/callback?code=c&state=abc", + "forwards": false + }, + { + "method": "GET", + "target": "/api/oauth/callback?code=c", + "forwards": false + }, + { + "method": "GET", + "target": "/oauth/client-metadata.json", + "forwards": false + }, + { + "method": "GET", + "target": "/oauth/client-id-metadata.json", + "forwards": false + }, + { + "method": "GET", + "target": "/git", + "forwards": false + }, + { + "method": "GET", + "target": "/gitlab/repo", + "forwards": false + }, + { + "method": "GET", + "target": "/demo", + "forwards": false + }, + { + "method": "GET", + "target": "/demo/posthog", + "forwards": false + }, + { + "method": "GET", + "target": "/experiments", + "forwards": false + }, + { + "method": "GET", + "target": "/privacy", + "forwards": false + }, + { + "method": "GET", + "target": "/terms", + "forwards": false + }, + { + "method": "GET", + "target": "/google-oauth", + "forwards": false + }, + { + "method": "GET", + "target": "/_v1-marketing/style.css", + "forwards": false + }, + { + "method": "GET", + "target": "/favicon-32.png", + "forwards": false + }, + { + "method": "GET", + "target": "/favicon-192.png", + "forwards": false + }, + { + "method": "GET", + "target": "/apple-touch-icon.png", + "forwards": false + }, + { + "method": "GET", + "target": "/favicon.ico", + "forwards": false + }, + { + "method": "GET", + "target": "/pricing/extra", + "forwards": false + }, + { + "method": "GET", + "target": "/home/extra", + "forwards": false + }, + { + "method": "GET", + "target": "/login", + "forwards": false + }, + { + "method": "GET", + "target": "/sign-up", + "forwards": false + }, + { + "method": "GET", + "target": "/signup", + "forwards": false + }, + { + "method": "POST", + "target": "/mcp", + "forwards": false + }, + { + "method": "POST", + "target": "/acme/mcp", + "forwards": false + }, + { + "method": "GET", + "target": "/acme", + "forwards": false + }, + { + "method": "GET", + "target": "/api/00e2e1f082a6ef17", + "forwards": false + }, + { + "method": "GET", + "target": "/api/fd6fab1fbb4883e1", + "forwards": false + }, + { + "method": "POST", + "target": "/api/fd6fab1fbb4883e1/submit/extra", + "forwards": false + }, + { + "method": "GET", + "target": "/api/0123456789abcdef/e/", + "forwards": false + }, + { + "method": "POST", + "target": "/api/webhooks/workos", + "forwards": false + } ] } From 176682df3dd080c620f52bb40bbd1d4256b41889 Mon Sep 17 00:00:00 2001 From: Rhys Sullivan <39114868+RhysSullivan@users.noreply.github.com> Date: Thu, 8 Oct 2026 09:26:05 -0700 Subject: [PATCH 4/4] Test that slashed v2 pages redirect and update the pinned contract --- apps/cloud/src/edge/marketing.test.ts | 73 +++++++++++++++++++ apps/cloud/src/edge/production-config.test.ts | 25 +++++++ apps/cloud/src/edge/v2-edge-contract.json | 53 +++++++++++++- 3 files changed, 150 insertions(+), 1 deletion(-) diff --git a/apps/cloud/src/edge/marketing.test.ts b/apps/cloud/src/edge/marketing.test.ts index a9761f578b..2fdaff85c3 100644 --- a/apps/cloud/src/edge/marketing.test.ts +++ b/apps/cloud/src/edge/marketing.test.ts @@ -8,6 +8,7 @@ import { marketingProxyRequest, parseV2Edge, v2EdgeResponse, + v2PageForSlashedPath, type V2EdgeEnv, type V2Service, } from "./marketing"; @@ -145,6 +146,18 @@ describe("isV2Path", () => { } }); +describe("v2PageForSlashedPath", () => { + it("canonicalizes only v2's exact pages", () => { + expect(v2PageForSlashedPath("/pricing/")).toBe("/pricing"); + expect(v2PageForSlashedPath("/google-workspace/")).toBe("/google-workspace"); + expect(v2PageForSlashedPath("/pricing")).toBeNull(); + expect(v2PageForSlashedPath("/pricing.md/")).toBeNull(); + expect(v2PageForSlashedPath("/blog/")).toBeNull(); + expect(v2PageForSlashedPath("/terms/")).toBeNull(); + expect(v2PageForSlashedPath("/")).toBeNull(); + }); +}); + describe("isSignUpPath", () => { it("claims /sign-up and /signup only", () => { expect(isSignUpPath("/sign-up")).toBe(true); @@ -689,6 +702,66 @@ describe("v2EdgeResponse marketing", () => { return { received, service }; }; + // A signed-out visitor at `/pricing/` would otherwise reach v1's sign-in + // gate, which redirects to login. + it("redirects v2's slashed exact pages to the page, query kept, without forwarding", async () => { + const { received, service } = recordingService(); + + for (const [target, location] of [ + ["/pricing/", "/pricing"], + ["/pricing/?ref=hn", "/pricing?ref=hn"], + ["/home/", "/home"], + ["/about-executor/", "/about-executor"], + ["/google-workspace/", "/google-workspace"], + ] as const) { + for (const method of ["GET", "HEAD"]) { + const response = await v2EdgeResponse( + new Request(`https://executor.sh${target}`, { + method, + headers: { cookie: "wos-session=sealed" }, + }), + settings(service), + ); + expect(response?.status, `${method} ${target}`).toBe(308); + expect(response?.headers.get("location"), `${method} ${target}`).toBe( + `https://executor.sh${location}`, + ); + } + } + expect(received).toHaveLength(0); + }); + + it("forwards the slashed form of a page v2 owns below, such as /blog/", async () => { + const { received, service } = recordingService(); + + const response = await v2EdgeResponse( + new Request("https://executor.sh/docs/"), + settings(service), + ); + + expect(await response?.text()).toBe("v2"); + expect(received[0]?.url).toBe("https://executor.sh/docs/"); + }); + + it("keeps deeper paths, other methods and v1's own slashed pages with v1", () => { + const { received, service } = recordingService(); + + for (const [method, target] of [ + ["GET", "/pricing/extra"], + ["GET", "/home/extra/"], + ["GET", "/pricing//"], + ["POST", "/pricing/"], + ["GET", "/terms/"], + ["GET", "/demo/"], + ] as const) { + expect( + v2EdgeResponse(new Request(`https://executor.sh${target}`, { method }), settings(service)), + `${method} ${target}`, + ).toBeNull(); + } + expect(received).toHaveLength(0); + }); + it("sends the signed-out homepage to v2 with the URL unchanged", async () => { const { received, service } = recordingService(); diff --git a/apps/cloud/src/edge/production-config.test.ts b/apps/cloud/src/edge/production-config.test.ts index c9dac4cc9f..700e3634ff 100644 --- a/apps/cloud/src/edge/production-config.test.ts +++ b/apps/cloud/src/edge/production-config.test.ts @@ -77,6 +77,10 @@ const EdgeContract = Schema.Struct({ cases: Schema.Array( Schema.Struct({ method: Schema.String, target: Schema.String, forwards: Schema.Boolean }), ), + slashRedirects: Schema.Struct({ + pages: Schema.Array(Schema.String), + cases: Schema.Array(Schema.Struct({ target: Schema.String, location: Schema.String })), + }), }); const contract = Schema.decodeUnknownSync(Schema.fromJsonString(EdgeContract))( readFileSync(fileURLToPath(new URL("./v2-edge-contract.json", import.meta.url)), "utf8"), @@ -134,6 +138,27 @@ describe("v2's edge contract", () => { expect(signUps.map((c) => c.target).toSorted()).toEqual(["/sign-up", "/signup"]); }); + // A slashed exact page is not forwarded: the edge redirects it to the page, + // which is. Every page v2 lists has an example. + it("covers every slashed page v2 lists", () => { + expect( + contract.slashRedirects.cases + .map((c) => new URL(c.target, contract.origin).pathname) + .toSorted(), + ).toEqual(expect.arrayContaining(contract.slashRedirects.pages.map((page) => `${page}/`))); + }); + + for (const { target, location } of contract.slashRedirects.cases) { + for (const method of ["GET", "HEAD"]) { + it(`redirects ${method} ${target} to ${location} without forwarding`, async () => { + const { calls, response } = await runCase(method, target); + expect(calls).toHaveLength(0); + expect(response?.status).toBe(308); + expect(response?.headers.get("location")).toBe(`${contract.origin}${location}`); + }); + } + } + for (const { method, target } of signUps) { it(`redirects ${method} ${target} to v2's sign-up page without forwarding`, async () => { const { calls, response } = await runCase(method, target); diff --git a/apps/cloud/src/edge/v2-edge-contract.json b/apps/cloud/src/edge/v2-edge-contract.json index b85420b8d5..8ad182e0e2 100644 --- a/apps/cloud/src/edge/v2-edge-contract.json +++ b/apps/cloud/src/edge/v2-edge-contract.json @@ -116,6 +116,11 @@ "target": "/blog", "forwards": true }, + { + "method": "GET", + "target": "/blog/", + "forwards": true + }, { "method": "GET", "target": "/blog/a-post", @@ -126,6 +131,11 @@ "target": "/docs", "forwards": true }, + { + "method": "GET", + "target": "/docs/", + "forwards": true + }, { "method": "GET", "target": "/docs/quickstart", @@ -316,6 +326,21 @@ "target": "/home/extra", "forwards": false }, + { + "method": "GET", + "target": "/about-executor/extra", + "forwards": false + }, + { + "method": "GET", + "target": "/google-workspace/extra", + "forwards": false + }, + { + "method": "POST", + "target": "/pricing/", + "forwards": false + }, { "method": "GET", "target": "/login", @@ -371,5 +396,31 @@ "target": "/api/webhooks/workos", "forwards": false } - ] + ], + "slashRedirects": { + "rule": "GET or HEAD / answers 308 to , query kept, for each of pages", + "pages": ["/home", "/pricing", "/about-executor", "/google-workspace"], + "cases": [ + { + "target": "/pricing/", + "location": "/pricing" + }, + { + "target": "/pricing/?ref=hn", + "location": "/pricing?ref=hn" + }, + { + "target": "/home/", + "location": "/home" + }, + { + "target": "/about-executor/", + "location": "/about-executor" + }, + { + "target": "/google-workspace/", + "location": "/google-workspace" + } + ] + } }