/** * End-to-end checks for dynamic sites against a running dev server. * * SITES_E2E_URL=http://localhost:3100 SITES_DOMAIN=gitforstatic.localhost bun run e2e/sites.e2e.ts * * Requests to site hosts go to the forge's address with an explicit Host header, so no hosts-file entries are needed. */ import { deployScratch, DOMAIN, FORGE, HTTP_OK, log, send } from "./helpers"; const BLOCKED_STATUS = 599; const HTTP_ACCEPTED = 202; const HTTP_UNAUTHORIZED = 401; const HTTP_NOT_FOUND = 404; let failures = 0; function check(name: string, ok: boolean, detail = ""): void { log(`${ok ? "ok " : "FAIL"} ${name}${ok || !detail ? "" : ` -- ${detail}`}`); if (!ok) failures += 1; } const first = await deployScratch("site-a"); check("scratch deploy returns a claim token", first.claimToken.startsWith("gitfor_claim_")); const second = await deployScratch("site-b"); check( "each scratch site gets its own origin", first.host !== second.host && first.host.endsWith(`--scratch.${DOMAIN}`), ); const page = await send(first.host, "/"); check( "static assets are served through env.ASSETS", page.status === HTTP_OK && page.body.includes("site-a"), page.body, ); check( "worker source is never served statically", (await send(first.host, "/_worker.js")).body.includes("export default") === false, ); const forgeCookie = "__Host-gitfor_session=forge-secret; gitfor_session=legacy; __Host-gitfor_site=x; gitfor_state=y; theme=dark"; const echo = JSON.parse((await send(first.host, "/echo", { headers: { cookie: forgeCookie } })).body) as { cookie: string | null; env: string[]; }; check("dispatcher cookies never reach user code", echo.cookie === "theme=dark", String(echo.cookie)); check("scratch workers get no bindings beyond ASSETS", echo.env.join(",") === "ASSETS", echo.env.join(",")); const set = await send(first.host, "/set"); const cookies = ([] as string[]).concat(set.headers["set-cookie"] ?? []); check( "user code can't set reserved cookies", cookies.length === 1 && cookies[0].startsWith("site_token="), cookies.join(" | "), ); check( "site cookies are host-only", cookies.every((cookie) => !/;\s*domain=/i.test(cookie)), ); const outbound = await send(first.host, "/fetch?u=https://example.com/"); check( "scratch sites have no outbound network", outbound.status === BLOCKED_STATUS, `${outbound.status} ${outbound.body}`, ); const report = await send(second.host, "/__gitfor/report", { method: "POST", body: new TextEncoder().encode("e2e") }); check("abuse reports are accepted", report.status === HTTP_ACCEPTED, `${report.status}`); const claim = await fetch(first.claimUrl, { redirect: "manual" }); check("claiming requires a forge session", claim.status === HTTP_UNAUTHORIZED, `${claim.status}`); const unknown = await send(`nope--nobody.${DOMAIN}`, "/"); check( "unknown site hosts 404 without falling through to the forge", unknown.status === HTTP_NOT_FOUND && !unknown.body.includes("