Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

118 linesCodeBlameRaw
1// Exercise the built Worker in workerd before it can be deployed. Storage is
2// temporary and local; no service bindings or Cloudflare credentials are used.
3import assert from "node:assert/strict";
4import { readFileSync, readdirSync } from "node:fs";
5import { join, resolve } from "node:path";
6import { Miniflare, convertV4MiniflareOptions } from "miniflare";
7
8const root = resolve("build/server");
9const config = JSON.parse(readFileSync(join(root, "wrangler.json"), "utf8"));
10const source = readFileSync(join(root, "index.js"), "utf8");
11const build = source.match(/searchParams\.set\("_g1t_build", "([^"]+)"\)/)?.[1];
12assert.ok(build, "The page cache must be separated by build");
13const css = "body{color:red}";
14// Seed R2 and the page cache through a test-only entry, keeping all R2 I/O
15// inside workerd. The application entry itself is the unmodified build.
16const seed = `import app from './index.js';
17import { WorkerEntrypoint } from 'cloudflare:workers';
18export class ScreenshotStub extends WorkerEntrypoint {
19 async image(input) {
20 if (input.host !== 'public-acme.g1t.page' || input.commit !== 'abcdef1234567') throw new Error('Unexpected screenshot target');
21 return {body:new TextEncoder().encode('production-preview').buffer,contentType:'image/jpeg',commit:input.commit,capturedAt:'2026-10-15T02:00:00Z'};
22 }
23}
24export default { async fetch(request, env, ctx) {
25 if (new URL(request.url).pathname === '/__seed') {
26 await env.DOWNLOADS.put('web-assets/assets/app-old12345.css', ${JSON.stringify(css)}, {httpMetadata:{contentType:'text/css'}});
27 const cache = new URL('/pricing.data', request.url);
28 cache.searchParams.set('_g1t_build', ${JSON.stringify(build)});
29 cache.searchParams.set('_g1t_representation', 'html');
30 await caches.default.put(new Request(cache), new Response('wrong-build-cache', {headers:{'cache-control':'public, max-age=300','x-g1t-kept-at':String(Date.now())}}));
31 return new Response('seeded');
32 }
33 return app.fetch(request, env, ctx);
34}};`;
35const files = [join(root, "index.js"), ...readdirSync(join(root, "assets")).filter((name) => name.endsWith(".js")).map((name) => join(root, "assets", name))];
36const runtime = new Miniflare(convertV4MiniflareOptions({
37 name: "web-deploy-check", cf: false, modulesRoot: root,
38 modules: [{ type: "ESModule", path: join(root, "deploy-check.mjs"), contents: seed }, ...files.map((path) => ({ type: "ESModule", path }))],
39 compatibilityDate: config.compatibility_date,
40 compatibilityFlags: config.compatibility_flags,
41 r2Buckets: ["DOWNLOADS"],
42 serviceBindings: {
43 IDENTITY: async () => Response.json(null),
44 PROJECTS: async (request) => {
45 const method = new URL(request.url).pathname.split("/").pop();
46 const args = await request.json();
47 if (method !== "get") return Response.json({ ok: true, value: [] });
48 if (args.slug !== "public") return Response.json({ ok: false, error: { code: "not_found", message: "Not found" } });
49 return Response.json({ ok: true, value: { source: { kind: "hosted", repo: { namespace: "acme", name: "public" } } } });
50 },
51 DEPLOYMENTS: async (request) => {
52 const method = new URL(request.url).pathname.split("/").pop();
53 const args = await request.json();
54 assert.equal(method, "list_environments", "Public previews must not read member-only deployment lists");
55 assert.equal(args.viewer, null);
56 assert.equal(args.repo.name, "public");
57 const current = { id: "dpl_live", source: "g1t_page", state: "success", sha: "abcdef1234567", environment_url: "https://public-acme.g1t.page", updated_at: "2026-10-15T01:00:00Z" };
58 return Response.json({ ok: true, value: { environments: [{ name: "production", production_environment: true, updated_at: current.updated_at, current, latest: { ...current, id: "dpl_next", sha: "bbbbbbb", state: "in_progress" } }] } });
59 },
60 SCREENSHOTS: { name: "web-deploy-check", entrypoint: "ScreenshotStub" },
61 },
62}));
63try {
64 const origin = await runtime.ready;
65 const request = (path, init) => fetch(new URL(path, origin), { ...init, signal: AbortSignal.timeout(15_000) });
66 assert.equal((await request("/__seed")).status, 200);
67 const screenshot = await request("/acme/public/production.jpg?v=abcdef1234567-" + Date.parse("2026-10-15T01:00:00Z"));
68 assert.equal(screenshot.status, 200, "Signed-out readers can see public production screenshots");
69 assert.equal(screenshot.headers.get("content-type"), "image/jpeg");
70 assert.equal(screenshot.headers.get("cache-control"), "private, max-age=31536000, immutable");
71 assert.equal(await screenshot.text(), "production-preview");
72 assert.equal((await request("/acme/private/production.jpg")).status, 404, "Unreadable projects never expose screenshots");
73 console.log("Public production screenshots: anonymous access, private-project denial, and serving commit selection verified.");
74 for (const [path, destination] of [["/developers", "https://docs.g1t.sh/reference/api/"], ["/openapi.json", "https://api.g1t.sh/openapi.json"], ["/mcp", "https://mcp.g1t.sh"]]) {
75 const answer = await request(path, { redirect: "manual" });
76 assert.equal(answer.status, 308);
77 assert.equal(answer.headers.get("location"), new URL(destination).href);
78 }
79 // Run Markdown first, then HTML at the same URL: the cache must not mix them.
80 for (const path of ["/", "/__agent-readiness-missing"]) {
81 for (const accept of ["text/markdown", "text/html", "text/markdown"]) {
82 const answer = await request(path, { headers: { accept } });
83 assert.equal(answer.status, path === "/" ? 200 : 404);
84 assert.ok(answer.headers.get("vary")?.toLowerCase().split(",").map((value) => value.trim()).includes("accept"));
85 assert.ok(answer.headers.get("content-type")?.startsWith(accept));
86 const body = await answer.text();
87 if (accept === "text/markdown") { assert.match(body, /\[.*\]\(.*\/llms.txt\)/); assert.ok(body.length > 20); }
88 else { assert.match(body, /<html/); if (path === "/") assert.match(body, /rel="canonical"/); }
89 }
90 }
91 assert.equal((await request("/", { headers: { accept: "application/json" } })).status, 406);
92 for (const accept of ["text/markdown", "text/html"]) {
93 const answer = await request("/", { method: "HEAD", headers: { accept } });
94 assert.equal(answer.status, 200);
95 assert.ok(answer.headers.get("content-type")?.startsWith(accept));
96 assert.equal(await answer.text(), "");
97 }
98 const old = await request("/assets/app-old12345.css");
99 assert.equal(old.status, 200);
100 assert.equal(old.headers.get("content-type"), "text/css");
101 assert.equal(await old.text(), css);
102 const missing = await request("/assets/app-missing0.css");
103 assert.equal(missing.status, 404);
104 assert.equal(missing.headers.get("cache-control"), "no-store");
105 assert.doesNotMatch(missing.headers.get("content-type") ?? "", /html/);
106 for (const path of ["/pricing.data", "/flagon-io/-/home.data?tab=one&_routes=root"]) {
107 const answer = await request(path, { headers: { "x-g1t-build": "previous-build" } });
108 assert.equal(answer.status, 202);
109 const body = await answer.text();
110 assert.match(body, /reload/);
111 assert.ok(body.includes(path.split(".data")[0]));
112 assert.doesNotMatch(body, /_routes|wrong-build-cache/);
113 }
114 console.log("Deployment safety: old CSS survives, missing assets stay isolated, old navigations bypass cache and loaders.");
115 console.log("Agent pages: Markdown/HTML negotiation, isolated caches, 404s, HEAD, canonical metadata and discovery redirects verified.");
116} finally {
117 await runtime.dispose();
118}