Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
312 changes: 311 additions & 1 deletion apps/cloud/src/edge/marketing.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { describe, expect, it } from "@effect/vitest";

import { isMarketingPath, marketingProxyRequest } from "./marketing";
import {
isMarketingPath,
isSignUpPath,
isV2Path,
marketingProxyRequest,
parseV2Edge,
v2EdgeResponse,
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
Expand Down Expand Up @@ -101,3 +109,305 @@ describe("marketingProxyRequest", () => {
expect(marketingProxyRequest(new Request("https://executor.sh/login"))).toBeNull();
});
});

// v2 on executor.sh: sign-up redirects to v2, and a fixed list of paths is
// forwarded to v2's Worker. Everything else stays with v1.
describe("isV2Path", () => {
const forwarded = [
"/.well-known/oauth-authorization-server/api/auth",
"/api/auth/callback/google",
"/api/auth/callback/github",
"/git/acme/tools/info/refs",
"/git/acme/tools/git-upload-pack",
"/git/acme/tools/git-receive-pack",
"/.well-known/agent-skills/",
"/.well-known/agent-skills/index.json",
];
for (const pathname of forwarded) {
it(`forwards ${pathname} to v2`, () => {
expect(isV2Path(pathname)).toBe(true);
});
}

const v1Owned = [
// v1's WorkOS callback has no provider segment.
"/api/auth/callback",
"/api/auth/callback/",
"/api/auth/callback/google/extra",
"/api/auth/login",
"/api/auth/me",
// v1's own issuer metadata and client metadata document.
"/.well-known/oauth-authorization-server",
"/.well-known/oauth-authorization-server/api/auth/extra",
"/.well-known/oauth-protected-resource/mcp",
"/oauth/client-id-metadata.json",
// v2 does not serve OpenID configuration on executor.sh, and its client
// metadata document's move to executor.sh is pending.
"/api/auth/.well-known/openid-configuration",
"/oauth/client-metadata.json",
// Git remotes need a path under /git/.
"/git",
"/gitlab/acme/tools/info/refs",
"/github",
"/.well-known/agent-skills",
"/.well-known/agent-skillset/index.json",
// Not yet: connected-account callback and marketing.
"/api/oauth/callback",
"/pricing",
// v1 dashboard, org pages and MCP, including org slugs that look similar.
"/",
"/login",
"/mcp",
"/acme/mcp",
"/gitops/mcp",
"/git-team/policies",
"/oauth-team/mcp",
"/api/connections",
];
for (const pathname of v1Owned) {
it(`leaves ${pathname} with v1`, () => {
expect(isV2Path(pathname)).toBe(false);
});
}
});

describe("isSignUpPath", () => {
it("claims /sign-up and /signup only", () => {
expect(isSignUpPath("/sign-up")).toBe(true);
expect(isSignUpPath("/signup")).toBe(true);
expect(isSignUpPath("/sign-up/")).toBe(false);
expect(isSignUpPath("/signup/team")).toBe(false);
expect(isSignUpPath("/sign-in")).toBe(false);
expect(isSignUpPath("/signups")).toBe(false);
});
});

describe("parseV2Edge", () => {
const service: V2Service = { fetch: () => Promise.resolve(new Response(null)) };

it("is off when neither setting is present", () => {
expect(parseV2Edge(undefined, undefined)).toBeNull();
});

it("refuses a binding or sign-up URL set without the other", () => {
expect(typeof parseV2Edge(undefined, "https://v2.executor.sh/login?mode=signup")).toBe(
"string",
);
expect(typeof parseV2Edge(service, undefined)).toBe("string");
});

it("refuses a sign-up URL that is not absolute http(s)", () => {
expect(typeof parseV2Edge(service, "/login?mode=signup")).toBe("string");
expect(typeof parseV2Edge(service, "javascript:alert(1)")).toBe("string");
});

it("parses both settings", () => {
const edge = parseV2Edge(service, "https://v2.executor.sh/login?mode=signup");
if (edge === null || typeof edge === "string") return expect.unreachable("settings must parse");
expect(edge.signUpUrl.href).toBe("https://v2.executor.sh/login?mode=signup");
});
});

describe("v2EdgeResponse", () => {
const SIGN_UP_URL = "https://v2.executor.sh/login?mode=signup";

/** A v2 service that records what it receives and answers with `respond`. */
const recordingService = (respond: (request: Request) => Promise<Response> | Response) => {
const received: Request[] = [];
const service: V2Service = {
fetch: async (request) => {
received.push(request);
return respond(request);
},
};
return { received, service };
};

it("redirects sign-up to v2's configured sign-up page, ignoring the query", async () => {
const { received, service } = recordingService(() => new Response(null));

for (const url of ["https://executor.sh/sign-up", "https://executor.sh/signup?ref=docs"]) {
const response = await v2EdgeResponse(new Request(url), service, SIGN_UP_URL);
expect(response?.status).toBe(302);
expect(response?.headers.get("location")).toBe(SIGN_UP_URL);
}
expect(received).toHaveLength(0);
});

it("follows the configured sign-up URL", async () => {
const response = await v2EdgeResponse(
new Request("https://executor.sh/signup"),
{ fetch: () => Promise.resolve(new Response(null)) },
"https://app.executor.sh/sign-up",
);
expect(response?.headers.get("location")).toBe("https://app.executor.sh/sign-up");
});

it("leaves non-GET sign-up requests with v1", () => {
const { service } = recordingService(() => new Response(null));
expect(
v2EdgeResponse(
new Request("https://executor.sh/sign-up", { method: "POST" }),
service,
SIGN_UP_URL,
),
).toBeNull();
});

it("answers edge requests with a 500 on a broken setting and leaves other paths with v1", async () => {
const { received, service } = recordingService(() => new Response(null));
const response = await v2EdgeResponse(
new Request("https://executor.sh/sign-up"),
service,
"/relative",
);
expect(response?.status).toBe(500);
expect(
v2EdgeResponse(new Request("https://executor.sh/acme/mcp"), service, "/relative"),
).toBeNull();
expect(received).toHaveLength(0);
});

it("is off without settings", () => {
expect(
v2EdgeResponse(new Request("https://executor.sh/sign-up"), undefined, undefined),
).toBeNull();
});

it("only acts on executor.sh", () => {
const { service } = recordingService(() => new Response(null));
expect(
v2EdgeResponse(new Request("http://executor-cloud.localhost/sign-up"), service, SIGN_UP_URL),
).toBeNull();
expect(
v2EdgeResponse(
new Request("https://v2.executor.sh/api/auth/callback/google"),
service,
SIGN_UP_URL,
),
).toBeNull();
});

it("leaves v1 paths with v1", () => {
const { received, service } = recordingService(() => new Response(null));
expect(
v2EdgeResponse(
new Request("https://executor.sh/api/auth/callback?code=c"),
service,
SIGN_UP_URL,
),
).toBeNull();
expect(
v2EdgeResponse(new Request("https://executor.sh/gitlab/x/info/refs"), service, SIGN_UP_URL),
).toBeNull();
expect(received).toHaveLength(0);
});

it("forwards with the public host, path and query, and returns v2's redirect unfollowed", async () => {
const { received, service } = recordingService(
() =>
new Response(null, {
status: 302,
headers: { location: "https://app.executor.sh/api/auth/callback/google?code=c&state=s" },
}),
);

const response = await v2EdgeResponse(
new Request("https://executor.sh/api/auth/callback/google?code=c&state=s"),
service,
SIGN_UP_URL,
);

expect(response?.status).toBe(302);
expect(response?.headers.get("location")).toBe(
"https://app.executor.sh/api/auth/callback/google?code=c&state=s",
);
expect(received).toHaveLength(1);
expect(received[0]?.url).toBe("https://executor.sh/api/auth/callback/google?code=c&state=s");
expect(received[0]?.redirect).toBe("manual");
});

it("strips v1's cookies and client forwarding headers but keeps Authorization", async () => {
const { received, service } = recordingService(() => new Response("ok"));

await v2EdgeResponse(
new Request("https://executor.sh/git/acme/tools/info/refs?service=git-upload-pack", {
headers: {
authorization: "Basic dXNlcjp0b2tlbg==",
cookie: "wos-session=sealed; ph_id=1",
"git-protocol": "version=2",
"x-forwarded-host": "attacker.example",
"x-forwarded-proto": "http",
},
}),
service,
SIGN_UP_URL,
);

const forwarded = received[0];
expect(forwarded?.headers.get("authorization")).toBe("Basic dXNlcjp0b2tlbg==");
expect(forwarded?.headers.get("git-protocol")).toBe("version=2");
expect(forwarded?.headers.has("cookie")).toBe(false);
expect(forwarded?.headers.has("x-forwarded-host")).toBe(false);
expect(forwarded?.headers.has("x-forwarded-proto")).toBe(false);
expect(new URL(forwarded?.url ?? "").search).toBe("?service=git-upload-pack");
});

it("returns v2's response unchanged, status and body stream included", async () => {
const upstream = new Response("not found", {
status: 404,
headers: { "content-type": "text/plain", "www-authenticate": 'Basic realm="git"' },
});
const { service } = recordingService(() => upstream);

const response = await v2EdgeResponse(
new Request("https://executor.sh/git/acme/tools/info/refs"),
service,
SIGN_UP_URL,
);

expect(response).toBe(upstream);
});

it("streams a git push body to v2 without buffering it, preserving the method", async () => {
const encoder = new TextEncoder();
let source: ReadableStreamDefaultController<Uint8Array> | undefined;
const body = new ReadableStream<Uint8Array>({
start(controller) {
source = controller;
controller.enqueue(encoder.encode("first-pack-chunk"));
},
});
// v2 reads the first chunk while the client is still sending: a buffering
// edge would wait for the end of the body and never reach v2.
const { received, service } = recordingService(async (request) => {
const reader = request.body?.getReader();
if (reader === undefined) return new Response("no body", { status: 500 });
const first = await reader.read();
source?.enqueue(encoder.encode("second-pack-chunk"));
source?.close();
const second = await reader.read();
const done = await reader.read();
const decoder = new TextDecoder();
return new Response(
`${decoder.decode(first.value)}|${decoder.decode(second.value)}|${done.done}`,
);
});

const response = await v2EdgeResponse(
new Request("https://executor.sh/git/acme/tools/git-receive-pack", {
method: "POST",
headers: { "content-type": "application/x-git-receive-pack-request" },
body,
// @ts-expect-error -- Node's fetch needs `duplex` for a stream body; workerd does not.
duplex: "half",
}),
service,
SIGN_UP_URL,
);

expect(received[0]?.method).toBe("POST");
expect(received[0]?.headers.get("content-type")).toBe("application/x-git-receive-pack-request");
expect(await response?.text()).toBe("first-pack-chunk|second-pack-chunk|true");
});
});
39 changes: 39 additions & 0 deletions packages/core/api/src/account/org-slug.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,45 @@ describe("isValidOrgSlug", () => {
expect(RESERVED_ORG_SLUGS.has(critical), critical).toBe(true);
}
});

it("reserves the root segments the executor.sh edge gives to v2", () => {
// `/git/<owner>/<repo>` and the other forwarded or redirected roots would
// otherwise read as an org's console URL (`/<org>/...`).
for (const claimed of [
"git",
"apps",
"experiments",
"oauth",
"api",
"app",
"mcp",
"docs",
"sign-up",
"signup",
"pricing",
"blog",
]) {
expect(isValidOrgSlug(claimed), claimed).toBe(false);
}
// Look-alikes stay claimable.
for (const lookalike of [
"gitlab",
"git-team",
"github",
"app-team",
"experiment",
"oauth-co",
"blogs",
]) {
expect(isValidOrgSlug(lookalike), lookalike).toBe(true);
}
});

it("never mints a reserved edge slug for an org name", async () => {
const slug = await generateOrgSlug("Git", async () => false);
expect(slug).not.toBe("git");
expect(slug).toMatch(/^git-[a-z2-9]{4}$/);
});
});

describe("generateOrgSlug", () => {
Expand Down
Loading