@odla-ai/harness 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +178 -0
  3. package/dist/chunk-ATKV6VTU.js +168 -0
  4. package/dist/chunk-ATKV6VTU.js.map +1 -0
  5. package/dist/chunk-GE6CCN7W.js +93 -0
  6. package/dist/chunk-GE6CCN7W.js.map +1 -0
  7. package/dist/chunk-GMVZ4LZH.js +1769 -0
  8. package/dist/chunk-GMVZ4LZH.js.map +1 -0
  9. package/dist/chunk-PHXQH4YM.js +550 -0
  10. package/dist/chunk-PHXQH4YM.js.map +1 -0
  11. package/dist/chunk-PTXZVYD4.js +81 -0
  12. package/dist/chunk-PTXZVYD4.js.map +1 -0
  13. package/dist/chunk-QTUEF2HZ.js +9 -0
  14. package/dist/chunk-QTUEF2HZ.js.map +1 -0
  15. package/dist/cli.cjs +795 -0
  16. package/dist/cli.cjs.map +1 -0
  17. package/dist/cli.d.cts +1 -0
  18. package/dist/cli.d.ts +1 -0
  19. package/dist/cli.js +98 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/code-runtime-cli.cjs +2341 -0
  22. package/dist/code-runtime-cli.cjs.map +1 -0
  23. package/dist/code-runtime-cli.d.cts +1 -0
  24. package/dist/code-runtime-cli.d.ts +1 -0
  25. package/dist/code-runtime-cli.js +133 -0
  26. package/dist/code-runtime-cli.js.map +1 -0
  27. package/dist/index.cjs +228 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +44 -0
  30. package/dist/index.d.ts +44 -0
  31. package/dist/index.js +46 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/node.cjs +2580 -0
  34. package/dist/node.cjs.map +1 -0
  35. package/dist/node.d.cts +544 -0
  36. package/dist/node.d.ts +544 -0
  37. package/dist/node.js +71 -0
  38. package/dist/node.js.map +1 -0
  39. package/dist/testing.cjs +106 -0
  40. package/dist/testing.cjs.map +1 -0
  41. package/dist/testing.d.cts +25 -0
  42. package/dist/testing.d.ts +25 -0
  43. package/dist/testing.js +79 -0
  44. package/dist/testing.js.map +1 -0
  45. package/dist/types-D12vK3K9.d.cts +249 -0
  46. package/dist/types-D12vK3K9.d.ts +249 -0
  47. package/package.json +84 -0
@@ -0,0 +1,550 @@
1
+ import {
2
+ encodeAgentInput,
3
+ parseAgentOutput
4
+ } from "./chunk-GE6CCN7W.js";
5
+ import {
6
+ HARNESS_PROTOCOL_VERSION
7
+ } from "./chunk-QTUEF2HZ.js";
8
+
9
+ // src/container.ts
10
+ import { execFile, spawn } from "child_process";
11
+ import { constants } from "fs";
12
+ import { access } from "fs/promises";
13
+ import { delimiter, join } from "path";
14
+ import { getgid, getuid } from "process";
15
+ var DIGEST_IMAGE = /^[a-z0-9][a-z0-9._/-]*(?::[a-zA-Z0-9._-]+)?@sha256:[0-9a-f]{64}$/;
16
+ function assertPinnedImage(image) {
17
+ if (!DIGEST_IMAGE.test(image)) throw new TypeError("container image must be pinned by sha256 digest");
18
+ }
19
+ async function commandAvailable(engine) {
20
+ for (const directory of (process.env.PATH ?? "").split(delimiter).filter(Boolean)) {
21
+ try {
22
+ await access(join(directory, engine), constants.X_OK);
23
+ return true;
24
+ } catch {
25
+ }
26
+ }
27
+ return false;
28
+ }
29
+ async function selectContainerEngine(requested = "auto", options = {}) {
30
+ const platform = options.platform ?? process.platform;
31
+ const arch = options.arch ?? process.arch;
32
+ const uid = options.uid ?? (typeof getuid === "function" ? getuid() : 1e3);
33
+ const available = options.available ?? commandAvailable;
34
+ const validate = async (engine) => {
35
+ if (engine === "container" && (platform !== "darwin" || arch !== "arm64")) {
36
+ throw new TypeError("Apple container requires Apple Silicon macOS");
37
+ }
38
+ if (engine === "podman" && platform === "linux" && uid === 0) {
39
+ throw new TypeError("the Linux harness requires rootless Podman; do not run the runner as root");
40
+ }
41
+ if (!await available(engine)) throw new TypeError(`${engine} is not installed or executable`);
42
+ return engine;
43
+ };
44
+ if (requested !== "auto") return validate(requested);
45
+ const candidates = platform === "darwin" ? arch === "arm64" ? ["container", "podman"] : ["podman"] : platform === "linux" ? ["podman"] : [];
46
+ for (const engine of candidates) {
47
+ if (await available(engine)) return validate(engine);
48
+ }
49
+ if (platform === "linux") {
50
+ throw new TypeError("no rootless Podman found; install Podman or explicitly choose --engine docker after reviewing its daemon boundary");
51
+ }
52
+ if (platform === "darwin") {
53
+ throw new TypeError("Apple container is not installed; on Apple Silicon macOS 26 run `brew install container`, then retry (Podman Machine is the fallback)");
54
+ }
55
+ throw new TypeError("no supported container engine found");
56
+ }
57
+ function inspectRootlessPodman() {
58
+ return new Promise((resolve3, reject) => {
59
+ execFile(
60
+ "podman",
61
+ ["info", "--format", "{{.Host.Security.Rootless}}"],
62
+ { encoding: "utf8", maxBuffer: 16 * 1024, timeout: 1e4 },
63
+ (error, stdout) => {
64
+ if (error) {
65
+ reject(new TypeError("could not verify that the active Podman service is rootless"));
66
+ return;
67
+ }
68
+ resolve3(stdout.trim() === "true");
69
+ }
70
+ );
71
+ });
72
+ }
73
+ async function verifyContainerEngineBoundary(engine, options = {}) {
74
+ const platform = options.platform ?? process.platform;
75
+ const arch = options.arch ?? process.arch;
76
+ const uid = options.uid ?? (typeof getuid === "function" ? getuid() : 1e3);
77
+ if (engine === "container" && (platform !== "darwin" || arch !== "arm64")) {
78
+ throw new TypeError("Apple container requires Apple Silicon macOS");
79
+ }
80
+ if (engine !== "podman" || platform !== "linux") return;
81
+ if (uid === 0) throw new TypeError("the Linux harness requires rootless Podman; do not run the runner as root");
82
+ const rootless = await (options.podmanRootless ?? inspectRootlessPodman)();
83
+ if (!rootless) throw new TypeError("the active Podman service is not rootless; refusing to run the harness");
84
+ }
85
+ function buildContainerRunArgs(options) {
86
+ if (!options.allowUnpinnedImage) assertPinnedImage(options.image);
87
+ if (/[,\r\n]/.test(options.workspaceDir)) throw new TypeError("workspace path contains unsupported mount characters");
88
+ const uid = typeof getuid === "function" ? getuid() : 1e3;
89
+ const gid = typeof getgid === "function" ? getgid() : 1e3;
90
+ const safeAttempt = options.task.attemptId.toLowerCase().replace(/[^a-z0-9_.-]/g, "-").slice(0, 40);
91
+ const name = `odla-harness-${safeAttempt}-${crypto.randomUUID().slice(0, 8)}`;
92
+ const limits = options.limits ?? {};
93
+ const access2 = options.workspaceAccess ?? "read-write";
94
+ const appleMount = access2 === "none" ? [] : [`--mount=type=bind,source=${options.workspaceDir},target=/workspace${access2 === "read-only" ? ",readonly" : ""}`];
95
+ const ociMount = access2 === "none" ? [] : [`--mount=type=bind,src=${options.workspaceDir},dst=/workspace${access2 === "read-only" ? ",readonly" : ""}`];
96
+ if (options.engine === "container") {
97
+ return [
98
+ "run",
99
+ "--rm",
100
+ "--interactive",
101
+ `--name=${name}`,
102
+ "--network=none",
103
+ "--read-only",
104
+ "--cap-drop=ALL",
105
+ `--memory=${limits.memory ?? "1g"}`,
106
+ `--cpus=${limits.cpus ?? 1}`,
107
+ `--user=${uid}:${gid}`,
108
+ "--tmpfs=/tmp",
109
+ ...appleMount,
110
+ "--workdir=/workspace",
111
+ `--env=ODLA_HARNESS_PROTOCOL=${HARNESS_PROTOCOL_VERSION}`,
112
+ `--label=ai.odla.harness.attempt=${options.task.attemptId}`,
113
+ options.image
114
+ ];
115
+ }
116
+ return [
117
+ "run",
118
+ "--rm",
119
+ "--interactive",
120
+ `--name=${name}`,
121
+ "--pull=never",
122
+ "--network=none",
123
+ "--read-only",
124
+ "--cap-drop=ALL",
125
+ "--security-opt=no-new-privileges",
126
+ `--pids-limit=${limits.pids ?? 256}`,
127
+ `--memory=${limits.memory ?? "1g"}`,
128
+ `--cpus=${limits.cpus ?? 1}`,
129
+ `--user=${uid}:${gid}`,
130
+ `--tmpfs=/tmp:rw,noexec,nosuid,nodev,size=${limits.tmpfsBytes ?? 64 * 1024 * 1024}`,
131
+ ...ociMount,
132
+ "--workdir=/workspace",
133
+ `--env=ODLA_HARNESS_PROTOCOL=${HARNESS_PROTOCOL_VERSION}`,
134
+ `--label=ai.odla.harness.attempt=${options.task.attemptId}`,
135
+ options.image
136
+ ];
137
+ }
138
+ function containerName(args) {
139
+ return args.find((arg) => arg.startsWith("--name=")).slice("--name=".length);
140
+ }
141
+ async function runContainerAttempt(options) {
142
+ if (options.signal?.aborted) return { exitCode: 1, status: "cancelled", stderr: "" };
143
+ await verifyContainerEngineBoundary(options.engine);
144
+ const args = buildContainerRunArgs(options);
145
+ const name = containerName(args);
146
+ const child = spawn(options.engine, args, { stdio: ["pipe", "pipe", "pipe"], shell: false });
147
+ let stderr = "";
148
+ let outputBytes = 0;
149
+ let complete = null;
150
+ let stopped = false;
151
+ let exited = false;
152
+ child.stderr.setEncoding("utf8");
153
+ child.stderr.on("data", (text) => {
154
+ if (stderr.length < 64 * 1024) stderr += text.slice(0, 64 * 1024 - stderr.length);
155
+ });
156
+ const stop = (reason) => {
157
+ if (stopped || exited) return;
158
+ stopped = true;
159
+ if (!child.stdin.destroyed) {
160
+ const cancel = { protocolVersion: HARNESS_PROTOCOL_VERSION, type: "attempt.cancel", reason };
161
+ child.stdin.write(encodeAgentInput(cancel));
162
+ }
163
+ const removeArgs = options.engine === "container" ? ["delete", "--force", name] : ["rm", "-f", name];
164
+ const killer = spawn(options.engine, removeArgs, { stdio: "ignore", shell: false });
165
+ killer.unref();
166
+ };
167
+ const abort = () => stop("runner_cancelled");
168
+ options.signal?.addEventListener("abort", abort, { once: true });
169
+ const timeout = setTimeout(() => stop("timeout"), options.task.policy.timeoutMs);
170
+ const start = { protocolVersion: HARNESS_PROTOCOL_VERSION, type: "task.start", task: options.task };
171
+ if (!stopped && !options.signal?.aborted) child.stdin.write(encodeAgentInput(start));
172
+ const consume = (async () => {
173
+ let pending = Buffer.alloc(0);
174
+ const handleLine = async (raw) => {
175
+ const bytes = raw.at(-1) === 13 ? raw.subarray(0, -1) : raw;
176
+ if (bytes.byteLength > 1e6) throw new Error("agent message exceeds 1 MB");
177
+ const line = bytes.toString("utf8");
178
+ if (!line.trim()) return;
179
+ const message = parseAgentOutput(line);
180
+ if (message.type === "attempt.complete") complete = message;
181
+ const response = await options.onMessage(message);
182
+ if (response && !child.stdin.destroyed) child.stdin.write(encodeAgentInput(response));
183
+ };
184
+ try {
185
+ for await (const raw of child.stdout) {
186
+ const chunk = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
187
+ outputBytes += chunk.byteLength;
188
+ if (outputBytes > options.task.policy.maxOutputBytes) {
189
+ throw new Error(`agent output exceeds ${options.task.policy.maxOutputBytes} bytes`);
190
+ }
191
+ pending = Buffer.concat([pending, chunk]);
192
+ let newline = pending.indexOf(10);
193
+ while (newline >= 0) {
194
+ await handleLine(pending.subarray(0, newline));
195
+ pending = pending.subarray(newline + 1);
196
+ newline = pending.indexOf(10);
197
+ }
198
+ if (pending.byteLength > 1e6) throw new Error("agent message exceeds 1 MB");
199
+ }
200
+ if (pending.byteLength) await handleLine(pending);
201
+ } catch (error) {
202
+ stop("protocol_error");
203
+ throw error;
204
+ }
205
+ })();
206
+ const exit = new Promise((accept, reject) => {
207
+ child.once("error", reject);
208
+ child.once("exit", (code) => {
209
+ exited = true;
210
+ accept(code ?? 1);
211
+ });
212
+ });
213
+ try {
214
+ const [exitCode] = await Promise.all([exit, consume]);
215
+ if (stderr && options.onStderr) await options.onStderr(stderr);
216
+ if (options.signal?.aborted) return { exitCode, status: "cancelled", stderr };
217
+ const terminal = complete;
218
+ if (!terminal) return { exitCode, status: "failed", result: { error: "agent exited without completion" }, stderr };
219
+ return { exitCode, status: exitCode === 0 ? terminal.status : "failed", result: terminal.result, stderr };
220
+ } catch (error) {
221
+ stop("runner_error");
222
+ await exit.catch(() => 1);
223
+ throw error;
224
+ } finally {
225
+ clearTimeout(timeout);
226
+ options.signal?.removeEventListener("abort", abort);
227
+ }
228
+ }
229
+
230
+ // src/workspace-git-tree.ts
231
+ import { mkdir, mkdtemp, realpath, rm, writeFile } from "fs/promises";
232
+ import { tmpdir } from "os";
233
+ import { join as join2, resolve, sep } from "path";
234
+ import { spawn as spawn2 } from "child_process";
235
+
236
+ // src/workspace-policy.ts
237
+ import { isAbsolute } from "path";
238
+ var SKIP_WORKSPACE_DIRS = /* @__PURE__ */ new Set([
239
+ ".git",
240
+ ".odla",
241
+ ".wrangler",
242
+ "node_modules",
243
+ "dist",
244
+ "coverage"
245
+ ]);
246
+ var SECRET_WORKSPACE_FILE = /^(?:\.env(?:\..+)?|\.dev\.vars|\.dev-token(?:\..+)?|credentials(?:\..+)?\.json|dev-token(?:\..+)?(?:\.json)?)$/i;
247
+ function allowedWorkspacePath(relativePath) {
248
+ const parts = relativePath.split("/");
249
+ return !isAbsolute(relativePath) && !relativePath.includes("\\") && !relativePath.includes("\0") && !parts.some((part) => !part || part === "." || part === ".." || SKIP_WORKSPACE_DIRS.has(part)) && !SECRET_WORKSPACE_FILE.test(parts.at(-1) ?? "");
250
+ }
251
+
252
+ // src/workspace-git-tree.ts
253
+ async function gitOutput(cwd, args, maxBytes) {
254
+ const child = spawn2("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], shell: false });
255
+ const stdout = [];
256
+ const stderr = [];
257
+ let bytes = 0;
258
+ child.stdout.on("data", (chunk) => {
259
+ bytes += chunk.byteLength;
260
+ if (bytes > maxBytes) child.kill("SIGKILL");
261
+ else stdout.push(chunk);
262
+ });
263
+ child.stderr.on("data", (chunk) => {
264
+ if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16384) stderr.push(chunk);
265
+ });
266
+ const code = await new Promise((accept, reject) => {
267
+ child.once("error", reject);
268
+ child.once("exit", accept);
269
+ });
270
+ if (bytes > maxBytes) throw new Error(`git output exceeds ${maxBytes} bytes`);
271
+ if (code !== 0) throw new Error(`git command failed: ${Buffer.concat(stderr).toString("utf8").slice(0, 1e3)}`);
272
+ return Buffer.concat(stdout);
273
+ }
274
+ async function gitBlobs(cwd, entries, maxBytes) {
275
+ const child = spawn2("git", ["cat-file", "--batch"], { cwd, stdio: ["pipe", "pipe", "pipe"], shell: false });
276
+ const stdout = [];
277
+ const stderr = [];
278
+ let bytes = 0;
279
+ child.stdout.on("data", (chunk) => {
280
+ bytes += chunk.byteLength;
281
+ if (bytes > maxBytes + entries.length * 100) child.kill("SIGKILL");
282
+ else stdout.push(chunk);
283
+ });
284
+ child.stderr.on("data", (chunk) => {
285
+ if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16384) stderr.push(chunk);
286
+ });
287
+ child.stdin.end(`${entries.map((entry) => entry.hash).join("\n")}
288
+ `);
289
+ const code = await new Promise((accept, reject) => {
290
+ child.once("error", reject);
291
+ child.once("exit", accept);
292
+ });
293
+ if (bytes > maxBytes + entries.length * 100) throw new Error(`Git tree exceeds ${maxBytes} bytes`);
294
+ if (code !== 0) throw new Error(`git object read failed: ${Buffer.concat(stderr).toString("utf8").slice(0, 1e3)}`);
295
+ const output = Buffer.concat(stdout);
296
+ const blobs = [];
297
+ let offset = 0;
298
+ let total = 0;
299
+ for (const entry of entries) {
300
+ const newline = output.indexOf(10, offset);
301
+ if (newline < 0) throw new Error("git object output is truncated");
302
+ const match = /^([0-9a-f]{40,64}) blob ([0-9]+)$/.exec(output.subarray(offset, newline).toString("utf8"));
303
+ if (!match || match[1] !== entry.hash) throw new Error("git object output does not match its inventory");
304
+ const length = Number(match[2]);
305
+ if (!Number.isSafeInteger(length) || length < 0 || newline + 1 + length >= output.length) {
306
+ throw new Error("git object output has an invalid length");
307
+ }
308
+ const content = output.subarray(newline + 1, newline + 1 + length);
309
+ if (output[newline + 1 + length] !== 10) throw new Error("git object output is malformed");
310
+ total += content.byteLength;
311
+ if (total > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
312
+ blobs.push(content);
313
+ offset = newline + 1 + length + 1;
314
+ }
315
+ return blobs;
316
+ }
317
+ async function materializeGitTree(source, commitSha, options = {}) {
318
+ if (!/^[0-9a-f]{40}$/.test(commitSha)) throw new TypeError("Git tree requires an exact commit SHA");
319
+ const sourceDir = await realpath(resolve(source));
320
+ const maxFiles = options.maxFiles ?? 2e4;
321
+ const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
322
+ const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
323
+ const entries = inventory.flatMap((record) => {
324
+ const match = /^(100644|100755) blob ([0-9a-f]{40,64})\t([\s\S]+)$/.exec(record);
325
+ return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
326
+ });
327
+ if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
328
+ const root = await mkdtemp(join2(options.tempRoot ?? tmpdir(), "odla-git-tree-"));
329
+ const targetRoot = join2(root, "source");
330
+ await mkdir(targetRoot);
331
+ let byteCount = 0;
332
+ try {
333
+ const blobs = await gitBlobs(sourceDir, entries, maxBytes);
334
+ for (const [index, entry] of entries.entries()) {
335
+ const content = blobs[index];
336
+ byteCount += content.byteLength;
337
+ if (byteCount > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
338
+ const target = resolve(targetRoot, entry.path);
339
+ if (!target.startsWith(`${resolve(targetRoot)}${sep}`)) throw new TypeError("Git tree path escapes workspace");
340
+ await mkdir(resolve(target, ".."), { recursive: true });
341
+ await writeFile(target, content, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
342
+ }
343
+ return {
344
+ root,
345
+ sourceDir: targetRoot,
346
+ fileCount: entries.length,
347
+ byteCount,
348
+ cleanup: () => rm(root, { recursive: true, force: true })
349
+ };
350
+ } catch (error) {
351
+ await rm(root, { recursive: true, force: true });
352
+ throw error;
353
+ }
354
+ }
355
+
356
+ // src/workspace.ts
357
+ import { chmod, copyFile, lstat, mkdir as mkdir2, mkdtemp as mkdtemp2, readdir, realpath as realpath2, rm as rm2, stat } from "fs/promises";
358
+ import { tmpdir as tmpdir2 } from "os";
359
+ import { basename, join as join3, relative, resolve as resolve2, sep as sep2 } from "path";
360
+ import { spawn as spawn3 } from "child_process";
361
+ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
362
+ const files = [];
363
+ let bytes = 0;
364
+ const walk = async (dir) => {
365
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
366
+ if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
367
+ if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;
368
+ const path = join3(dir, entry.name);
369
+ if (entry.isSymbolicLink()) continue;
370
+ if (entry.isDirectory()) {
371
+ await walk(path);
372
+ continue;
373
+ }
374
+ if (!entry.isFile()) continue;
375
+ const metadata = await stat(path);
376
+ bytes += metadata.size;
377
+ if (files.length + 1 > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
378
+ if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
379
+ files.push({
380
+ source: path,
381
+ relativePath: relative(sourceDir, path),
382
+ mode: metadata.mode & 511,
383
+ bytes: metadata.size
384
+ });
385
+ }
386
+ };
387
+ await walk(sourceDir);
388
+ return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
389
+ }
390
+ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
391
+ const child = spawn3("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
392
+ cwd: sourceDir,
393
+ stdio: ["ignore", "pipe", "pipe"],
394
+ shell: false
395
+ });
396
+ const stdout = [];
397
+ const stderr = [];
398
+ let outputBytes = 0;
399
+ child.stdout.on("data", (chunk) => {
400
+ outputBytes += chunk.byteLength;
401
+ if (outputBytes > 8 * 1024 * 1024) child.kill("SIGKILL");
402
+ else stdout.push(chunk);
403
+ });
404
+ child.stderr.on("data", (chunk) => {
405
+ if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16384) stderr.push(chunk);
406
+ });
407
+ const code = await new Promise((accept, reject) => {
408
+ child.once("error", reject);
409
+ child.once("exit", accept);
410
+ });
411
+ if (outputBytes > 8 * 1024 * 1024) throw new Error("git file inventory exceeds 8 MiB");
412
+ if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr).toString("utf8").slice(0, 1e3)}`);
413
+ const paths = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
414
+ if (paths.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
415
+ const root = resolve2(sourceDir);
416
+ const files = [];
417
+ let bytes = 0;
418
+ for (const relativePath of paths) {
419
+ if (!allowedWorkspacePath(relativePath)) continue;
420
+ const source = resolve2(root, relativePath);
421
+ if (!source.startsWith(`${root}${sep2}`)) throw new TypeError("git file path escapes workspace");
422
+ let metadata;
423
+ try {
424
+ metadata = await lstat(source);
425
+ } catch (error) {
426
+ if (error.code === "ENOENT") continue;
427
+ throw error;
428
+ }
429
+ if (metadata.isSymbolicLink() || !metadata.isFile()) continue;
430
+ bytes += metadata.size;
431
+ if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
432
+ files.push({ source, relativePath, mode: metadata.mode & 511, bytes: metadata.size });
433
+ }
434
+ return files;
435
+ }
436
+ async function copyTree(files, destination) {
437
+ for (const file of files) {
438
+ const target = join3(destination, file.relativePath);
439
+ await mkdir2(resolve2(target, ".."), { recursive: true });
440
+ await copyFile(file.source, target);
441
+ await chmod(target, file.mode);
442
+ }
443
+ }
444
+ async function captureGitDiff(root, maxBytes) {
445
+ const child = spawn3("git", [
446
+ "diff",
447
+ "--no-index",
448
+ "--binary",
449
+ "--no-ext-diff",
450
+ "--src-prefix=a/",
451
+ "--dst-prefix=b/",
452
+ "--",
453
+ "baseline",
454
+ "workspace"
455
+ ], { cwd: root, stdio: ["ignore", "pipe", "pipe"], shell: false });
456
+ const stdout = [];
457
+ const stderr = [];
458
+ let bytes = 0;
459
+ child.stdout.on("data", (chunk) => {
460
+ bytes += chunk.byteLength;
461
+ if (bytes > maxBytes) child.kill("SIGKILL");
462
+ else stdout.push(chunk);
463
+ });
464
+ child.stderr.on("data", (chunk) => {
465
+ if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16384) stderr.push(chunk);
466
+ });
467
+ const code = await new Promise((accept, reject) => {
468
+ child.once("error", reject);
469
+ child.once("exit", accept);
470
+ });
471
+ if (bytes > maxBytes) throw new Error(`patch exceeds ${maxBytes} bytes`);
472
+ if (code !== 0 && code !== 1) {
473
+ throw new Error(`git diff failed: ${Buffer.concat(stderr).toString("utf8").slice(0, 1e3)}`);
474
+ }
475
+ return Buffer.concat(stdout).toString("utf8").replaceAll("a/baseline/", "a/").replaceAll("a/workspace/", "a/").replaceAll("b/baseline/", "b/").replaceAll("b/workspace/", "b/").replaceAll("--- a/baseline", "--- a").replaceAll("+++ b/workspace", "+++ b");
476
+ }
477
+ async function stageWorkspace(source, options = {}) {
478
+ const sourceDir = await realpath2(resolve2(source));
479
+ const sourceStat = await stat(sourceDir);
480
+ if (!sourceStat.isDirectory()) throw new TypeError("workspace source must be a directory");
481
+ const root = await mkdtemp2(join3(options.tempRoot ?? tmpdir2(), "odla-harness-"));
482
+ const baselineDir = join3(root, "baseline");
483
+ const workspaceDir = join3(root, "workspace");
484
+ await Promise.all([mkdir2(baselineDir), mkdir2(workspaceDir)]);
485
+ try {
486
+ const maxFiles = options.maxFiles ?? 2e4;
487
+ const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
488
+ const files = options.gitTrackedAndUnignored ? await gitSourceFiles(sourceDir, maxFiles, maxBytes) : await sourceFiles(sourceDir, maxFiles, maxBytes);
489
+ await Promise.all([copyTree(files, baselineDir), copyTree(files, workspaceDir)]);
490
+ return {
491
+ root,
492
+ baselineDir,
493
+ workspaceDir,
494
+ fileCount: files.length,
495
+ byteCount: files.reduce((sum, file) => sum + file.bytes, 0),
496
+ patch: (maxBytes2) => captureGitDiff(root, maxBytes2),
497
+ cleanup: () => rm2(root, { recursive: true, force: true })
498
+ };
499
+ } catch (error) {
500
+ await rm2(root, { recursive: true, force: true });
501
+ throw error;
502
+ }
503
+ }
504
+ async function stageWorkspacePair(baselineSource, workspaceSource, options = {}) {
505
+ const baselineDirSource = await realpath2(resolve2(baselineSource));
506
+ const workspaceDirSource = await realpath2(resolve2(workspaceSource));
507
+ const maxFiles = options.maxFiles ?? 2e4;
508
+ const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
509
+ const [baselineFiles, workspaceFiles] = await Promise.all([
510
+ sourceFiles(baselineDirSource, maxFiles, maxBytes),
511
+ sourceFiles(workspaceDirSource, maxFiles, maxBytes)
512
+ ]);
513
+ const root = await mkdtemp2(join3(options.tempRoot ?? tmpdir2(), "odla-harness-"));
514
+ const baselineDir = join3(root, "baseline");
515
+ const workspaceDir = join3(root, "workspace");
516
+ await Promise.all([mkdir2(baselineDir), mkdir2(workspaceDir)]);
517
+ try {
518
+ await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);
519
+ return {
520
+ root,
521
+ baselineDir,
522
+ workspaceDir,
523
+ fileCount: workspaceFiles.length,
524
+ byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),
525
+ patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),
526
+ cleanup: () => rm2(root, { recursive: true, force: true })
527
+ };
528
+ } catch (error) {
529
+ await rm2(root, { recursive: true, force: true });
530
+ throw error;
531
+ }
532
+ }
533
+ function safeWorkspaceLabel(value) {
534
+ const label = basename(value).toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
535
+ if (!label) throw new TypeError("workspace label is empty");
536
+ return label.slice(0, 80);
537
+ }
538
+
539
+ export {
540
+ assertPinnedImage,
541
+ selectContainerEngine,
542
+ verifyContainerEngineBoundary,
543
+ buildContainerRunArgs,
544
+ runContainerAttempt,
545
+ materializeGitTree,
546
+ stageWorkspace,
547
+ stageWorkspacePair,
548
+ safeWorkspaceLabel
549
+ };
550
+ //# sourceMappingURL=chunk-PHXQH4YM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/container.ts","../src/workspace-git-tree.ts","../src/workspace-policy.ts","../src/workspace.ts"],"sourcesContent":["import { execFile, spawn } from \"node:child_process\";\nimport { constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { delimiter, join } from \"node:path\";\nimport { getgid, getuid } from \"node:process\";\nimport { encodeAgentInput, parseAgentOutput } from \"./protocol\";\nimport {\n HARNESS_PROTOCOL_VERSION,\n type HarnessAgentInput,\n type HarnessAgentOutput,\n type HarnessTaskSpec,\n} from \"./types\";\n\nconst DIGEST_IMAGE = /^[a-z0-9][a-z0-9._/-]*(?::[a-zA-Z0-9._-]+)?@sha256:[0-9a-f]{64}$/;\n\n/** Supported command-line container engines for isolated harness attempts. */\nexport type ContainerEngine = \"container\" | \"podman\" | \"docker\";\n\n/** Host facts and executable probe used while selecting a safe container engine. */\nexport interface ContainerEngineSelectionOptions {\n platform?: NodeJS.Platform;\n arch?: string;\n uid?: number;\n available?: (engine: ContainerEngine) => Promise<boolean>;\n}\n\n/** Host facts and rootless probe used to verify the selected engine boundary. */\nexport interface ContainerEngineVerificationOptions {\n platform?: NodeJS.Platform;\n arch?: string;\n uid?: number;\n podmanRootless?: () => Promise<boolean>;\n}\n\n/** Optional CPU, memory, process, and temporary-filesystem limits for an attempt. */\nexport interface ContainerLimits {\n cpus?: number;\n memory?: string;\n pids?: number;\n tmpfsBytes?: number;\n}\n\n/** Container, task, callback, and cancellation settings for one agent attempt. */\nexport interface ContainerRunOptions {\n engine: ContainerEngine;\n image: string;\n workspaceDir: string;\n workspaceAccess?: \"read-write\" | \"read-only\" | \"none\";\n task: HarnessTaskSpec;\n limits?: ContainerLimits;\n allowUnpinnedImage?: boolean;\n signal?: AbortSignal;\n onMessage(message: HarnessAgentOutput): Promise<HarnessAgentInput | void>;\n onStderr?(text: string): Promise<void> | void;\n}\n\n/** Terminal container outcome and bounded diagnostic output returned to the runner. */\nexport interface ContainerRunResult {\n exitCode: number;\n status: \"completed\" | \"failed\" | \"cancelled\";\n result?: unknown;\n stderr: string;\n}\n\n/** Require an immutable OCI image reference pinned to a SHA-256 digest. */\nexport function assertPinnedImage(image: string): void {\n if (!DIGEST_IMAGE.test(image)) throw new TypeError(\"container image must be pinned by sha256 digest\");\n}\n\nasync function commandAvailable(engine: ContainerEngine): Promise<boolean> {\n for (const directory of (process.env.PATH ?? \"\").split(delimiter).filter(Boolean)) {\n try { await access(join(directory, engine), constants.X_OK); return true; } catch { /* try the next PATH entry */ }\n }\n return false;\n}\n\n/** Choose the strongest installed local default without silently selecting a\n * rootful Linux daemon. Apple container is a per-container VM boundary;\n * rootless Podman is the Linux default; Docker remains explicit. */\nexport async function selectContainerEngine(\n requested: ContainerEngine | \"auto\" = \"auto\",\n options: ContainerEngineSelectionOptions = {},\n): Promise<ContainerEngine> {\n const platform = options.platform ?? process.platform;\n const arch = options.arch ?? process.arch;\n const uid = options.uid ?? (typeof getuid === \"function\" ? getuid() : 1000);\n const available = options.available ?? commandAvailable;\n const validate = async (engine: ContainerEngine): Promise<ContainerEngine> => {\n if (engine === \"container\" && (platform !== \"darwin\" || arch !== \"arm64\")) {\n throw new TypeError(\"Apple container requires Apple Silicon macOS\");\n }\n if (engine === \"podman\" && platform === \"linux\" && uid === 0) {\n throw new TypeError(\"the Linux harness requires rootless Podman; do not run the runner as root\");\n }\n if (!(await available(engine))) throw new TypeError(`${engine} is not installed or executable`);\n return engine;\n };\n if (requested !== \"auto\") return validate(requested);\n const candidates: ContainerEngine[] = platform === \"darwin\"\n ? arch === \"arm64\" ? [\"container\", \"podman\"] : [\"podman\"]\n : platform === \"linux\" ? [\"podman\"] : [];\n for (const engine of candidates) {\n if (await available(engine)) return validate(engine);\n }\n if (platform === \"linux\") {\n throw new TypeError(\"no rootless Podman found; install Podman or explicitly choose --engine docker after reviewing its daemon boundary\");\n }\n if (platform === \"darwin\") {\n throw new TypeError(\"Apple container is not installed; on Apple Silicon macOS 26 run `brew install container`, then retry (Podman Machine is the fallback)\");\n }\n throw new TypeError(\"no supported container engine found\");\n}\n\nfunction inspectRootlessPodman(): Promise<boolean> {\n return new Promise((resolve, reject) => {\n execFile(\n \"podman\",\n [\"info\", \"--format\", \"{{.Host.Security.Rootless}}\"],\n { encoding: \"utf8\", maxBuffer: 16 * 1024, timeout: 10_000 },\n (error, stdout) => {\n if (error) {\n reject(new TypeError(\"could not verify that the active Podman service is rootless\"));\n return;\n }\n resolve(stdout.trim() === \"true\");\n },\n );\n });\n}\n\n/** Fail closed if the selected engine cannot provide the promised host\n * boundary. This is checked for every attempt so a changed Podman connection\n * cannot silently turn a rootless Linux runner into a rootful one. */\nexport async function verifyContainerEngineBoundary(\n engine: ContainerEngine,\n options: ContainerEngineVerificationOptions = {},\n): Promise<void> {\n const platform = options.platform ?? process.platform;\n const arch = options.arch ?? process.arch;\n const uid = options.uid ?? (typeof getuid === \"function\" ? getuid() : 1000);\n if (engine === \"container\" && (platform !== \"darwin\" || arch !== \"arm64\")) {\n throw new TypeError(\"Apple container requires Apple Silicon macOS\");\n }\n if (engine !== \"podman\" || platform !== \"linux\") return;\n if (uid === 0) throw new TypeError(\"the Linux harness requires rootless Podman; do not run the runner as root\");\n const rootless = await (options.podmanRootless ?? inspectRootlessPodman)();\n if (!rootless) throw new TypeError(\"the active Podman service is not rootless; refusing to run the harness\");\n}\n\n/** Build hardened, networkless engine arguments without starting the container. */\nexport function buildContainerRunArgs(options: Omit<ContainerRunOptions, \"onMessage\" | \"onStderr\" | \"signal\">): string[] {\n if (!options.allowUnpinnedImage) assertPinnedImage(options.image);\n if (/[,\\r\\n]/.test(options.workspaceDir)) throw new TypeError(\"workspace path contains unsupported mount characters\");\n const uid = typeof getuid === \"function\" ? getuid() : 1000;\n const gid = typeof getgid === \"function\" ? getgid() : 1000;\n const safeAttempt = options.task.attemptId.toLowerCase().replace(/[^a-z0-9_.-]/g, \"-\").slice(0, 40);\n const name = `odla-harness-${safeAttempt}-${crypto.randomUUID().slice(0, 8)}`;\n const limits = options.limits ?? {};\n const access = options.workspaceAccess ?? \"read-write\";\n const appleMount = access === \"none\" ? [] : [`--mount=type=bind,source=${options.workspaceDir},target=/workspace${access === \"read-only\" ? \",readonly\" : \"\"}`];\n const ociMount = access === \"none\" ? [] : [`--mount=type=bind,src=${options.workspaceDir},dst=/workspace${access === \"read-only\" ? \",readonly\" : \"\"}`];\n if (options.engine === \"container\") {\n return [\n \"run\", \"--rm\", \"--interactive\", `--name=${name}`,\n \"--network=none\", \"--read-only\", \"--cap-drop=ALL\",\n `--memory=${limits.memory ?? \"1g\"}`, `--cpus=${limits.cpus ?? 1}`,\n `--user=${uid}:${gid}`, \"--tmpfs=/tmp\",\n ...appleMount,\n \"--workdir=/workspace\", `--env=ODLA_HARNESS_PROTOCOL=${HARNESS_PROTOCOL_VERSION}`,\n `--label=ai.odla.harness.attempt=${options.task.attemptId}`,\n options.image,\n ];\n }\n return [\n \"run\", \"--rm\", \"--interactive\", `--name=${name}`, \"--pull=never\",\n \"--network=none\", \"--read-only\", \"--cap-drop=ALL\",\n \"--security-opt=no-new-privileges\", `--pids-limit=${limits.pids ?? 256}`,\n `--memory=${limits.memory ?? \"1g\"}`, `--cpus=${limits.cpus ?? 1}`,\n `--user=${uid}:${gid}`,\n `--tmpfs=/tmp:rw,noexec,nosuid,nodev,size=${limits.tmpfsBytes ?? 64 * 1024 * 1024}`,\n ...ociMount,\n \"--workdir=/workspace\", `--env=ODLA_HARNESS_PROTOCOL=${HARNESS_PROTOCOL_VERSION}`,\n `--label=ai.odla.harness.attempt=${options.task.attemptId}`,\n options.image,\n ];\n}\n\nfunction containerName(args: string[]): string {\n return args.find((arg) => arg.startsWith(\"--name=\"))!.slice(\"--name=\".length);\n}\n\n/** Execute one JSONL agent inside a hardened Apple container, Podman, or Docker\n * boundary. The\n * container has no network and receives no credentials; inference requests are\n * bridged over stdin/stdout to the trusted runner process. */\nexport async function runContainerAttempt(options: ContainerRunOptions): Promise<ContainerRunResult> {\n if (options.signal?.aborted) return { exitCode: 1, status: \"cancelled\", stderr: \"\" };\n await verifyContainerEngineBoundary(options.engine);\n const args = buildContainerRunArgs(options);\n const name = containerName(args);\n const child = spawn(options.engine, args, { stdio: [\"pipe\", \"pipe\", \"pipe\"], shell: false });\n let stderr = \"\";\n let outputBytes = 0;\n let complete: Extract<HarnessAgentOutput, { type: \"attempt.complete\" }> | null = null;\n let stopped = false;\n let exited = false;\n\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (text: string) => {\n if (stderr.length < 64 * 1024) stderr += text.slice(0, 64 * 1024 - stderr.length);\n });\n\n const stop = (reason: string) => {\n if (stopped || exited) return;\n stopped = true;\n if (!child.stdin.destroyed) {\n const cancel: HarnessAgentInput = { protocolVersion: HARNESS_PROTOCOL_VERSION, type: \"attempt.cancel\", reason };\n child.stdin.write(encodeAgentInput(cancel));\n }\n const removeArgs = options.engine === \"container\" ? [\"delete\", \"--force\", name] : [\"rm\", \"-f\", name];\n const killer = spawn(options.engine, removeArgs, { stdio: \"ignore\", shell: false });\n killer.unref();\n };\n const abort = () => stop(\"runner_cancelled\");\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n\n const timeout = setTimeout(() => stop(\"timeout\"), options.task.policy.timeoutMs);\n const start: HarnessAgentInput = { protocolVersion: HARNESS_PROTOCOL_VERSION, type: \"task.start\", task: options.task };\n if (!stopped && !options.signal?.aborted) child.stdin.write(encodeAgentInput(start));\n\n const consume = (async () => {\n let pending = Buffer.alloc(0);\n const handleLine = async (raw: Buffer) => {\n const bytes = raw.at(-1) === 13 ? raw.subarray(0, -1) : raw;\n if (bytes.byteLength > 1_000_000) throw new Error(\"agent message exceeds 1 MB\");\n const line = bytes.toString(\"utf8\");\n if (!line.trim()) return;\n const message = parseAgentOutput(line);\n if (message.type === \"attempt.complete\") complete = message;\n const response = await options.onMessage(message);\n if (response && !child.stdin.destroyed) child.stdin.write(encodeAgentInput(response));\n };\n try {\n for await (const raw of child.stdout) {\n const chunk = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);\n outputBytes += chunk.byteLength;\n if (outputBytes > options.task.policy.maxOutputBytes) {\n throw new Error(`agent output exceeds ${options.task.policy.maxOutputBytes} bytes`);\n }\n pending = Buffer.concat([pending, chunk]);\n let newline = pending.indexOf(10);\n while (newline >= 0) {\n await handleLine(pending.subarray(0, newline));\n pending = pending.subarray(newline + 1);\n newline = pending.indexOf(10);\n }\n if (pending.byteLength > 1_000_000) throw new Error(\"agent message exceeds 1 MB\");\n }\n if (pending.byteLength) await handleLine(pending);\n } catch (error) {\n stop(\"protocol_error\");\n throw error;\n }\n })();\n\n const exit = new Promise<number>((accept, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", (code) => { exited = true; accept(code ?? 1); });\n });\n try {\n const [exitCode] = await Promise.all([exit, consume]);\n if (stderr && options.onStderr) await options.onStderr(stderr);\n if (options.signal?.aborted) return { exitCode, status: \"cancelled\", stderr };\n const terminal = complete as Extract<HarnessAgentOutput, { type: \"attempt.complete\" }> | null;\n if (!terminal) return { exitCode, status: \"failed\", result: { error: \"agent exited without completion\" }, stderr };\n return { exitCode, status: exitCode === 0 ? terminal.status : \"failed\", result: terminal.result, stderr };\n } catch (error) {\n stop(\"runner_error\");\n await exit.catch(() => 1);\n throw error;\n } finally {\n clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", abort);\n }\n}\n","import { mkdir, mkdtemp, realpath, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport { allowedWorkspacePath } from \"./workspace-policy\";\nimport type { StageWorkspaceOptions } from \"./workspace\";\n\n/** Disposable, filtered materialization of one committed Git tree. */\nexport interface MaterializedGitTree {\n root: string;\n sourceDir: string;\n fileCount: number;\n byteCount: number;\n cleanup(): Promise<void>;\n}\n\nasync function gitOutput(cwd: string, args: string[], maxBytes: number): Promise<Buffer> {\n const child = spawn(\"git\", args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"], shell: false });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n let bytes = 0;\n child.stdout.on(\"data\", (chunk: Buffer) => {\n bytes += chunk.byteLength;\n if (bytes > maxBytes) child.kill(\"SIGKILL\");\n else stdout.push(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16_384) stderr.push(chunk);\n });\n const code = await new Promise<number | null>((accept, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", accept);\n });\n if (bytes > maxBytes) throw new Error(`git output exceeds ${maxBytes} bytes`);\n if (code !== 0) throw new Error(`git command failed: ${Buffer.concat(stderr).toString(\"utf8\").slice(0, 1_000)}`);\n return Buffer.concat(stdout);\n}\n\nasync function gitBlobs(cwd: string, entries: Array<{ hash: string }>, maxBytes: number): Promise<Buffer[]> {\n const child = spawn(\"git\", [\"cat-file\", \"--batch\"], { cwd, stdio: [\"pipe\", \"pipe\", \"pipe\"], shell: false });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n let bytes = 0;\n child.stdout.on(\"data\", (chunk: Buffer) => {\n bytes += chunk.byteLength;\n if (bytes > maxBytes + entries.length * 100) child.kill(\"SIGKILL\");\n else stdout.push(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16_384) stderr.push(chunk);\n });\n child.stdin.end(`${entries.map((entry) => entry.hash).join(\"\\n\")}\\n`);\n const code = await new Promise<number | null>((accept, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", accept);\n });\n if (bytes > maxBytes + entries.length * 100) throw new Error(`Git tree exceeds ${maxBytes} bytes`);\n if (code !== 0) throw new Error(`git object read failed: ${Buffer.concat(stderr).toString(\"utf8\").slice(0, 1_000)}`);\n const output = Buffer.concat(stdout);\n const blobs: Buffer[] = [];\n let offset = 0;\n let total = 0;\n for (const entry of entries) {\n const newline = output.indexOf(0x0a, offset);\n if (newline < 0) throw new Error(\"git object output is truncated\");\n const match = /^([0-9a-f]{40,64}) blob ([0-9]+)$/.exec(output.subarray(offset, newline).toString(\"utf8\"));\n if (!match || match[1] !== entry.hash) throw new Error(\"git object output does not match its inventory\");\n const length = Number(match[2]);\n if (!Number.isSafeInteger(length) || length < 0 || newline + 1 + length >= output.length) {\n throw new Error(\"git object output has an invalid length\");\n }\n const content = output.subarray(newline + 1, newline + 1 + length);\n if (output[newline + 1 + length] !== 0x0a) throw new Error(\"git object output is malformed\");\n total += content.byteLength;\n if (total > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);\n blobs.push(content);\n offset = newline + 1 + length + 1;\n }\n return blobs;\n}\n\n/** Materialize ordinary files from an exact commit without copying secrets,\n * symlinks, ignored local files, or Git metadata. */\nexport async function materializeGitTree(\n source: string, commitSha: string,\n options: Pick<StageWorkspaceOptions, \"maxFiles\" | \"maxBytes\" | \"tempRoot\"> = {},\n): Promise<MaterializedGitTree> {\n if (!/^[0-9a-f]{40}$/.test(commitSha)) throw new TypeError(\"Git tree requires an exact commit SHA\");\n const sourceDir = await realpath(resolve(source));\n const maxFiles = options.maxFiles ?? 20_000;\n const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;\n const inventory = (await gitOutput(sourceDir, [\"ls-tree\", \"-rz\", commitSha], 16 * 1024 * 1024))\n .toString(\"utf8\").split(\"\\0\").filter(Boolean);\n const entries = inventory.flatMap((record) => {\n const match = /^(100644|100755) blob ([0-9a-f]{40,64})\\t([\\s\\S]+)$/.exec(record);\n return match && allowedWorkspacePath(match[3]!)\n ? [{ mode: match[1]!, hash: match[2]!, path: match[3]! }]\n : [];\n });\n if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);\n const root = await mkdtemp(join(options.tempRoot ?? tmpdir(), \"odla-git-tree-\"));\n const targetRoot = join(root, \"source\");\n await mkdir(targetRoot);\n let byteCount = 0;\n try {\n const blobs = await gitBlobs(sourceDir, entries, maxBytes);\n for (const [index, entry] of entries.entries()) {\n const content = blobs[index]!;\n byteCount += content.byteLength;\n if (byteCount > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);\n const target = resolve(targetRoot, entry.path);\n if (!target.startsWith(`${resolve(targetRoot)}${sep}`)) throw new TypeError(\"Git tree path escapes workspace\");\n await mkdir(resolve(target, \"..\"), { recursive: true });\n await writeFile(target, content, { flag: \"wx\", mode: entry.mode === \"100755\" ? 0o755 : 0o644 });\n }\n return { root, sourceDir: targetRoot, fileCount: entries.length, byteCount,\n cleanup: () => rm(root, { recursive: true, force: true }) };\n } catch (error) {\n await rm(root, { recursive: true, force: true });\n throw error;\n }\n}\n","import { isAbsolute } from \"node:path\";\n\nexport const SKIP_WORKSPACE_DIRS = new Set([\n \".git\", \".odla\", \".wrangler\", \"node_modules\", \"dist\", \"coverage\",\n]);\nexport const SECRET_WORKSPACE_FILE = /^(?:\\.env(?:\\..+)?|\\.dev\\.vars|\\.dev-token(?:\\..+)?|credentials(?:\\..+)?\\.json|dev-token(?:\\..+)?(?:\\.json)?)$/i;\n\n/** Reject paths that are unsafe or reserved at either the local or Git-tree boundary. */\nexport function allowedWorkspacePath(relativePath: string): boolean {\n const parts = relativePath.split(\"/\");\n return !isAbsolute(relativePath) && !relativePath.includes(\"\\\\\") && !relativePath.includes(\"\\0\")\n && !parts.some((part) => !part || part === \".\" || part === \"..\" || SKIP_WORKSPACE_DIRS.has(part))\n && !SECRET_WORKSPACE_FILE.test(parts.at(-1) ?? \"\");\n}\n","import { chmod, copyFile, lstat, mkdir, mkdtemp, readdir, realpath, rm, stat } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join, relative, resolve, sep } from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport { allowedWorkspacePath, SECRET_WORKSPACE_FILE, SKIP_WORKSPACE_DIRS } from \"./workspace-policy\";\nexport { materializeGitTree, type MaterializedGitTree } from \"./workspace-git-tree\";\n\n/** File, byte, and temporary-directory limits applied while staging a workspace. */\nexport interface StageWorkspaceOptions {\n maxFiles?: number;\n maxBytes?: number;\n tempRoot?: string;\n /** Stage tracked files plus non-ignored untracked files from a Git checkout. */\n gitTrackedAndUnignored?: boolean;\n}\n\n/** Disposable baseline and mutable workspace copy used to generate a bounded patch. */\nexport interface StagedWorkspace {\n root: string;\n baselineDir: string;\n workspaceDir: string;\n fileCount: number;\n byteCount: number;\n patch(maxBytes: number): Promise<string>;\n cleanup(): Promise<void>;\n}\n\ninterface SourceFile {\n source: string;\n relativePath: string;\n mode: number;\n bytes: number;\n}\n\nasync function sourceFiles(sourceDir: string, maxFiles: number, maxBytes: number): Promise<SourceFile[]> {\n const files: SourceFile[] = [];\n let bytes = 0;\n const walk = async (dir: string): Promise<void> => {\n for (const entry of await readdir(dir, { withFileTypes: true })) {\n if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;\n if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;\n const path = join(dir, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n await walk(path);\n continue;\n }\n if (!entry.isFile()) continue;\n const metadata = await stat(path);\n bytes += metadata.size;\n if (files.length + 1 > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);\n if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);\n files.push({\n source: path,\n relativePath: relative(sourceDir, path),\n mode: metadata.mode & 0o777,\n bytes: metadata.size,\n });\n }\n };\n await walk(sourceDir);\n return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n}\n\nasync function gitSourceFiles(sourceDir: string, maxFiles: number, maxBytes: number): Promise<SourceFile[]> {\n const child = spawn(\"git\", [\"ls-files\", \"-z\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: sourceDir, stdio: [\"ignore\", \"pipe\", \"pipe\"], shell: false,\n });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n let outputBytes = 0;\n child.stdout.on(\"data\", (chunk: Buffer) => {\n outputBytes += chunk.byteLength;\n if (outputBytes > 8 * 1024 * 1024) child.kill(\"SIGKILL\");\n else stdout.push(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16_384) stderr.push(chunk);\n });\n const code = await new Promise<number | null>((accept, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", accept);\n });\n if (outputBytes > 8 * 1024 * 1024) throw new Error(\"git file inventory exceeds 8 MiB\");\n if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr).toString(\"utf8\").slice(0, 1_000)}`);\n const paths = Buffer.concat(stdout).toString(\"utf8\").split(\"\\0\").filter(Boolean).sort();\n if (paths.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);\n const root = resolve(sourceDir);\n const files: SourceFile[] = [];\n let bytes = 0;\n for (const relativePath of paths) {\n if (!allowedWorkspacePath(relativePath)) continue;\n const source = resolve(root, relativePath);\n if (!source.startsWith(`${root}${sep}`)) throw new TypeError(\"git file path escapes workspace\");\n let metadata;\n try { metadata = await lstat(source); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw error;\n }\n if (metadata.isSymbolicLink() || !metadata.isFile()) continue;\n bytes += metadata.size;\n if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);\n files.push({ source, relativePath, mode: metadata.mode & 0o777, bytes: metadata.size });\n }\n return files;\n}\n\nasync function copyTree(files: SourceFile[], destination: string): Promise<void> {\n for (const file of files) {\n const target = join(destination, file.relativePath);\n await mkdir(resolve(target, \"..\"), { recursive: true });\n await copyFile(file.source, target);\n await chmod(target, file.mode);\n }\n}\n\nasync function captureGitDiff(root: string, maxBytes: number): Promise<string> {\n const child = spawn(\"git\", [\n \"diff\", \"--no-index\", \"--binary\", \"--no-ext-diff\",\n \"--src-prefix=a/\", \"--dst-prefix=b/\", \"--\", \"baseline\", \"workspace\",\n ], { cwd: root, stdio: [\"ignore\", \"pipe\", \"pipe\"], shell: false });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n let bytes = 0;\n child.stdout.on(\"data\", (chunk: Buffer) => {\n bytes += chunk.byteLength;\n if (bytes > maxBytes) child.kill(\"SIGKILL\");\n else stdout.push(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (stderr.reduce((sum, value) => sum + value.byteLength, 0) < 16_384) stderr.push(chunk);\n });\n const code = await new Promise<number | null>((accept, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", accept);\n });\n if (bytes > maxBytes) throw new Error(`patch exceeds ${maxBytes} bytes`);\n if (code !== 0 && code !== 1) {\n throw new Error(`git diff failed: ${Buffer.concat(stderr).toString(\"utf8\").slice(0, 1_000)}`);\n }\n return Buffer.concat(stdout).toString(\"utf8\")\n .replaceAll(\"a/baseline/\", \"a/\")\n .replaceAll(\"a/workspace/\", \"a/\")\n .replaceAll(\"b/baseline/\", \"b/\")\n .replaceAll(\"b/workspace/\", \"b/\")\n .replaceAll(\"--- a/baseline\", \"--- a\")\n .replaceAll(\"+++ b/workspace\", \"+++ b\");\n}\n\n/** Copy a bounded, secret-filtered workspace twice: one immutable baseline and\n * one disposable directory mounted into the container. The developer checkout\n * itself is never mounted. */\nexport async function stageWorkspace(source: string, options: StageWorkspaceOptions = {}): Promise<StagedWorkspace> {\n const sourceDir = await realpath(resolve(source));\n const sourceStat = await stat(sourceDir);\n if (!sourceStat.isDirectory()) throw new TypeError(\"workspace source must be a directory\");\n const root = await mkdtemp(join(options.tempRoot ?? tmpdir(), \"odla-harness-\"));\n const baselineDir = join(root, \"baseline\");\n const workspaceDir = join(root, \"workspace\");\n await Promise.all([mkdir(baselineDir), mkdir(workspaceDir)]);\n try {\n const maxFiles = options.maxFiles ?? 20_000;\n const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;\n const files = options.gitTrackedAndUnignored\n ? await gitSourceFiles(sourceDir, maxFiles, maxBytes)\n : await sourceFiles(sourceDir, maxFiles, maxBytes);\n await Promise.all([copyTree(files, baselineDir), copyTree(files, workspaceDir)]);\n return {\n root,\n baselineDir,\n workspaceDir,\n fileCount: files.length,\n byteCount: files.reduce((sum, file) => sum + file.bytes, 0),\n patch: (maxBytes) => captureGitDiff(root, maxBytes),\n cleanup: () => rm(root, { recursive: true, force: true }),\n };\n } catch (error) {\n await rm(root, { recursive: true, force: true });\n throw error;\n }\n}\n\n/** Create a disposable workspace whose diff base and initial editable tree\n * intentionally come from different already-filtered sources. */\nexport async function stageWorkspacePair(\n baselineSource: string, workspaceSource: string, options: StageWorkspaceOptions = {},\n): Promise<StagedWorkspace> {\n const baselineDirSource = await realpath(resolve(baselineSource));\n const workspaceDirSource = await realpath(resolve(workspaceSource));\n const maxFiles = options.maxFiles ?? 20_000;\n const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;\n const [baselineFiles, workspaceFiles] = await Promise.all([\n sourceFiles(baselineDirSource, maxFiles, maxBytes),\n sourceFiles(workspaceDirSource, maxFiles, maxBytes),\n ]);\n const root = await mkdtemp(join(options.tempRoot ?? tmpdir(), \"odla-harness-\"));\n const baselineDir = join(root, \"baseline\");\n const workspaceDir = join(root, \"workspace\");\n await Promise.all([mkdir(baselineDir), mkdir(workspaceDir)]);\n try {\n await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);\n return {\n root, baselineDir, workspaceDir,\n fileCount: workspaceFiles.length,\n byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),\n patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),\n cleanup: () => rm(root, { recursive: true, force: true }),\n };\n } catch (error) {\n await rm(root, { recursive: true, force: true });\n throw error;\n }\n}\n\n/** Convert a path-like value into a bounded lowercase label safe for runner metadata. */\nexport function safeWorkspaceLabel(value: string): string {\n const label = basename(value).toLowerCase().replace(/[^a-z0-9_-]+/g, \"-\").replace(/^-+|-+$/g, \"\");\n if (!label) throw new TypeError(\"workspace label is empty\");\n return label.slice(0, 80);\n}\n"],"mappings":"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","names":["resolve","access","join","spawn","spawn","join","mkdir","mkdtemp","realpath","rm","tmpdir","join","resolve","sep","spawn","join","spawn","resolve","sep","mkdir","realpath","mkdtemp","tmpdir","maxBytes","rm"]}