@theokit/sdk 5.12.0 → 5.13.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 (139) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/{agent-IG7BP6GN.js → agent-5DSDDH7K.js} +5 -5
  3. package/dist/{agent-IG7BP6GN.js.map → agent-5DSDDH7K.js.map} +1 -1
  4. package/dist/{agent-CVzDy_Oj.d.ts → agent-DSMuwADp.d.ts} +9 -2
  5. package/dist/{agent-BVKIUP7F.cjs → agent-WOMRT3KX.cjs} +6 -6
  6. package/dist/{agent-BVKIUP7F.cjs.map → agent-WOMRT3KX.cjs.map} +1 -1
  7. package/dist/{agent-Cn0sphpA.d.cts → agent-iW5kPpfT.d.cts} +9 -2
  8. package/dist/{chunk-XJ4C4NFX.js → chunk-2PRGRYEQ.js} +61 -47
  9. package/dist/chunk-2PRGRYEQ.js.map +1 -0
  10. package/dist/{chunk-HN4IKB6X.cjs → chunk-2XWAYCFM.cjs} +15 -13
  11. package/dist/chunk-2XWAYCFM.cjs.map +1 -0
  12. package/dist/{chunk-VVGFZQZC.js → chunk-3LMVJTNJ.js} +9 -5
  13. package/dist/chunk-3LMVJTNJ.js.map +1 -0
  14. package/dist/{chunk-IO4RI5ZJ.cjs → chunk-47EACDOC.cjs} +4 -4
  15. package/dist/{chunk-IO4RI5ZJ.cjs.map → chunk-47EACDOC.cjs.map} +1 -1
  16. package/dist/{chunk-LSWHDOCL.cjs → chunk-4UYHP6NF.cjs} +64 -48
  17. package/dist/chunk-4UYHP6NF.cjs.map +1 -0
  18. package/dist/{chunk-ZLFFDPXC.js → chunk-73IITAF7.js} +36 -14
  19. package/dist/chunk-73IITAF7.js.map +1 -0
  20. package/dist/{chunk-XRPMZ7TO.js → chunk-CYWOJA6B.js} +6 -4
  21. package/dist/chunk-CYWOJA6B.js.map +1 -0
  22. package/dist/{chunk-AQW54OWQ.js → chunk-DFBWYETS.js} +5 -3
  23. package/dist/chunk-DFBWYETS.js.map +1 -0
  24. package/dist/{chunk-YOVZMN4P.cjs → chunk-DVP3YMDA.cjs} +3 -3
  25. package/dist/{chunk-YOVZMN4P.cjs.map → chunk-DVP3YMDA.cjs.map} +1 -1
  26. package/dist/{chunk-BRWI4HLK.cjs → chunk-FLDHYF5C.cjs} +13 -3
  27. package/dist/chunk-FLDHYF5C.cjs.map +1 -0
  28. package/dist/{chunk-BJ7BPLQK.js → chunk-JX4LB6XO.js} +124 -13
  29. package/dist/chunk-JX4LB6XO.js.map +1 -0
  30. package/dist/{chunk-Q6WT5535.cjs → chunk-KL7ZUMK3.cjs} +161 -50
  31. package/dist/chunk-KL7ZUMK3.cjs.map +1 -0
  32. package/dist/{chunk-FEAWEBWN.cjs → chunk-PDOXYXWX.cjs} +6 -4
  33. package/dist/chunk-PDOXYXWX.cjs.map +1 -0
  34. package/dist/{chunk-EEK7S77K.js → chunk-QGDPMM3C.js} +13 -3
  35. package/dist/chunk-QGDPMM3C.js.map +1 -0
  36. package/dist/{chunk-ZWLFHSON.cjs → chunk-R35ZJAYT.cjs} +38 -15
  37. package/dist/chunk-R35ZJAYT.cjs.map +1 -0
  38. package/dist/{chunk-4YD2WI57.cjs → chunk-R427EOZE.cjs} +19 -15
  39. package/dist/chunk-R427EOZE.cjs.map +1 -0
  40. package/dist/{chunk-TLVI2OQK.cjs → chunk-SETHRLQS.cjs} +18 -2
  41. package/dist/chunk-SETHRLQS.cjs.map +1 -0
  42. package/dist/{chunk-BO3PV3OP.js → chunk-TDED5XES.js} +18 -3
  43. package/dist/chunk-TDED5XES.js.map +1 -0
  44. package/dist/{chunk-4GUFNDZR.js → chunk-XOYNB3YN.js} +3 -3
  45. package/dist/{chunk-4GUFNDZR.js.map → chunk-XOYNB3YN.js.map} +1 -1
  46. package/dist/{chunk-NJBJ3CUG.js → chunk-ZTP6ZACR.js} +3 -3
  47. package/dist/{chunk-NJBJ3CUG.js.map → chunk-ZTP6ZACR.js.map} +1 -1
  48. package/dist/{compact-session-3U2JYTVG.js → compact-session-5HMX6KYT.js} +3 -3
  49. package/dist/{compact-session-3U2JYTVG.js.map → compact-session-5HMX6KYT.js.map} +1 -1
  50. package/dist/{compact-session-NM56BREJ.cjs → compact-session-B7P6EU3Z.cjs} +12 -12
  51. package/dist/{compact-session-NM56BREJ.cjs.map → compact-session-B7P6EU3Z.cjs.map} +1 -1
  52. package/dist/{cron-BWDYetbq.d.cts → cron-BvxrLW5J.d.cts} +1 -1
  53. package/dist/{cron-CHn-F0fC.d.ts → cron-DdKzwJqK.d.ts} +1 -1
  54. package/dist/cron.cjs +5 -5
  55. package/dist/cron.d.cts +2 -2
  56. package/dist/cron.d.ts +2 -2
  57. package/dist/cron.js +4 -4
  58. package/dist/eval.cjs +9 -9
  59. package/dist/eval.js +4 -4
  60. package/dist/{executor-HKHT4CWS.cjs → executor-5QL5AXIZ.cjs} +18 -15
  61. package/dist/executor-5QL5AXIZ.cjs.map +1 -0
  62. package/dist/{executor-3D2UDJHW.js → executor-THUXNAFR.js} +6 -3
  63. package/dist/executor-THUXNAFR.js.map +1 -0
  64. package/dist/generate-object-A5F576IT.cjs +20 -0
  65. package/dist/{generate-object-XBWD2PU7.cjs.map → generate-object-A5F576IT.cjs.map} +1 -1
  66. package/dist/{generate-object-S7MNVF2V.js → generate-object-TBDOBBYW.js} +4 -4
  67. package/dist/{generate-object-S7MNVF2V.js.map → generate-object-TBDOBBYW.js.map} +1 -1
  68. package/dist/generate-object.d.ts +14 -1
  69. package/dist/index.cjs +43 -43
  70. package/dist/index.d.cts +30 -4
  71. package/dist/index.d.ts +30 -4
  72. package/dist/index.js +13 -13
  73. package/dist/{inject-session-THABTKJY.js → inject-session-75L3NCNL.js} +3 -3
  74. package/dist/{inject-session-THABTKJY.js.map → inject-session-75L3NCNL.js.map} +1 -1
  75. package/dist/{inject-session-JVTZNQF6.cjs → inject-session-WOH7TPDX.cjs} +4 -4
  76. package/dist/{inject-session-JVTZNQF6.cjs.map → inject-session-WOH7TPDX.cjs.map} +1 -1
  77. package/dist/internal/providers/discovery.d.ts +2 -2
  78. package/dist/internal/providers/trust-gate.d.ts +35 -0
  79. package/dist/internal/runtime/plugin-loader/manifest-entry-import.d.ts +17 -0
  80. package/dist/internal/runtime/plugin-loader/workspace-plugin-trust.d.ts +16 -0
  81. package/dist/internal/structured-output-helpers.d.ts +5 -2
  82. package/dist/sandbox/bwrap.d.cts +10 -8
  83. package/dist/sandbox/bwrap.d.ts +10 -8
  84. package/dist/sandbox/deny-read.d.cts +24 -0
  85. package/dist/sandbox/deny-read.d.ts +24 -0
  86. package/dist/sandbox/index.cjs +198 -46
  87. package/dist/sandbox/index.cjs.map +1 -1
  88. package/dist/sandbox/index.d.cts +2 -1
  89. package/dist/sandbox/index.d.ts +2 -1
  90. package/dist/sandbox/index.js +184 -36
  91. package/dist/sandbox/index.js.map +1 -1
  92. package/dist/sandbox/linux-sandbox.d.cts +40 -5
  93. package/dist/sandbox/linux-sandbox.d.ts +40 -5
  94. package/dist/sandbox/local-sandbox.d.cts +3 -1
  95. package/dist/sandbox/local-sandbox.d.ts +3 -1
  96. package/dist/sandbox/seccomp-delivery.d.cts +49 -0
  97. package/dist/sandbox/seccomp-delivery.d.ts +49 -0
  98. package/dist/sandbox/shell-escape.d.cts +14 -2
  99. package/dist/sandbox/shell-escape.d.ts +14 -2
  100. package/dist/sandbox/types.d.cts +45 -0
  101. package/dist/sandbox/types.d.ts +45 -0
  102. package/dist/stream-object-AS4YYM4B.cjs +20 -0
  103. package/dist/{stream-object-TEEK3CAX.cjs.map → stream-object-AS4YYM4B.cjs.map} +1 -1
  104. package/dist/stream-object-EKM4WGTI.js +7 -0
  105. package/dist/{stream-object-R6SMYV4R.js.map → stream-object-EKM4WGTI.js.map} +1 -1
  106. package/dist/stream-object.d.ts +14 -1
  107. package/dist/subagents-loader.d.cts +1 -1
  108. package/dist/subagents-loader.d.ts +1 -1
  109. package/dist/types/agent.d.ts +8 -1
  110. package/dist/workflow-as-tool.d.ts +39 -5
  111. package/dist/workflow-errors.d.ts +16 -0
  112. package/dist/workflow.cjs +31 -23
  113. package/dist/workflow.d.cts +54 -4
  114. package/dist/workflow.d.ts +54 -4
  115. package/dist/workflow.js +2 -2
  116. package/docs/error-codes.md +16 -13
  117. package/docs/harness-capability-map.md +51 -5
  118. package/package.json +1 -1
  119. package/dist/chunk-4YD2WI57.cjs.map +0 -1
  120. package/dist/chunk-AQW54OWQ.js.map +0 -1
  121. package/dist/chunk-BJ7BPLQK.js.map +0 -1
  122. package/dist/chunk-BO3PV3OP.js.map +0 -1
  123. package/dist/chunk-BRWI4HLK.cjs.map +0 -1
  124. package/dist/chunk-EEK7S77K.js.map +0 -1
  125. package/dist/chunk-FEAWEBWN.cjs.map +0 -1
  126. package/dist/chunk-HN4IKB6X.cjs.map +0 -1
  127. package/dist/chunk-LSWHDOCL.cjs.map +0 -1
  128. package/dist/chunk-Q6WT5535.cjs.map +0 -1
  129. package/dist/chunk-TLVI2OQK.cjs.map +0 -1
  130. package/dist/chunk-VVGFZQZC.js.map +0 -1
  131. package/dist/chunk-XJ4C4NFX.js.map +0 -1
  132. package/dist/chunk-XRPMZ7TO.js.map +0 -1
  133. package/dist/chunk-ZLFFDPXC.js.map +0 -1
  134. package/dist/chunk-ZWLFHSON.cjs.map +0 -1
  135. package/dist/executor-3D2UDJHW.js.map +0 -1
  136. package/dist/executor-HKHT4CWS.cjs.map +0 -1
  137. package/dist/generate-object-XBWD2PU7.cjs +0 -20
  138. package/dist/stream-object-R6SMYV4R.js +0 -7
  139. package/dist/stream-object-TEEK3CAX.cjs +0 -20
@@ -1,13 +1,71 @@
1
- import { shellEscapePosix, LocalSandbox } from '../chunk-EEK7S77K.js';
2
- export { LocalSandbox, SandboxBackend, SandboxNotAvailableError, SandboxSecurityError, resolveSandbox } from '../chunk-EEK7S77K.js';
1
+ import { shellEscapePosix, LocalSandbox, SandboxNotAvailableError } from '../chunk-QGDPMM3C.js';
2
+ export { LocalSandbox, SandboxBackend, SandboxNotAvailableError, SandboxSecurityError, resolveSandbox, shellEscapePosix } from '../chunk-QGDPMM3C.js';
3
3
  import '../chunk-HKCKOAIO.js';
4
4
  import { TheokitAgentError } from '../chunk-TNFOU6SB.js';
5
5
  import { redactSecrets } from '../chunk-3OY6H3I7.js';
6
6
  import { execFileSync } from 'child_process';
7
- import { existsSync, mkdtempSync, writeFileSync, rmSync } from 'fs';
8
- import path, { dirname, join } from 'path';
7
+ import { existsSync, mkdtempSync, writeFileSync, statSync, realpathSync, rmSync } from 'fs';
8
+ import path, { dirname, join, resolve } from 'path';
9
9
  import { tmpdir } from 'os';
10
10
 
11
+ var KEPT_ROOTS_ALWAYS = ["/tmp"];
12
+ function isSameOrInside(outer, inner) {
13
+ const rel = path.relative(outer, inner);
14
+ return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
15
+ }
16
+ function resolveEntry(entry) {
17
+ if (!path.isAbsolute(entry)) {
18
+ throw new TypeError(`denyReadPaths: "${entry}" is not an absolute path`);
19
+ }
20
+ try {
21
+ return realpathSync(entry);
22
+ } catch (cause) {
23
+ throw new TypeError(`denyReadPaths: "${entry}" cannot be resolved: ${String(cause)}`);
24
+ }
25
+ }
26
+ function keptRoots(cwd) {
27
+ let real = cwd;
28
+ try {
29
+ real = realpathSync(cwd);
30
+ } catch {
31
+ }
32
+ return [.../* @__PURE__ */ new Set([cwd, real, ...KEPT_ROOTS_ALWAYS])];
33
+ }
34
+ function denyReadFlags(paths, policy) {
35
+ if (paths === void 0 || paths.length === 0) return [];
36
+ if (policy.mode === "danger-full-access") {
37
+ throw new TypeError(
38
+ "denyReadPaths cannot be honoured under danger-full-access: no sandbox is applied"
39
+ );
40
+ }
41
+ const roots = keptRoots(policy.cwd);
42
+ const resolved = /* @__PURE__ */ new Set();
43
+ for (const entry of paths) {
44
+ const target = resolveEntry(entry);
45
+ const covered = roots.find((root) => isSameOrInside(target, root));
46
+ if (covered !== void 0) {
47
+ throw new TypeError(
48
+ `denyReadPaths: "${entry}" would hide "${covered}", which the command needs`
49
+ );
50
+ }
51
+ resolved.add(target);
52
+ }
53
+ return [...resolved].flatMap(
54
+ (target) => statSync(target).isDirectory() ? ["--tmpfs", target] : ["--ro-bind", "/dev/null", target]
55
+ );
56
+ }
57
+ function refuseUnhonourableDenyRead(paths, mode, detect) {
58
+ if (paths === void 0 || paths.length === 0) return;
59
+ if (mode === "danger-full-access") denyReadFlags(paths, { mode, cwd: "/" });
60
+ const detection = detect();
61
+ if (!detection.ok) {
62
+ throw new SandboxNotAvailableError(
63
+ `denyReadPaths needs kernel confinement and it is unavailable (${detection.reason}); refusing to run unconfined`
64
+ );
65
+ }
66
+ }
67
+
68
+ // src/sandbox/bwrap.ts
11
69
  function pushWorkspaceBinds(argv, cwd, hasGit, gitDir) {
12
70
  for (const root of workspaceWriteRoots(cwd)) argv.push("--bind", root, root);
13
71
  if (hasGit) argv.push("--ro-bind", gitDir, gitDir);
@@ -26,8 +84,9 @@ function writableRootsFor(mode, cwd) {
26
84
  }
27
85
  }
28
86
  function buildBwrapArgv(mode, opts) {
29
- if (mode === "danger-full-access") return null;
30
87
  const cwd = path.resolve(opts.cwd);
88
+ const denyFlags = denyReadFlags(opts.denyReadPaths, { mode, cwd });
89
+ if (mode === "danger-full-access") return null;
31
90
  const gitDir = path.join(cwd, ".git");
32
91
  const hasGit = opts.gitDirExists ?? existsSync(gitDir);
33
92
  const argv = [
@@ -54,6 +113,7 @@ function buildBwrapArgv(mode, opts) {
54
113
  };
55
114
  for (const [k, v] of Object.entries(setenv)) argv.push("--setenv", k, v);
56
115
  if (mode === "workspace-write") pushWorkspaceBinds(argv, cwd, hasGit, gitDir);
116
+ argv.push(...denyFlags);
57
117
  argv.push("--chdir", cwd, "--");
58
118
  return argv;
59
119
  }
@@ -180,7 +240,7 @@ function buildSeccompFilter(opts) {
180
240
  const denyIdx = body.length - 1;
181
241
  push(RET_K, SECCOMP_RET_KILL_PROCESS);
182
242
  const killIdx = body.length - 1;
183
- const resolve = (i, t) => {
243
+ const resolve2 = (i, t) => {
184
244
  const abs = t === ALLOW ? allowIdx : t === DENY ? denyIdx : t === KILL ? killIdx : i + 1 + t;
185
245
  const off = abs - (i + 1);
186
246
  if (off < 0 || off > 255) throw new RangeError(`seccomp jump out of range at ${i}: ${off}`);
@@ -188,7 +248,7 @@ function buildSeccompFilter(opts) {
188
248
  };
189
249
  for (const [i, b] of body.entries()) {
190
250
  if (b.code === JEQ_K || b.code === JGE_K) {
191
- insns.push(jmp(b.code, b.k, resolve(i, b.jt), resolve(i, b.jf)));
251
+ insns.push(jmp(b.code, b.k, resolve2(i, b.jt), resolve2(i, b.jf)));
192
252
  } else {
193
253
  insns.push(stmt(b.code, b.k));
194
254
  }
@@ -202,15 +262,90 @@ function buildSeccompFilter(opts) {
202
262
  });
203
263
  return buf;
204
264
  }
265
+ function nonX64SeccompWarning(arch) {
266
+ return `[sandbox] seccomp syscall filter unsupported on ${arch} (x86_64 only in v1) \u2014 running without the filter; bwrap FS/network confinement still applies.`;
267
+ }
268
+ var warnedNonX64Program = false;
269
+ function seccompProgramForArch(arch, warn) {
270
+ if (arch !== "x64") {
271
+ if (!warnedNonX64Program) {
272
+ warnedNonX64Program = true;
273
+ warn(nonX64SeccompWarning(arch));
274
+ }
275
+ return void 0;
276
+ }
277
+ return buildSeccompFilter({ networkRestricted: true });
278
+ }
279
+ var memoizedProgram;
280
+ function restrictedSeccompProgram(warn) {
281
+ if (memoizedProgram === void 0)
282
+ memoizedProgram = seccompProgramForArch(process.arch, warn) ?? null;
283
+ return memoizedProgram ?? void 0;
284
+ }
285
+ function octalPrintfArg(program) {
286
+ let out = "";
287
+ for (const byte of program) out += `\\${byte.toString(8).padStart(3, "0")}`;
288
+ return out;
289
+ }
290
+ function assertSeccompProgramShape(program) {
291
+ if (program.length === 0 || program.length % 8 !== 0) {
292
+ throw new TypeError(
293
+ `seccompProgram must be a positive multiple of 8 bytes, got ${program.length}`
294
+ );
295
+ }
296
+ }
297
+ var PIPE_SCRIPT = '{ p=$1; shift; printf "$p" | exec "$@" 3<&0 0<&4 4<&-; } 4<&0';
298
+ function wrapWithSeccompProgram(bwrapArgv, command, program) {
299
+ assertSeccompProgramShape(program);
300
+ const words = [octalPrintfArg(program), ...bwrapArgv, "--seccomp", "3", "--", "/bin/sh", "-c"];
301
+ return `exec /bin/sh -c ${shellEscapePosix(PIPE_SCRIPT)} sh ${[...words, command].map(shellEscapePosix).join(" ")}`;
302
+ }
303
+ var programsWritten = /* @__PURE__ */ new Map();
304
+ function rememberSeccompFile(path3, program) {
305
+ programsWritten.set(resolve(path3), Buffer.from(program));
306
+ }
307
+ function removeDirOnExit(dir) {
308
+ const cleanup = () => rmSync(dir, { recursive: true, force: true });
309
+ process.once("exit", cleanup);
310
+ for (const signal of ["SIGINT", "SIGTERM"]) {
311
+ process.prependOnceListener(signal, () => {
312
+ cleanup();
313
+ if (process.listenerCount(signal) === 0) process.kill(process.pid, signal);
314
+ });
315
+ }
316
+ }
317
+ function wrapWithSeccompPath(bwrapArgv, policy, command, seccompPath) {
318
+ const program = programsWritten.get(resolve(seccompPath));
319
+ const bind = program === void 0 ? "--ro-bind" : "--ro-bind-try";
320
+ const flags = [
321
+ ...bwrapArgv.slice(0, -3),
322
+ ...readOnlyBindForSeccompPath(policy.mode, policy.cwd, seccompPath, bind),
323
+ ...bwrapArgv.slice(-3, -1)
324
+ ];
325
+ if (program !== void 0) return wrapWithSeccompProgram(flags, command, program);
326
+ return `${[...flags, "--seccomp", "3", "--"].map(shellEscapePosix).join(" ")} /bin/sh -c ${shellEscapePosix(command)} 3< ${shellEscapePosix(seccompPath)}`;
327
+ }
328
+ function readOnlyBindForSeccompPath(mode, cwd, seccompPath, bind) {
329
+ const file = resolve(seccompPath);
330
+ const dir = dirname(file);
331
+ const roots = writableRootsFor(mode, resolve(cwd)) ?? [];
332
+ const covers = (root) => dir === "/" || root === dir || root.startsWith(`${dir}/`);
333
+ const target = roots.some(covers) ? file : dir;
334
+ return [bind, target, target];
335
+ }
205
336
 
206
337
  // src/sandbox/linux-sandbox.ts
207
338
  function wrapCommandForSandbox(mode, opts, command) {
208
- const argv = buildBwrapArgv(mode, { cwd: opts.cwd, network: opts.network, env: opts.env });
339
+ const argv = buildBwrapArgv(mode, opts);
209
340
  if (argv === null) return null;
210
341
  const bin = opts.bin ?? "bwrap";
211
- const seccompArgv = opts.seccompPath !== void 0 ? ["--seccomp", "3"] : [];
212
- const base = `${shellEscapePosix(bin)} ${[...argv.slice(0, -1), ...seccompArgv, "--"].map(shellEscapePosix).join(" ")} /bin/sh -c ${shellEscapePosix(command)}`;
213
- return opts.seccompPath !== void 0 ? `${base} 3< ${shellEscapePosix(opts.seccompPath)}` : base;
342
+ if (opts.seccompProgram !== void 0) {
343
+ return wrapWithSeccompProgram([bin, ...argv.slice(0, -1)], command, opts.seccompProgram);
344
+ }
345
+ if (opts.seccompPath === void 0) {
346
+ return `${[bin, ...argv].map(shellEscapePosix).join(" ")} /bin/sh -c ${shellEscapePosix(command)}`;
347
+ }
348
+ return wrapWithSeccompPath([bin, ...argv], { mode, cwd: opts.cwd }, command, opts.seccompPath);
214
349
  }
215
350
  var ENV_ALLOWLIST = [
216
351
  "PATH",
@@ -237,17 +372,29 @@ var LinuxSandbox = class extends LocalSandbox {
237
372
  cwd;
238
373
  bin;
239
374
  env;
240
- /** M63 — path to the cBPF seccomp program written host-side; passed to `bwrap --seccomp 3` via a
241
- * shell redirect. `undefined` when the network is unrestricted OR generation failed (honest fallback). */
242
- seccompPath;
375
+ /** B-600 — the cBPF seccomp program, piped to `bwrap --seccomp 3` from memory (never a file a
376
+ * confined command could replace). `undefined` when the network is unrestricted or the arch is not
377
+ * x86_64 (honest fallback). */
378
+ seccompProgram;
379
+ denyReadPaths;
380
+ /**
381
+ * `"none"` exactly when the wrap passes `--unshare-net` (see `buildBwrapArgv`): a confined mode and
382
+ * `network` not set. With `network: true`, or under `danger-full-access` where nothing is wrapped,
383
+ * the command reaches whatever the host does.
384
+ */
385
+ networkPolicy;
386
+ /** `denyReadPaths`: see `BwrapArgvOptions`; a list that cannot be honoured throws `TypeError` here. */
243
387
  constructor(config, opts) {
244
388
  super(config);
245
389
  this.mode = opts.mode;
246
390
  this.network = opts.network ?? false;
391
+ this.networkPolicy = this.network || this.mode === "danger-full-access" ? { mode: "unrestricted" } : { mode: "none" };
247
392
  this.cwd = config.workDir ?? process.cwd();
248
393
  this.bin = opts.bin ?? "bwrap";
249
394
  this.env = opts.env ?? allowlistedEnv();
250
- this.seccompPath = seccompPathForNetwork(this.network);
395
+ this.seccompProgram = seccompProgramForNetwork(this.network);
396
+ this.denyReadPaths = opts.denyReadPaths;
397
+ denyReadFlags(this.denyReadPaths, { mode: this.mode, cwd: this.cwd });
251
398
  }
252
399
  /** Extracted for test visibility — delegates to the pure `wrapCommandForSandbox` (M57, single wrap SoT). */
253
400
  wrapCommand(command) {
@@ -258,7 +405,8 @@ var LinuxSandbox = class extends LocalSandbox {
258
405
  network: this.network,
259
406
  env: this.env,
260
407
  bin: this.bin,
261
- seccompPath: this.seccompPath
408
+ seccompProgram: this.seccompProgram,
409
+ denyReadPaths: this.denyReadPaths
262
410
  },
263
411
  command
264
412
  );
@@ -276,9 +424,9 @@ var LinuxSandbox = class extends LocalSandbox {
276
424
  * policy as everything else — if bwrap denies the path, the write fails, as it should. The content
277
425
  * goes over stdin (not argv) because argv has a size limit and file content does not.
278
426
  */
279
- async uploadFile(path2, content) {
280
- if (this.mode === "danger-full-access") return super.uploadFile(path2, content);
281
- const target = path2.startsWith("/") ? path2 : `${this.cwd}/${path2}`;
427
+ async uploadFile(path3, content) {
428
+ if (this.mode === "danger-full-access") return super.uploadFile(path3, content);
429
+ const target = path3.startsWith("/") ? path3 : `${this.cwd}/${path3}`;
282
430
  const b64 = Buffer.from(content).toString("base64");
283
431
  const r = await this.execute(
284
432
  `mkdir -p ${shellEscapePosix(dirname(target))} && printf %s ${shellEscapePosix(b64)} | base64 -d > ${shellEscapePosix(target)}`
@@ -300,21 +448,18 @@ function seccompPathForArch(arch, warn) {
300
448
  if (arch !== "x64") {
301
449
  if (!warnedNonX64) {
302
450
  warnedNonX64 = true;
303
- warn(
304
- `[sandbox] seccomp syscall filter unsupported on ${arch} (x86_64 only in v1) \u2014 running without the filter; bwrap FS/network confinement still applies.`
305
- );
451
+ warn(nonX64SeccompWarning(arch));
306
452
  }
307
453
  return void 0;
308
454
  }
309
455
  try {
310
456
  const dir = mkdtempSync(join(tmpdir(), "ab-seccomp-"));
311
- const path2 = join(dir, "filter.bpf");
312
- writeFileSync(path2, buildSeccompFilter({ networkRestricted: true }));
313
- const cleanup = () => rmSync(dir, { recursive: true, force: true });
314
- process.once("exit", cleanup);
315
- process.once("SIGINT", cleanup);
316
- process.once("SIGTERM", cleanup);
317
- return path2;
457
+ const path3 = join(dir, "filter.bpf");
458
+ const program = buildSeccompFilter({ networkRestricted: true });
459
+ writeFileSync(path3, program);
460
+ rememberSeccompFile(path3, program);
461
+ removeDirOnExit(dir);
462
+ return path3;
318
463
  } catch (err) {
319
464
  warn(
320
465
  `[sandbox] seccomp filter unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 running without syscall filter (bwrap FS/network confinement still applies).`
@@ -325,9 +470,9 @@ function seccompPathForArch(arch, warn) {
325
470
  var seccompFilterPath;
326
471
  function restrictedSeccompPath() {
327
472
  if (seccompFilterPath !== void 0) return seccompFilterPath ?? void 0;
328
- const path2 = seccompPathForArch(process.arch, (m) => console.warn(redactSecrets(m)));
329
- seccompFilterPath = path2 ?? null;
330
- return path2;
473
+ const path3 = seccompPathForArch(process.arch, (m) => console.warn(redactSecrets(m)));
474
+ seccompFilterPath = path3 ?? null;
475
+ return path3;
331
476
  }
332
477
  var warnedUnavailable = false;
333
478
  function __resetSandboxWarnLatchForTests() {
@@ -345,6 +490,7 @@ function resolveSandboxPosture(opts) {
345
490
  }
346
491
  function createSandboxBackend(opts) {
347
492
  const config = { workDir: opts.workDir, timeoutMs: opts.timeoutMs };
493
+ refuseUnhonourableDenyRead(opts.denyReadPaths, opts.mode, opts.detect ?? detectBwrapMemoized);
348
494
  if (opts.mode === "danger-full-access") return new LocalSandbox(config);
349
495
  const detection = (opts.detect ?? detectBwrapMemoized)();
350
496
  if (!detection.ok) {
@@ -357,16 +503,17 @@ function createSandboxBackend(opts) {
357
503
  }
358
504
  return new LocalSandbox(config);
359
505
  }
360
- return new LinuxSandbox(config, { mode: opts.mode, network: opts.network, bin: detection.bin });
506
+ return new LinuxSandbox(config, { ...opts, bin: detection.bin });
361
507
  }
362
508
  var interactiveWarned = false;
363
509
  function __resetInteractiveWarnLatchForTests() {
364
510
  interactiveWarned = false;
365
511
  }
366
- function seccompPathForNetwork(networkOpen) {
367
- return networkOpen ? void 0 : restrictedSeccompPath();
512
+ function seccompProgramForNetwork(networkOpen) {
513
+ return networkOpen ? void 0 : restrictedSeccompProgram((m) => console.warn(redactSecrets(m)));
368
514
  }
369
515
  function decideConfinement(opts) {
516
+ refuseUnhonourableDenyRead(opts.denyReadPaths, opts.mode, opts.detect ?? detectBwrapMemoized);
370
517
  if (opts.mode === "danger-full-access") return null;
371
518
  const detection = (opts.detect ?? detectBwrapMemoized)();
372
519
  if (detection.ok) return detection.bin;
@@ -390,7 +537,8 @@ function interactiveWrapCommand(opts) {
390
537
  network: opts.network ?? false,
391
538
  env: allowlistedEnv(),
392
539
  bin,
393
- seccompPath: seccompPathForNetwork(opts.network ?? false)
540
+ seccompProgram: seccompProgramForNetwork(opts.network ?? false),
541
+ denyReadPaths: opts.denyReadPaths
394
542
  },
395
543
  command
396
544
  );