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.

g1t.sh
309 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

A deploy makes the runner's image in the registry, without Docker: it reads the base's manifest and config from Cloudflare's registry, uploads one gzipped layer holding the runner binary at /usr/local/bin/g1t-runner with mode 0755, and writes a config (the entrypoint g1t-runner, the base's command cleared, as the Dockerfile's ENTRYPOINT does) and a manifest that name the base's layers and that one, under the runner's tag, for linux/amd64 (scripts/deploy/registry.mjs, the registry's own upload calls with the credentials Wrangler gives). Deploy #256 ran out of disk because docker build pulled the 4.5 GB base into the job's own Docker Engine, compressed and unpacked, on a 20 GB sandbox whose own filesystem is that same base; now nothing of the base is downloaded and the job's Docker Engine is never started. Docker is asked for only when it is needed: a dry run (build, or image --no-push) still builds services/runner/Dockerfile with it, and so does a deploy whose registry step fails, logging df -h and docker system df before and after. The image job removes npm's downloads, which it only restores, once its install has read them, and logs the disk before and after the deploy. Tests cover the layer's tar, the config and manifest, the calls against a registry kept in memory (the base's layers are never fetched), the token flow, and that the Dockerfile says the same path, mode and entrypoint; the image was also checked against a local registry, where it runs and has the same config as a docker build of the Dockerfile.1// The runner's image made in the registry (registry.mjs): its layer,
2// config and manifest, and the calls it makes, against a registry kept in
3// memory.
4import assert from "node:assert/strict";
5import { readFileSync } from "node:fs";
6import { join } from "node:path";
7import { test } from "node:test";
8import { gunzipSync } from "node:zlib";
9
10import {
11 DOCKER_MANIFEST,
12 OCI_MANIFEST,
13 RUNNER_BINARY_MODE,
14 RUNNER_BINARY_PATH,
15 RUNNER_ENTRYPOINT,
16 appendRunnerImage,
17 bearerChallenge,
18 parseRef,
19 runnerConfig,
20 runnerLayer,
21 runnerManifest,
22 sha256,
23 tarOf,
24} from "./registry.mjs";
25import { ROOT } from "./stack.mjs";
26
27/** A tar's entries: name, mode, size, owner, type and bytes, checksums checked. */
28function untar(tar) {
29 const entries = [];
30 for (let at = 0; at + 512 <= tar.length; ) {
31 const header = tar.subarray(at, at + 512);
32 if (header.every((b) => b === 0)) break;
33 const field = (start, length) => header.subarray(start, start + length).toString("ascii").replace(/\0.*$/s, "").trim();
34 const summed = [...header].reduce((sum, byte, i) => sum + (i >= 148 && i < 156 ? 32 : byte), 0);
35 assert.equal(Number.parseInt(field(148, 8), 8), summed, "the header's checksum");
36 assert.equal(field(257, 6), "ustar");
37 const size = Number.parseInt(field(124, 12), 8);
38 entries.push({
39 name: field(0, 100),
40 mode: Number.parseInt(field(100, 8), 8),
41 uid: Number.parseInt(field(108, 8), 8),
42 gid: Number.parseInt(field(116, 8), 8),
43 mtime: Number.parseInt(field(136, 12), 8),
44 type: field(156, 1),
45 data: tar.subarray(at + 512, at + 512 + size),
46 });
47 at += 512 + Math.ceil(size / 512) * 512;
48 }
49 return entries;
50}
51
52test("the runner's layer is the binary alone, at its path and mode, owned by root", () => {
53 const binary = Buffer.from("\x7fELF a runner, of a length that is not a whole block");
54 const layer = runnerLayer(binary, { mtime: 1_760_000_000 });
55 const tar = gunzipSync(layer.bytes);
56 assert.equal(tar.length % 512, 0);
57 assert.equal(layer.digest, sha256(layer.bytes));
58 assert.equal(layer.size, layer.bytes.length);
59 assert.equal(layer.diffId, sha256(tar));
60 const entries = untar(tar);
61 assert.equal(entries.length, 1);
62 const [entry] = entries;
63 assert.deepEqual(
64 { name: entry.name, mode: entry.mode, uid: entry.uid, gid: entry.gid, mtime: entry.mtime, type: entry.type },
65 { name: "usr/local/bin/g1t-runner", mode: 0o755, uid: 0, gid: 0, mtime: 1_760_000_000, type: "0" },
66 );
67 assert.ok(entry.data.equals(binary));
68 // The same bytes make the same layer.
69 assert.equal(runnerLayer(binary, { mtime: 1_760_000_000 }).digest, layer.digest);
70 // An exact number of blocks, and an empty file.
71 assert.equal(untar(tarOf("a", Buffer.alloc(512, 1)))[0].data.length, 512);
72 assert.equal(untar(tarOf("a", Buffer.alloc(0)))[0].data.length, 0);
73});
74
75test("the layer and entrypoint are what services/runner/Dockerfile builds", () => {
76 const dockerfile = readFileSync(join(ROOT, "services/runner/Dockerfile"), "utf8");
77 const copy = /^COPY --chmod=(\d+) g1t-runner (\S+)$/m.exec(dockerfile);
78 assert.ok(copy, "the Dockerfile copies the binary in");
79 assert.equal(Number.parseInt(copy[1], 8), RUNNER_BINARY_MODE);
80 assert.equal(copy[2], `/${RUNNER_BINARY_PATH}`);
81 const entrypoint = /^ENTRYPOINT (.+)$/m.exec(dockerfile);
82 assert.deepEqual(JSON.parse(entrypoint[1]), RUNNER_ENTRYPOINT);
83 // Nothing else that would change the image.
84 const instructions = dockerfile.split(/\r?\n/).filter((line) => line.trim() && !line.startsWith("#")).map((line) => line.split(" ")[0]);
85 assert.deepEqual(instructions, ["ARG", "FROM", "COPY", "ENTRYPOINT"]);
86});
87
88const BASE_CONFIG = {
89 architecture: "amd64",
90 os: "linux",
91 created: "2026-10-08T19:50:00Z",
92 config: { Env: ["PATH=/usr/local/bin:/usr/bin"], Cmd: ["bash"], WorkingDir: "/home/runner", User: "root" },
93 rootfs: { type: "layers", diff_ids: ["sha256:" + "1".repeat(64), "sha256:" + "2".repeat(64)] },
94 history: [{ created_by: "FROM debian" }, { created_by: "RUN apt-get install" }],
95};
96
97test("the config is the base's, with the layer, the entrypoint and no inherited command", () => {
98 const before = structuredClone(BASE_CONFIG);
99 const diffId = "sha256:" + "3".repeat(64);
100 const config = runnerConfig(BASE_CONFIG, { diffId, created: "2026-10-13T00:00:00.000Z" });
101 assert.deepEqual(BASE_CONFIG, before, "the base's config is left as it was");
102 assert.deepEqual(config.config.Entrypoint, ["g1t-runner"]);
103 assert.equal(config.config.Cmd, undefined);
104 assert.deepEqual(config.config.Env, BASE_CONFIG.config.Env);
105 assert.equal(config.config.WorkingDir, "/home/runner");
106 assert.deepEqual(config.rootfs.diff_ids, [...BASE_CONFIG.rootfs.diff_ids, diffId]);
107 assert.equal(config.created, "2026-10-13T00:00:00.000Z");
108 // History: one entry per layer, plus one that adds none.
109 assert.equal(config.history.filter((h) => !h.empty_layer).length - BASE_CONFIG.history.length, 1);
110 assert.equal(config.history.at(-1).empty_layer, true);
111 assert.throws(() => runnerConfig({ ...BASE_CONFIG, architecture: "arm64" }, { diffId, created: "x" }), /linux\/amd64/);
112});
113
114test("the manifest names the base's layers, then the binary's, in the base's format", () => {
115 const layers = [
116 { mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", digest: "sha256:" + "a".repeat(64), size: 10 },
117 { mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", digest: "sha256:" + "b".repeat(64), size: 20 },
118 ];
119 const config = { digest: "sha256:" + "c".repeat(64), size: 5 };
120 const layer = { digest: "sha256:" + "d".repeat(64), size: 7 };
121 const docker = runnerManifest(
122 { schemaVersion: 2, mediaType: DOCKER_MANIFEST, config: { mediaType: "application/vnd.docker.container.image.v1+json", digest: "x", size: 1 }, layers },
123 { config, layer },
124 );
125 assert.deepEqual(docker, {
126 schemaVersion: 2,
127 mediaType: DOCKER_MANIFEST,
128 config: { mediaType: "application/vnd.docker.container.image.v1+json", ...config },
129 layers: [...layers, { mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", ...layer }],
130 });
131 // OCI, with its type left unsaid.
132 const oci = runnerManifest(
133 { schemaVersion: 2, config: { mediaType: "application/vnd.oci.image.config.v1+json", digest: "x", size: 1 }, layers: [], annotations: { a: "b" } },
134 { config, layer },
135 );
136 assert.equal(oci.mediaType, OCI_MANIFEST);
137 assert.deepEqual(oci.layers, [{ mediaType: "application/vnd.oci.image.layer.v1.tar+gzip", ...layer }]);
138 assert.equal(oci.annotations, undefined);
139});
140
141test("image references and bearer challenges are read", () => {
142 const digest = "sha256:" + "e".repeat(64);
143 assert.deepEqual(parseRef("registry.cloudflare.com/acct/g1t-runner:abc"), { host: "registry.cloudflare.com", name: "acct/g1t-runner", tag: "abc", digest: null });
144 assert.deepEqual(parseRef(`localhost:5000/g1t-runner:base-1@${digest}`), { host: "localhost:5000", name: "g1t-runner", tag: "base-1", digest });
145 assert.deepEqual(parseRef(`r.example/x@${digest}`), { host: "r.example", name: "x", tag: null, digest });
146 assert.throws(() => parseRef("r.example/x"));
147 assert.deepEqual(bearerChallenge('Bearer realm="https://auth.example/token",service="registry",scope="repository:x:pull"'), {
148 realm: "https://auth.example/token",
149 service: "registry",
150 scope: "repository:x:pull",
151 });
152 assert.equal(bearerChallenge('Basic realm="x"'), null);
153 assert.equal(bearerChallenge(null), null);
154});
155
156/** A registry in memory: one repository, Basic auth, uploads by POST, PATCH and PUT. */
157function fakeRegistry({ name, auth = "Basic " + Buffer.from("u:p").toString("base64") }) {
158 const blobs = new Map();
159 const manifests = new Map();
160 const uploads = new Map();
161 const calls = [];
162 let next = 0;
163 const reply = (status, { headers = {}, body = null } = {}) => ({
164 status,
165 ok: status >= 200 && status < 300,
166 headers: new Headers(headers),
167 arrayBuffer: async () => (body ? body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength) : new ArrayBuffer(0)),
168 text: async () => (body ? body.toString("utf8") : ""),
169 json: async () => JSON.parse(body.toString("utf8")),
170 });
171 const fetchImpl = async (url, init) => {
172 const { pathname, searchParams } = new URL(url);
173 calls.push(`${init.method} ${pathname}`);
174 if (init.headers.authorization !== auth) return reply(401);
175 const prefix = `/v2/${name}/`;
176 if (!pathname.startsWith(prefix)) return reply(404);
177 const path = pathname.slice(prefix.length);
178 let match;
179 if ((match = /^manifests\/(.+)$/.exec(path))) {
180 if (init.method === "PUT") {
181 const bytes = Buffer.from(init.body);
182 const digest = sha256(bytes);
183 for (const ref of [...JSON.parse(bytes).layers, JSON.parse(bytes).config]) {
184 if (!blobs.has(ref.digest)) return reply(400, { body: Buffer.from('{"errors":[{"code":"MANIFEST_BLOB_UNKNOWN"}]}') });
185 }
186 manifests.set(match[1], { bytes, type: init.headers["content-type"] });
187 manifests.set(digest, { bytes, type: init.headers["content-type"] });
188 return reply(201, { headers: { "docker-content-digest": digest } });
189 }
190 const found = manifests.get(match[1]);
191 return found ? reply(200, { headers: { "content-type": found.type }, body: found.bytes }) : reply(404);
192 }
193 if ((match = /^blobs\/(sha256:[0-9a-f]{64})$/.exec(path))) {
194 const found = blobs.get(match[1]);
195 if (!found) return reply(404);
196 return init.method === "HEAD" ? reply(200) : reply(200, { body: found });
197 }
198 if (path === "blobs/uploads/" && init.method === "POST") {
199 const id = `u${next++}`;
200 uploads.set(id, Buffer.alloc(0));
201 return reply(202, { headers: { location: `${prefix}blobs/uploads/${id}` } });
202 }
203 if ((match = /^blobs\/uploads\/(u\d+)$/.exec(path))) {
204 const id = match[1];
205 if (init.method === "PATCH") {
206 uploads.set(id, Buffer.concat([uploads.get(id), Buffer.from(init.body)]));
207 return reply(202, { headers: { location: `${prefix}blobs/uploads/${id}?state=1` } });
208 }
209 if (init.method === "PUT") {
210 const bytes = uploads.get(id);
211 if (sha256(bytes) !== searchParams.get("digest")) return reply(400);
212 blobs.set(searchParams.get("digest"), bytes);
213 return reply(201);
214 }
215 }
216 return reply(405);
217 };
218 return { blobs, manifests, calls, fetchImpl };
219}
220
221test("the runner's image is made in the registry from the base's manifest and one new layer, pulling none of the base", async () => {
222 const registry = fakeRegistry({ name: "acct/g1t-runner" });
223 // The base, as `docker push` left it.
224 const layerBlobs = [Buffer.from("base layer one"), Buffer.from("base layer two")];
225 for (const blob of layerBlobs) registry.blobs.set(sha256(blob), blob);
226 const configBytes = Buffer.from(JSON.stringify(BASE_CONFIG));
227 registry.blobs.set(sha256(configBytes), configBytes);
228 const baseManifest = Buffer.from(
229 JSON.stringify({
230 schemaVersion: 2,
231 mediaType: OCI_MANIFEST,
232 config: { mediaType: "application/vnd.oci.image.config.v1+json", digest: sha256(configBytes), size: configBytes.length },
233 layers: layerBlobs.map((blob) => ({ mediaType: "application/vnd.oci.image.layer.v1.tar+gzip", digest: sha256(blob), size: blob.length })),
234 }),
235 );
236 registry.manifests.set(sha256(baseManifest), { bytes: baseManifest, type: OCI_MANIFEST });
237 const base = `registry.cloudflare.com/acct/g1t-runner:base-20261008-a314499af03b@${sha256(baseManifest)}`;
238 const ref = "registry.cloudflare.com/acct/g1t-runner:0123456789abcdef";
239 const binary = Buffer.from("the runner binary");
240 const credentials = async () => ({ username: "u", password: "p" });
241
242 const digest = await appendRunnerImage({ ref, base, binary, credentials, fetchImpl: registry.fetchImpl, created: "2026-10-13T00:00:00.000Z" });
243 const made = registry.manifests.get("0123456789abcdef");
244 assert.equal(sha256(made.bytes), digest);
245 assert.equal(made.type, OCI_MANIFEST);
246 const manifest = JSON.parse(made.bytes);
247 assert.deepEqual(manifest.layers.slice(0, 2).map((l) => l.digest), layerBlobs.map(sha256));
248 assert.equal(manifest.layers.length, 3);
249 const config = JSON.parse(registry.blobs.get(manifest.config.digest));
250 assert.deepEqual(config.config.Entrypoint, ["g1t-runner"]);
251 assert.equal(config.rootfs.diff_ids.at(-1), sha256(gunzipSync(registry.blobs.get(manifest.layers[2].digest))));
252 assert.ok(untar(gunzipSync(registry.blobs.get(manifest.layers[2].digest)))[0].data.equals(binary));
253 // The base's layers were asked about, never downloaded.
254 for (const blob of layerBlobs) assert.ok(!registry.calls.includes(`GET /v2/acct/g1t-runner/blobs/${sha256(blob)}`));
255
256 // Made again: the layer is already there, so only the config and manifest are written.
257 const before = registry.calls.length;
258 await appendRunnerImage({ ref, base, binary, credentials, fetchImpl: registry.fetchImpl, created: "2026-10-13T00:00:00.000Z" });
259 assert.ok(!registry.calls.slice(before).some((call) => call.startsWith("PATCH")));
260});
261
262test("a base that is not where it should be, or not what base.json says, stops it", async () => {
263 const registry = fakeRegistry({ name: "acct/g1t-runner" });
264 const credentials = async () => ({ username: "u", password: "p" });
265 const digest = "sha256:" + "f".repeat(64);
266 const options = { binary: Buffer.from("x"), credentials, fetchImpl: registry.fetchImpl, attempts: 1 };
267 await assert.rejects(
268 appendRunnerImage({ ...options, ref: "registry.cloudflare.com/acct/g1t-runner:t", base: `registry.cloudflare.com/acct/other:b@${digest}` }),
269 /not in the runner's repository/,
270 );
271 await assert.rejects(appendRunnerImage({ ...options, ref: "registry.cloudflare.com/acct/g1t-runner:t", base: `registry.cloudflare.com/acct/g1t-runner:b@${digest}` }), /404/);
272 // Wrong credentials: the registry's answer is the error.
273 await assert.rejects(
274 appendRunnerImage({ ...options, credentials: async () => ({ username: "u", password: "wrong" }), ref: "registry.cloudflare.com/acct/g1t-runner:t", base: `registry.cloudflare.com/acct/g1t-runner:b@${digest}` }),
275 /401/,
276 );
277});
278
279test("a registry that asks for a bearer token is given the one its realm trades the credentials for", async () => {
280 const registry = fakeRegistry({ name: "acct/r", auth: "Bearer tok" });
281 const inner = registry.fetchImpl;
282 const asked = [];
283 const fetchImpl = async (url, init) => {
284 if (url.startsWith("https://auth.example/")) {
285 asked.push([url, init.headers.authorization]);
286 return { ok: true, status: 200, json: async () => ({ token: "tok" }) };
287 }
288 const answer = await inner(url, init);
289 if (answer.status === 401) answer.headers.set("www-authenticate", 'Bearer realm="https://auth.example/token",service="r.example"');
290 return answer;
291 };
292 const config = Buffer.from(JSON.stringify(BASE_CONFIG));
293 registry.blobs.set(sha256(config), config);
294 const manifest = Buffer.from(
295 JSON.stringify({ schemaVersion: 2, mediaType: DOCKER_MANIFEST, config: { mediaType: "application/vnd.docker.container.image.v1+json", digest: sha256(config), size: config.length }, layers: [] }),
296 );
297 registry.manifests.set("base", { bytes: manifest, type: DOCKER_MANIFEST });
298 await appendRunnerImage({
299 ref: "r.example/acct/r:new",
300 base: "r.example/acct/r:base",
301 binary: Buffer.from("x"),
302 credentials: async () => ({ username: "u", password: "p" }),
303 fetchImpl,
304 });
305 assert.ok(registry.manifests.has("new"));
306 assert.equal(asked.length, 1, "one token, kept");
307 assert.equal(asked[0][0], "https://auth.example/token?service=r.example&scope=repository%3Aacct%2Fr%3Apull%2Cpush");
308 assert.equal(asked[0][1], `Basic ${Buffer.from("u:p").toString("base64")}`);
309});