@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.
- package/CHANGELOG.md +68 -0
- package/dist/{agent-IG7BP6GN.js → agent-5DSDDH7K.js} +5 -5
- package/dist/{agent-IG7BP6GN.js.map → agent-5DSDDH7K.js.map} +1 -1
- package/dist/{agent-CVzDy_Oj.d.ts → agent-DSMuwADp.d.ts} +9 -2
- package/dist/{agent-BVKIUP7F.cjs → agent-WOMRT3KX.cjs} +6 -6
- package/dist/{agent-BVKIUP7F.cjs.map → agent-WOMRT3KX.cjs.map} +1 -1
- package/dist/{agent-Cn0sphpA.d.cts → agent-iW5kPpfT.d.cts} +9 -2
- package/dist/{chunk-XJ4C4NFX.js → chunk-2PRGRYEQ.js} +61 -47
- package/dist/chunk-2PRGRYEQ.js.map +1 -0
- package/dist/{chunk-HN4IKB6X.cjs → chunk-2XWAYCFM.cjs} +15 -13
- package/dist/chunk-2XWAYCFM.cjs.map +1 -0
- package/dist/{chunk-VVGFZQZC.js → chunk-3LMVJTNJ.js} +9 -5
- package/dist/chunk-3LMVJTNJ.js.map +1 -0
- package/dist/{chunk-IO4RI5ZJ.cjs → chunk-47EACDOC.cjs} +4 -4
- package/dist/{chunk-IO4RI5ZJ.cjs.map → chunk-47EACDOC.cjs.map} +1 -1
- package/dist/{chunk-LSWHDOCL.cjs → chunk-4UYHP6NF.cjs} +64 -48
- package/dist/chunk-4UYHP6NF.cjs.map +1 -0
- package/dist/{chunk-ZLFFDPXC.js → chunk-73IITAF7.js} +36 -14
- package/dist/chunk-73IITAF7.js.map +1 -0
- package/dist/{chunk-XRPMZ7TO.js → chunk-CYWOJA6B.js} +6 -4
- package/dist/chunk-CYWOJA6B.js.map +1 -0
- package/dist/{chunk-AQW54OWQ.js → chunk-DFBWYETS.js} +5 -3
- package/dist/chunk-DFBWYETS.js.map +1 -0
- package/dist/{chunk-YOVZMN4P.cjs → chunk-DVP3YMDA.cjs} +3 -3
- package/dist/{chunk-YOVZMN4P.cjs.map → chunk-DVP3YMDA.cjs.map} +1 -1
- package/dist/{chunk-BRWI4HLK.cjs → chunk-FLDHYF5C.cjs} +13 -3
- package/dist/chunk-FLDHYF5C.cjs.map +1 -0
- package/dist/{chunk-BJ7BPLQK.js → chunk-JX4LB6XO.js} +124 -13
- package/dist/chunk-JX4LB6XO.js.map +1 -0
- package/dist/{chunk-Q6WT5535.cjs → chunk-KL7ZUMK3.cjs} +161 -50
- package/dist/chunk-KL7ZUMK3.cjs.map +1 -0
- package/dist/{chunk-FEAWEBWN.cjs → chunk-PDOXYXWX.cjs} +6 -4
- package/dist/chunk-PDOXYXWX.cjs.map +1 -0
- package/dist/{chunk-EEK7S77K.js → chunk-QGDPMM3C.js} +13 -3
- package/dist/chunk-QGDPMM3C.js.map +1 -0
- package/dist/{chunk-ZWLFHSON.cjs → chunk-R35ZJAYT.cjs} +38 -15
- package/dist/chunk-R35ZJAYT.cjs.map +1 -0
- package/dist/{chunk-4YD2WI57.cjs → chunk-R427EOZE.cjs} +19 -15
- package/dist/chunk-R427EOZE.cjs.map +1 -0
- package/dist/{chunk-TLVI2OQK.cjs → chunk-SETHRLQS.cjs} +18 -2
- package/dist/chunk-SETHRLQS.cjs.map +1 -0
- package/dist/{chunk-BO3PV3OP.js → chunk-TDED5XES.js} +18 -3
- package/dist/chunk-TDED5XES.js.map +1 -0
- package/dist/{chunk-4GUFNDZR.js → chunk-XOYNB3YN.js} +3 -3
- package/dist/{chunk-4GUFNDZR.js.map → chunk-XOYNB3YN.js.map} +1 -1
- package/dist/{chunk-NJBJ3CUG.js → chunk-ZTP6ZACR.js} +3 -3
- package/dist/{chunk-NJBJ3CUG.js.map → chunk-ZTP6ZACR.js.map} +1 -1
- package/dist/{compact-session-3U2JYTVG.js → compact-session-5HMX6KYT.js} +3 -3
- package/dist/{compact-session-3U2JYTVG.js.map → compact-session-5HMX6KYT.js.map} +1 -1
- package/dist/{compact-session-NM56BREJ.cjs → compact-session-B7P6EU3Z.cjs} +12 -12
- package/dist/{compact-session-NM56BREJ.cjs.map → compact-session-B7P6EU3Z.cjs.map} +1 -1
- package/dist/{cron-BWDYetbq.d.cts → cron-BvxrLW5J.d.cts} +1 -1
- package/dist/{cron-CHn-F0fC.d.ts → cron-DdKzwJqK.d.ts} +1 -1
- package/dist/cron.cjs +5 -5
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +4 -4
- package/dist/eval.cjs +9 -9
- package/dist/eval.js +4 -4
- package/dist/{executor-HKHT4CWS.cjs → executor-5QL5AXIZ.cjs} +18 -15
- package/dist/executor-5QL5AXIZ.cjs.map +1 -0
- package/dist/{executor-3D2UDJHW.js → executor-THUXNAFR.js} +6 -3
- package/dist/executor-THUXNAFR.js.map +1 -0
- package/dist/generate-object-A5F576IT.cjs +20 -0
- package/dist/{generate-object-XBWD2PU7.cjs.map → generate-object-A5F576IT.cjs.map} +1 -1
- package/dist/{generate-object-S7MNVF2V.js → generate-object-TBDOBBYW.js} +4 -4
- package/dist/{generate-object-S7MNVF2V.js.map → generate-object-TBDOBBYW.js.map} +1 -1
- package/dist/generate-object.d.ts +14 -1
- package/dist/index.cjs +43 -43
- package/dist/index.d.cts +30 -4
- package/dist/index.d.ts +30 -4
- package/dist/index.js +13 -13
- package/dist/{inject-session-THABTKJY.js → inject-session-75L3NCNL.js} +3 -3
- package/dist/{inject-session-THABTKJY.js.map → inject-session-75L3NCNL.js.map} +1 -1
- package/dist/{inject-session-JVTZNQF6.cjs → inject-session-WOH7TPDX.cjs} +4 -4
- package/dist/{inject-session-JVTZNQF6.cjs.map → inject-session-WOH7TPDX.cjs.map} +1 -1
- package/dist/internal/providers/discovery.d.ts +2 -2
- package/dist/internal/providers/trust-gate.d.ts +35 -0
- package/dist/internal/runtime/plugin-loader/manifest-entry-import.d.ts +17 -0
- package/dist/internal/runtime/plugin-loader/workspace-plugin-trust.d.ts +16 -0
- package/dist/internal/structured-output-helpers.d.ts +5 -2
- package/dist/sandbox/bwrap.d.cts +10 -8
- package/dist/sandbox/bwrap.d.ts +10 -8
- package/dist/sandbox/deny-read.d.cts +24 -0
- package/dist/sandbox/deny-read.d.ts +24 -0
- package/dist/sandbox/index.cjs +198 -46
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.d.cts +2 -1
- package/dist/sandbox/index.d.ts +2 -1
- package/dist/sandbox/index.js +184 -36
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/linux-sandbox.d.cts +40 -5
- package/dist/sandbox/linux-sandbox.d.ts +40 -5
- package/dist/sandbox/local-sandbox.d.cts +3 -1
- package/dist/sandbox/local-sandbox.d.ts +3 -1
- package/dist/sandbox/seccomp-delivery.d.cts +49 -0
- package/dist/sandbox/seccomp-delivery.d.ts +49 -0
- package/dist/sandbox/shell-escape.d.cts +14 -2
- package/dist/sandbox/shell-escape.d.ts +14 -2
- package/dist/sandbox/types.d.cts +45 -0
- package/dist/sandbox/types.d.ts +45 -0
- package/dist/stream-object-AS4YYM4B.cjs +20 -0
- package/dist/{stream-object-TEEK3CAX.cjs.map → stream-object-AS4YYM4B.cjs.map} +1 -1
- package/dist/stream-object-EKM4WGTI.js +7 -0
- package/dist/{stream-object-R6SMYV4R.js.map → stream-object-EKM4WGTI.js.map} +1 -1
- package/dist/stream-object.d.ts +14 -1
- package/dist/subagents-loader.d.cts +1 -1
- package/dist/subagents-loader.d.ts +1 -1
- package/dist/types/agent.d.ts +8 -1
- package/dist/workflow-as-tool.d.ts +39 -5
- package/dist/workflow-errors.d.ts +16 -0
- package/dist/workflow.cjs +31 -23
- package/dist/workflow.d.cts +54 -4
- package/dist/workflow.d.ts +54 -4
- package/dist/workflow.js +2 -2
- package/docs/error-codes.md +16 -13
- package/docs/harness-capability-map.md +51 -5
- package/package.json +1 -1
- package/dist/chunk-4YD2WI57.cjs.map +0 -1
- package/dist/chunk-AQW54OWQ.js.map +0 -1
- package/dist/chunk-BJ7BPLQK.js.map +0 -1
- package/dist/chunk-BO3PV3OP.js.map +0 -1
- package/dist/chunk-BRWI4HLK.cjs.map +0 -1
- package/dist/chunk-EEK7S77K.js.map +0 -1
- package/dist/chunk-FEAWEBWN.cjs.map +0 -1
- package/dist/chunk-HN4IKB6X.cjs.map +0 -1
- package/dist/chunk-LSWHDOCL.cjs.map +0 -1
- package/dist/chunk-Q6WT5535.cjs.map +0 -1
- package/dist/chunk-TLVI2OQK.cjs.map +0 -1
- package/dist/chunk-VVGFZQZC.js.map +0 -1
- package/dist/chunk-XJ4C4NFX.js.map +0 -1
- package/dist/chunk-XRPMZ7TO.js.map +0 -1
- package/dist/chunk-ZLFFDPXC.js.map +0 -1
- package/dist/chunk-ZWLFHSON.cjs.map +0 -1
- package/dist/executor-3D2UDJHW.js.map +0 -1
- package/dist/executor-HKHT4CWS.cjs.map +0 -1
- package/dist/generate-object-XBWD2PU7.cjs +0 -20
- package/dist/stream-object-R6SMYV4R.js +0 -7
- package/dist/stream-object-TEEK3CAX.cjs +0 -20
package/dist/sandbox/index.js
CHANGED
|
@@ -1,13 +1,71 @@
|
|
|
1
|
-
import { shellEscapePosix, LocalSandbox } from '../chunk-
|
|
2
|
-
export { LocalSandbox, SandboxBackend, SandboxNotAvailableError, SandboxSecurityError, resolveSandbox } from '../chunk-
|
|
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
|
|
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,
|
|
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,
|
|
339
|
+
const argv = buildBwrapArgv(mode, opts);
|
|
209
340
|
if (argv === null) return null;
|
|
210
341
|
const bin = opts.bin ?? "bwrap";
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
/**
|
|
241
|
-
*
|
|
242
|
-
|
|
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.
|
|
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
|
-
|
|
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(
|
|
280
|
-
if (this.mode === "danger-full-access") return super.uploadFile(
|
|
281
|
-
const target =
|
|
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
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
|
329
|
-
seccompFilterPath =
|
|
330
|
-
return
|
|
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, {
|
|
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
|
|
367
|
-
return networkOpen ? void 0 :
|
|
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
|
-
|
|
540
|
+
seccompProgram: seccompProgramForNetwork(opts.network ?? false),
|
|
541
|
+
denyReadPaths: opts.denyReadPaths
|
|
394
542
|
},
|
|
395
543
|
command
|
|
396
544
|
);
|