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.

82 linesCodeBlameRaw
1// Read-only production verification. --mcp uses the existing CLI login without logging it.
2// Run: node --use-system-ca scripts/check-agent-readiness.mjs [--mcp]
3import assert from "node:assert/strict";
4import { execFileSync } from "node:child_process";
5import { verifyMcp } from "./mcp-readiness.mjs";
6
7let failures = 0;
8async function check(name, run) {
9 try { await run(); console.log(`PASS ${name}`); }
10 catch (error) { failures++; console.error(`FAIL ${name}: ${error.message}`); }
11}
12async function get(url, headers = {}) {
13 const response = await fetch(url, { headers, signal: AbortSignal.timeout(20_000) });
14 return { response, body: await response.text() };
15}
16const varies = (response) => (response.headers.get("vary") ?? "").toLowerCase().split(",").map((v) => v.trim()).includes("accept");
17for (const [path, status] of [["/", 200], ["/__agent-readiness-nonexistent", 404]]) {
18 for (const accept of ["text/markdown", "text/html", "text/html;q=0.2,text/markdown;q=1"]) {
19 await check(`${path} Accept: ${accept}`, async () => {
20 const { response, body } = await get(`https://g1t.sh${path}`, { accept });
21 assert.equal(response.status, status);
22 assert.ok(varies(response), "Vary must contain Accept");
23 const markdown = accept !== "text/html";
24 assert.ok(response.headers.get("content-type")?.startsWith(markdown ? "text/markdown" : "text/html"));
25 if (markdown) { assert.ok(body.length > 20); assert.match(body, /\[.*\]\(https:\/\/g1t.sh\/llms.txt\)/); }
26 else assert.match(body, /<html/);
27 });
28 }
29}
30await check("unsupported homepage representation", async () => assert.equal((await get("https://g1t.sh/", { accept: "application/json" })).response.status, 406));
31await check("homepage metadata", async () => {
32 const { body } = await get("https://g1t.sh/", { accept: "text/html" });
33 assert.match(body, /<html[^>]*lang="en"/);
34 assert.match(body, /<link[^>]*rel="canonical"[^>]*href="https:\/\/g1t.sh\/"/);
35 assert.match(body, /property="og:image"/);
36 assert.match(body, /property="og:type"/);
37 const schemas = [...body.matchAll(/<script[^>]*type="application\/ld\+json"[^>]*>([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1]));
38 const organization = schemas.find((schema) => schema["@type"] === "Organization");
39 assert.equal(organization?.contactPoint?.email, "hey@flagon.io");
40});
41await check("llms.txt instructions and developer links", async () => {
42 const { response, body } = await get("https://g1t.sh/llms.txt");
43 assert.equal(response.status, 200);
44 assert.match(body, /^# g1t\s/m);
45 assert.match(body, /## (When to use g1t|Developer resources)/);
46 for (const url of ["https://api.g1t.sh/openapi.json", "https://mcp.g1t.sh/.well-known/oauth-protected-resource", "https://g1t.sh/settings/tokens"]) assert.ok(body.includes(url));
47});
48await check("OpenAPI scopes and unprefixed versioned API", async () => {
49 const { body, response } = await get("https://api.g1t.sh/openapi.json");
50 assert.equal(response.status, 200);
51 const spec = JSON.parse(body);
52 assert.equal(spec.servers[0].url, "https://api.g1t.sh");
53 const scopes = spec.components.securitySchemes.oauth.flows.authorizationCode.scopes;
54 const metadata = JSON.parse((await get("https://mcp.g1t.sh/.well-known/oauth-protected-resource")).body);
55 assert.deepEqual(Object.keys(scopes).sort(), metadata.scopes_supported.sort());
56 assert.equal(spec.components.parameters.ApiVersion.name, "X-G1t-Api-Version");
57 assert.ok(spec.components.responses.RateLimited.headers["Retry-After"]);
58});
59for (const path of ["/repos", "/v1/repos"]) await check(`REST ${path} version and limit headers`, async () => {
60 const { response, body } = await get(`https://api.g1t.sh${path}`, { "X-G1t-Api-Version": "1" });
61 assert.equal(response.status, 200);
62 assert.ok(Array.isArray(JSON.parse(body)));
63 assert.equal(response.headers.get("x-g1t-api-version"), "1");
64 assert.equal(response.headers.get("ratelimit-policy"), '"anonymous";q=60;w=60');
65});
66await check("unsupported REST version fails", async () => assert.equal((await get("https://api.g1t.sh/repos", { "X-G1t-Api-Version": "not-a-version" })).response.status, 422));
67for (const url of ["https://g1t.sh/developers", "https://g1t.sh/openapi.json", "https://g1t.sh/mcp", "https://g1t.sh/sitemap.xml", "https://g1t.sh/robots.txt", "https://docs.g1t.sh/reference/api/", "https://docs.g1t.sh/reference/rate-limits/", "https://docs.g1t.sh/guides/authentication/", "https://docs.g1t.sh/guides/cli/", "https://docs.g1t.sh/guides/self-hosting/", "https://g1t.sh/downloads/cli/latest.json"]) {
68 await check(url, async () => { const { response, body } = await get(url); assert.equal(response.status, 200); assert.ok(body.length > 20); });
69}
70await check("published versioning documentation", async () => assert.match((await get("https://docs.g1t.sh/reference/api/")).body, /X-G1t-Api-Version/));
71await check("MCP still requires authorization", async () => {
72 const response = await fetch("https://mcp.g1t.sh", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list", params: {} }), signal: AbortSignal.timeout(20_000) });
73 assert.equal(response.status, 401);
74 assert.match(response.headers.get("www-authenticate") ?? "", /resource_metadata/);
75 await response.body?.cancel();
76});
77if (process.argv.includes("--mcp")) await check("authorized MCP initialize and tools/list", async () => {
78 const token = execFileSync("g1t", ["auth", "token", "--hostname", "g1t.sh"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
79 const result = await verifyMcp(token);
80 console.log(`Verified ${result.tools} protected tools and ${result.actions} documented action scopes.`);
81});
82process.exitCode = failures ? 1 : 0;