opencode-swarm 7.144.4 → 7.144.6
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/.opencode/skills/swarm-pr-review/references/prompt-templates.md +2 -2
- package/dist/background/workspace-snapshot.d.ts +7 -0
- package/dist/cli/{capability-probe-f1paszww.js → capability-probe-976tt4ba.js} +6 -2
- package/dist/cli/{config-doctor-rw9zrjk6.js → config-doctor-4chz0b95.js} +2 -2
- package/dist/cli/{core-zjx9aqaf.js → core-p04nvknr.js} +4 -3
- package/dist/cli/{curation-policy-0wbrh11c.js → curation-policy-a511r0qz.js} +4 -4
- package/dist/cli/{curator-drift-2jbjv03a.js → curator-drift-ckjm272w.js} +2 -2
- package/dist/cli/curator-llm-factory-vc1mrc3r.js +63 -0
- package/dist/cli/{curator-g54a7wv0.js → curator-sxeh36gw.js} +33 -32
- package/dist/cli/{dispatch-1y1rnv1h.js → dispatch-ndxbsk98.js} +2 -2
- package/dist/cli/{evidence-summary-service-fnr5y54e.js → evidence-summary-service-spyxcgsx.js} +13 -12
- package/dist/cli/{gate-evidence-2xt1x07r.js → gate-evidence-nz0bwa15.js} +7 -6
- package/dist/cli/guardrail-explain-ass47kn8.js +64 -0
- package/dist/cli/{guardrail-log-5w4b9zrw.js → guardrail-log-fyzd55fp.js} +4 -4
- package/dist/cli/{hive-promoter-x63ehffd.js → hive-promoter-k8gtah3n.js} +33 -32
- package/dist/cli/{index-h98t1m88.js → index-01nhedm7.js} +29 -1
- package/dist/cli/{index-q4ed1jk7.js → index-42ezdzam.js} +1994 -1333
- package/dist/cli/{index-y8j8ehc8.js → index-68mqwvf5.js} +11 -5
- package/dist/cli/{index-1csyxv0f.js → index-6z5jtf7d.js} +2 -2
- package/dist/cli/{index-2m7mavaz.js → index-7zehmnv1.js} +2 -2
- package/dist/cli/index-9e6fdz2h.js +282 -0
- package/dist/cli/{index-mazgg5s2.js → index-9s8drsf9.js} +1 -1
- package/dist/cli/{index-b6e016tv.js → index-abtrcs16.js} +1 -1
- package/dist/cli/{index-8fwhhayc.js → index-b44qqqt2.js} +27 -18
- package/dist/cli/{index-yts89pqg.js → index-bac12jpv.js} +4 -4
- package/dist/cli/{index-psvxq93b.js → index-ckq719fr.js} +2 -2
- package/dist/cli/{index-k3cxyk66.js → index-cwtpqm5f.js} +1 -1
- package/dist/cli/{index-d12jd5mn.js → index-dj8cah6s.js} +1 -1
- package/dist/cli/{index-pw83zgny.js → index-dvybg11w.js} +3 -3
- package/dist/cli/{index-03pv47h2.js → index-ec1kywxg.js} +6 -6
- package/dist/cli/{index-74hpm6sh.js → index-f36ybbsv.js} +12 -6
- package/dist/cli/{index-az8etqpp.js → index-fgdhf6a5.js} +298 -1179
- package/dist/cli/{index-rn0eq85g.js → index-fv0s19g9.js} +1 -1
- package/dist/cli/{index-ywn7vtxp.js → index-h1p08s3n.js} +1 -1
- package/dist/cli/{index-nckg4gxb.js → index-h5krb653.js} +15 -4
- package/dist/cli/{index-bt9aa01f.js → index-hkdgkkhb.js} +1 -1
- package/dist/cli/{index-p7cm3gtj.js → index-jqvsh0g3.js} +35 -34
- package/dist/cli/{index-x6tp0hfr.js → index-n06653nr.js} +5 -5
- package/dist/cli/{index-jabkn643.js → index-n4hwcsbd.js} +2 -2
- package/dist/cli/{index-z6v7kwpa.js → index-q6bhmyxb.js} +1 -1
- package/dist/cli/{index-cz25e8xp.js → index-sqe3nqh5.js} +166 -34
- package/dist/cli/{index-q67jb94n.js → index-sswzhcqb.js} +1 -1
- package/dist/cli/{index-8j0va7jp.js → index-tq89td7b.js} +43 -22
- package/dist/cli/{index-dty5qgk2.js → index-vdha477y.js} +1 -1
- package/dist/cli/{index-zb0xcz9t.js → index-vngs0meh.js} +3 -3
- package/dist/cli/{index-fqcjragy.js → index-wknz5c8q.js} +1 -1
- package/dist/cli/{index-9qq7c18c.js → index-ytzz6pq1.js} +36 -1
- package/dist/cli/{index-4w5qdbk7.js → index-zde2mkmg.js} +6 -6
- package/dist/cli/{index-4nt52yr9.js → index-zj6t9zgx.js} +173 -25
- package/dist/cli/{index-btmsqv7p.js → index-zxr5r9b7.js} +5 -4
- package/dist/cli/index-zy7f84cs.js +1210 -0
- package/dist/cli/index.d.ts +11 -1
- package/dist/cli/index.js +61 -39
- package/dist/cli/{knowledge-escalator-ypg14d5r.js → knowledge-escalator-yaxzz0k5.js} +12 -11
- package/dist/cli/{knowledge-events-nkrym4wb.js → knowledge-events-rgcwewpn.js} +10 -9
- package/dist/cli/{knowledge-link-e4qgqmpx.js → knowledge-link-4cg4776a.js} +3 -3
- package/dist/cli/{knowledge-store-vh3nhtg2.js → knowledge-store-qf8t25sw.js} +4 -4
- package/dist/cli/{knowledge-validator-jrxvexv6.js → knowledge-validator-dx6zzcdf.js} +6 -6
- package/dist/cli/{pending-delegations-pw79c8ds.js → pending-delegations-9h1jmtw1.js} +3 -3
- package/dist/cli/{pr-subscriptions-fk628bhc.js → pr-subscriptions-8pg34pev.js} +3 -3
- package/dist/cli/{runner-b02sz2vx.js → runner-cqecp1na.js} +4 -4
- package/dist/cli/{scan-cursor-fp7w5jmc.js → scan-cursor-pbcaj8hj.js} +7 -5
- package/dist/cli/{schema-rptwqbm4.js → schema-tzcjwe8j.js} +3 -1
- package/dist/cli/{scope-persistence-0bkaxawa.js → scope-persistence-mjg4we75.js} +7 -6
- package/dist/cli/{skill-generator-nh8b4gjv.js → skill-generator-7jrzbaej.js} +14 -13
- package/dist/cli/{workspace-snapshot-w3tg4ne5.js → workspace-snapshot-d89zm6wm.js} +5 -2
- package/dist/cli/{worktree-collision-ownership-hqd9ypsz.js → worktree-collision-ownership-vy0kxa98.js} +26 -19
- package/dist/cli/{worktree-isolation-canf3rj8.js → worktree-isolation-awpkp0yh.js} +33 -32
- package/dist/cli/{worktree-provisioning-owner-g24xd417.js → worktree-provisioning-owner-zzkjycp1.js} +3 -3
- package/dist/commands/ci-simulate.d.ts +2 -0
- package/dist/config/cache-paths.d.ts +57 -0
- package/dist/config/evidence-schema.d.ts +3 -3
- package/dist/config/schema.d.ts +9 -0
- package/dist/git/branch.d.ts +2 -0
- package/dist/git/pr.d.ts +2 -0
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +7 -0
- package/dist/hooks/diff-scope.d.ts +7 -0
- package/dist/hooks/review-receipt-scope.d.ts +7 -0
- package/dist/hooks/reviewer-scope-lifecycle.d.ts +9 -0
- package/dist/hooks/semantic-diff-injection.d.ts +8 -0
- package/dist/index.js +599 -589
- package/dist/mutation/engine.d.ts +11 -0
- package/dist/review/diff-source.d.ts +2 -0
- package/dist/sandbox/capability-probe.d.ts +22 -0
- package/dist/sandbox/executor.d.ts +15 -0
- package/dist/sandbox/linux/bubblewrap-executor.d.ts +6 -0
- package/dist/sandbox/macos/sandbox-exec-executor.d.ts +41 -0
- package/dist/tools/checkpoint.d.ts +11 -0
- package/dist/tools/complexity-hotspots.d.ts +15 -0
- package/dist/tools/diff-summary.d.ts +12 -0
- package/dist/tools/dispatch-lanes.d.ts +8 -0
- package/dist/tools/gh-evidence.d.ts +17 -1
- package/dist/tools/knowledge-receipt.d.ts +1 -1
- package/dist/tools/pkg-audit.d.ts +13 -0
- package/dist/tools/prepare-pr-workflow-checkout.d.ts +1 -0
- package/dist/utils/bun-compat.d.ts +80 -3
- package/dist/utils/git-binary-missing-error.d.ts +80 -2
- package/dist/utils/git-executable.d.ts +179 -0
- package/dist/utils/gitignore-warning.d.ts +10 -0
- package/dist/workflow/coder-settlement.d.ts +18 -0
- package/dist/worktree/core.d.ts +8 -0
- package/dist/worktree/merge.d.ts +33 -0
- package/package.json +3 -2
- package/dist/cli/curator-llm-factory-xgb4pxmm.js +0 -62
- package/dist/cli/guardrail-explain-6wcgr9tz.js +0 -63
- package/dist/cli/index-q1exe2b3.js +0 -256
|
@@ -0,0 +1,1210 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
init_logger,
|
|
4
|
+
warn
|
|
5
|
+
} from "./index-zgwm4ryv.js";
|
|
6
|
+
import {
|
|
7
|
+
__esm,
|
|
8
|
+
__export,
|
|
9
|
+
__require,
|
|
10
|
+
__toCommonJS
|
|
11
|
+
} from "./index-a76rekgs.js";
|
|
12
|
+
|
|
13
|
+
// src/sandbox/executors/bubblewrap.ts
|
|
14
|
+
var exports_bubblewrap = {};
|
|
15
|
+
__export(exports_bubblewrap, {
|
|
16
|
+
BubblewrapSandboxExecutor: () => BubblewrapSandboxExecutor
|
|
17
|
+
});
|
|
18
|
+
var init_bubblewrap = __esm(() => {
|
|
19
|
+
init_bubblewrap_executor();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// src/sandbox/macos/sandbox-exec-executor.ts
|
|
23
|
+
import { spawnSync } from "child_process";
|
|
24
|
+
import { existsSync, mkdtempSync, writeFileSync } from "fs";
|
|
25
|
+
import * as os from "os";
|
|
26
|
+
import * as path from "path";
|
|
27
|
+
function resolveBinary(absolutePath, bareName) {
|
|
28
|
+
try {
|
|
29
|
+
if (_internals.exists(absolutePath)) {
|
|
30
|
+
return absolutePath;
|
|
31
|
+
}
|
|
32
|
+
} catch {}
|
|
33
|
+
return bareName;
|
|
34
|
+
}
|
|
35
|
+
function resolveSandboxExecBinary() {
|
|
36
|
+
return resolveBinary(SANDBOX_EXEC_ABSOLUTE, "sandbox-exec");
|
|
37
|
+
}
|
|
38
|
+
function resolveProbeTargetBinary() {
|
|
39
|
+
return resolveBinary(TRUE_ABSOLUTE, "true");
|
|
40
|
+
}
|
|
41
|
+
function buildProbeProfile(tempDir) {
|
|
42
|
+
return `(version 1)
|
|
43
|
+
(allow default)
|
|
44
|
+
(deny file-write*)
|
|
45
|
+
(allow file-write* (subpath "${sbplEscapePath(tempDir)}"))
|
|
46
|
+
(setenv SWARM_SANDBOX_PROBE "1")
|
|
47
|
+
(unsetenv SWARM_SANDBOX_PROBE)`;
|
|
48
|
+
}
|
|
49
|
+
function probeSandboxExec() {
|
|
50
|
+
try {
|
|
51
|
+
const binary = resolveSandboxExecBinary();
|
|
52
|
+
const target = resolveProbeTargetBinary();
|
|
53
|
+
const profile = buildProbeProfile(os.tmpdir());
|
|
54
|
+
const result = _internals.spawnSync(binary, ["-p", profile, target], {
|
|
55
|
+
windowsHide: true,
|
|
56
|
+
encoding: "utf-8",
|
|
57
|
+
timeout: 5000,
|
|
58
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
59
|
+
});
|
|
60
|
+
if (result.error) {
|
|
61
|
+
const code = result.error.code;
|
|
62
|
+
if (code && SANDBOX_UNAVAILABLE_CODES.has(code)) {
|
|
63
|
+
warn(`Sandbox disabled: sandbox-exec error (${code}). Falling through to tool-layer enforcement.`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
warn(`Sandbox disabled: spawn error (${result.error.message}). Falling through to tool-layer enforcement.`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return result.status === 0;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
72
|
+
warn(`Sandbox disabled: probe threw (${message}). Falling through to tool-layer enforcement.`);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function probeSandboxExecMemoized() {
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
if (_probeMemo && now < _probeMemo.expiresAt) {
|
|
79
|
+
return _probeMemo.result;
|
|
80
|
+
}
|
|
81
|
+
const result = _internals.probeSandboxExec();
|
|
82
|
+
_probeMemo = {
|
|
83
|
+
result,
|
|
84
|
+
expiresAt: result ? Number.POSITIVE_INFINITY : now + PROBE_FAILURE_TTL_MS
|
|
85
|
+
};
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function resetProbeMemo() {
|
|
89
|
+
_probeMemo = undefined;
|
|
90
|
+
}
|
|
91
|
+
function shellEscape(s) {
|
|
92
|
+
return s.replace(/'/g, "'\\''");
|
|
93
|
+
}
|
|
94
|
+
function sbplEscapePath(path2) {
|
|
95
|
+
const withoutControlChars = path2.split("").filter((ch) => {
|
|
96
|
+
const cp = ch.codePointAt(0);
|
|
97
|
+
return cp >= 32 && cp !== 127;
|
|
98
|
+
}).join("");
|
|
99
|
+
return withoutControlChars.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
100
|
+
}
|
|
101
|
+
function buildSandboxProfile(scopePaths, tempDir, envOverrides) {
|
|
102
|
+
const rwPaths = [...scopePaths];
|
|
103
|
+
if (tempDir) {
|
|
104
|
+
rwPaths.push(tempDir);
|
|
105
|
+
}
|
|
106
|
+
const rwAllowLines = rwPaths.map((p) => `(allow file-write* (subpath "${sbplEscapePath(p)}"))`).join(`
|
|
107
|
+
`);
|
|
108
|
+
const envLines = [];
|
|
109
|
+
if (envOverrides) {
|
|
110
|
+
for (const [key, value] of Object.entries(envOverrides)) {
|
|
111
|
+
if (!isValidEnvKey(key)) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (value === null) {
|
|
115
|
+
envLines.push(`(unsetenv ${key})`);
|
|
116
|
+
} else {
|
|
117
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
118
|
+
envLines.push(`(setenv ${key} "${escaped}")`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const profile = `(version 1)
|
|
123
|
+
(allow default)
|
|
124
|
+
(allow file-read* (subpath "/usr"))
|
|
125
|
+
(allow file-read* (subpath "/bin"))
|
|
126
|
+
(allow file-read* (subpath "/sbin"))
|
|
127
|
+
(allow file-read* (subpath "/lib"))
|
|
128
|
+
(allow file-read* (subpath "/lib64"))
|
|
129
|
+
(deny file-write*)
|
|
130
|
+
${rwAllowLines}
|
|
131
|
+
${envLines.join(`
|
|
132
|
+
`)}`;
|
|
133
|
+
return profile;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class MacOSSandboxExecutor {
|
|
137
|
+
mechanism = "sandbox-exec";
|
|
138
|
+
_scopePaths;
|
|
139
|
+
_tempDir;
|
|
140
|
+
_available;
|
|
141
|
+
_disabledReason;
|
|
142
|
+
constructor(scopePaths = [], tempDir) {
|
|
143
|
+
if (process.platform !== "darwin") {
|
|
144
|
+
throw new Error("MacOSSandboxExecutor not yet implemented");
|
|
145
|
+
}
|
|
146
|
+
this._scopePaths = scopePaths;
|
|
147
|
+
this._tempDir = tempDir;
|
|
148
|
+
this._available = false;
|
|
149
|
+
this._disabledReason = null;
|
|
150
|
+
try {
|
|
151
|
+
if (!_internals.probeSandboxExecMemoized()) {
|
|
152
|
+
this._disabledReason = "sandbox-exec not available or not functional";
|
|
153
|
+
warn(`Sandbox disabled: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
154
|
+
} else {
|
|
155
|
+
this._available = true;
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
159
|
+
this._disabledReason = `constructor threw: ${message}`;
|
|
160
|
+
this._available = false;
|
|
161
|
+
warn(`Sandbox disabled: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
isAvailable() {
|
|
165
|
+
return this._available;
|
|
166
|
+
}
|
|
167
|
+
disable(reason) {
|
|
168
|
+
this._disabledReason = reason;
|
|
169
|
+
this._available = false;
|
|
170
|
+
warn(`Sandbox disabled: ${reason}. Falling through to tool-layer enforcement.`);
|
|
171
|
+
}
|
|
172
|
+
wrapCommand(command, scopePaths, tempDir, envOverrides) {
|
|
173
|
+
if (!this._available) {
|
|
174
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
175
|
+
}
|
|
176
|
+
if (!_internals.probeSandboxExecMemoized()) {
|
|
177
|
+
this._available = false;
|
|
178
|
+
this._disabledReason = "sandbox-exec became unavailable between calls";
|
|
179
|
+
warn(`Sandbox disabled: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
180
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
181
|
+
}
|
|
182
|
+
const temp = tempDir ?? this._tempDir ?? os.tmpdir();
|
|
183
|
+
const allScopes = [...this._scopePaths, ...scopePaths];
|
|
184
|
+
const profile = buildSandboxProfile(allScopes, temp, envOverrides);
|
|
185
|
+
let profilePath;
|
|
186
|
+
try {
|
|
187
|
+
const profileDir = mkdtempSync(path.join(os.tmpdir(), "sandbox-"));
|
|
188
|
+
profilePath = path.join(profileDir, `profile-${process.pid}-${Date.now()}.sb`);
|
|
189
|
+
writeFileSync(profilePath, profile, { mode: 384 });
|
|
190
|
+
} catch (err) {
|
|
191
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
192
|
+
warn(`Sandbox disabled: failed to write profile (${message}). Falling through to tool-layer enforcement.`);
|
|
193
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
194
|
+
}
|
|
195
|
+
const binary = _internals.resolveSandboxExecBinary();
|
|
196
|
+
const escapedCommand = shellEscape(command);
|
|
197
|
+
const escapedProfilePath = shellEscape(profilePath);
|
|
198
|
+
return `${binary} -f '${escapedProfilePath}' bash -c '${escapedCommand}'`;
|
|
199
|
+
}
|
|
200
|
+
getEnvOverrides() {
|
|
201
|
+
return {
|
|
202
|
+
DYLD_INSERT_LIBRARIES: null,
|
|
203
|
+
DYLD_LIBRARY_PATH: null,
|
|
204
|
+
DYLD_FRAMEWORK_PATH: null,
|
|
205
|
+
DYLD_ROOT_PATH: null,
|
|
206
|
+
PATH: "/usr/bin:/bin:/usr/sbin:/sbin"
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
var SANDBOX_UNAVAILABLE_CODES, SANDBOX_EXEC_ABSOLUTE = "/usr/bin/sandbox-exec", TRUE_ABSOLUTE = "/usr/bin/true", PROBE_FAILURE_TTL_MS = 60000, _probeMemo, _internals;
|
|
211
|
+
var init_sandbox_exec_executor = __esm(() => {
|
|
212
|
+
init_logger();
|
|
213
|
+
init_executor();
|
|
214
|
+
SANDBOX_UNAVAILABLE_CODES = new Set(["ENOENT", "EACCES", "ENOSPC"]);
|
|
215
|
+
_internals = {
|
|
216
|
+
probeSandboxExec,
|
|
217
|
+
probeSandboxExecMemoized,
|
|
218
|
+
resetProbeMemo,
|
|
219
|
+
buildSandboxProfile,
|
|
220
|
+
buildProbeProfile,
|
|
221
|
+
resolveSandboxExecBinary,
|
|
222
|
+
resolveProbeTargetBinary,
|
|
223
|
+
exists: existsSync,
|
|
224
|
+
spawnSync
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// src/sandbox/executors/macos.ts
|
|
229
|
+
var exports_macos = {};
|
|
230
|
+
__export(exports_macos, {
|
|
231
|
+
MacOSSandboxExecutor: () => MacOSSandboxExecutor
|
|
232
|
+
});
|
|
233
|
+
var init_macos = __esm(() => {
|
|
234
|
+
init_sandbox_exec_executor();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// src/sandbox/win32/edge-cases.ts
|
|
238
|
+
function detectPowerShellEscape(command) {
|
|
239
|
+
if (process.platform !== "win32")
|
|
240
|
+
return false;
|
|
241
|
+
const encodedCommandPattern = /-EncodedCommand/i;
|
|
242
|
+
if (encodedCommandPattern.test(command)) {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
const encodedBase64Pattern = /-Enc(odedCommand)?\s+[A-Za-z0-9+/=]+/i;
|
|
246
|
+
if (encodedBase64Pattern.test(command)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
const psExePattern = /powershell\.exe?\s+.*-(?:e(?:n(?:c(?:odedCommand)?)?)?|wmi|remote)/i;
|
|
250
|
+
if (psExePattern.test(command)) {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
const iexPattern = /\biex\b/i;
|
|
254
|
+
if (iexPattern.test(command)) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
const invokeExpressionPattern = /Invoke-Expression/i;
|
|
258
|
+
if (invokeExpressionPattern.test(command)) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
const invokeCommandRemotePattern = /Invoke-Command\s+.*-ComputerName/i;
|
|
262
|
+
if (invokeCommandRemotePattern.test(command)) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
const psCommandPattern = /powershell.*-Command\s+["'].*\$/i;
|
|
266
|
+
if (psCommandPattern.test(command)) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
const execPolicyPattern = /-ExecutionPolicy\s+(?:Bypass|RemoteSigned|Unrestricted)/i;
|
|
270
|
+
if (execPolicyPattern.test(command)) {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
const noProfilePattern = /-NoProfile\s+-/i;
|
|
274
|
+
if (noProfilePattern.test(command)) {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
const automationPattern = /New-Object\s+.*Management\.Automation/i;
|
|
278
|
+
if (automationPattern.test(command)) {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
const downloadPattern = /\[System\.Net\.(?:WebClient|Http).*\]\.(?:DownloadString|DownloadFile)/i;
|
|
282
|
+
if (downloadPattern.test(command)) {
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
const hiddenWindowPattern = /-WindowStyle\s+Hidden/i;
|
|
286
|
+
if (hiddenWindowPattern.test(command)) {
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
const scriptInjectionPattern = /\$(?:env|input|host)\b.*\|/i;
|
|
290
|
+
if (scriptInjectionPattern.test(command)) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
const obfuscatedIexPattern = /IEX|i:eX/i;
|
|
294
|
+
if (obfuscatedIexPattern.test(command)) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
var init_edge_cases = () => {};
|
|
300
|
+
|
|
301
|
+
// src/sandbox/win32/restricted-environment-executor.ts
|
|
302
|
+
import { Buffer } from "buffer";
|
|
303
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
304
|
+
import * as os2 from "os";
|
|
305
|
+
import * as path2 from "path";
|
|
306
|
+
function containsUnsafePathSyntax(value) {
|
|
307
|
+
return [...value].some((character) => character.charCodeAt(0) < 32 || UNSAFE_PATH_CHARACTERS.has(character));
|
|
308
|
+
}
|
|
309
|
+
function getSafeSystemRoot() {
|
|
310
|
+
const raw = process.env.SystemRoot;
|
|
311
|
+
if (typeof raw !== "string" || !/^[A-Za-z]:[\\/]/.test(raw) || containsUnsafePathSyntax(raw.slice(2)) || raw.slice(3).split(/[\\/]+/).some((segment) => segment === "." || segment === "..")) {
|
|
312
|
+
return DEFAULT_SYSTEM_ROOT;
|
|
313
|
+
}
|
|
314
|
+
const normalized = path2.win32.normalize(raw);
|
|
315
|
+
return normalized.length > 3 ? normalized.replace(/\\+$/, "") : normalized;
|
|
316
|
+
}
|
|
317
|
+
function getWindowsExecutablePaths() {
|
|
318
|
+
const systemRoot = getSafeSystemRoot();
|
|
319
|
+
return {
|
|
320
|
+
systemRoot,
|
|
321
|
+
cmdExe: path2.win32.join(systemRoot, "System32", "cmd.exe"),
|
|
322
|
+
powerShellExe: path2.win32.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function probeWindowsSandbox() {
|
|
326
|
+
try {
|
|
327
|
+
const result = spawnSync2(getWindowsExecutablePaths().cmdExe, ["/d", "/s", "/c", "echo ok"], {
|
|
328
|
+
cwd: os2.tmpdir(),
|
|
329
|
+
windowsHide: true,
|
|
330
|
+
encoding: "utf-8",
|
|
331
|
+
timeout: 5000,
|
|
332
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
333
|
+
});
|
|
334
|
+
if (result.error) {
|
|
335
|
+
const code = result.error.code;
|
|
336
|
+
if (code && SANDBOX_UNAVAILABLE_CODES2.has(code)) {
|
|
337
|
+
warn(`Sandbox disabled: spawn error (${code}). Falling through to tool-layer enforcement.`);
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
warn(`Sandbox disabled: spawn error (${result.error.message}). Falling through to tool-layer enforcement.`);
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
return result.status === 0;
|
|
344
|
+
} catch (err) {
|
|
345
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
346
|
+
warn(`Sandbox disabled: probe threw (${message}). Falling through to tool-layer enforcement.`);
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
function psSingleQuoteEscape(s) {
|
|
351
|
+
return s.replace(/'/g, "''");
|
|
352
|
+
}
|
|
353
|
+
function normalizeInheritedPathEntry(rawEntry) {
|
|
354
|
+
const entry = rawEntry.trim();
|
|
355
|
+
if (!/^[A-Za-z]:[\\/]/.test(entry) || containsUnsafePathSyntax(entry.slice(2)) || entry.slice(3).split(/[\\/]+/).some((segment) => segment === "." || segment === "..")) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const normalized = path2.win32.normalize(entry);
|
|
359
|
+
return normalized.length > 3 ? normalized.replace(/\\+$/, "") : normalized;
|
|
360
|
+
}
|
|
361
|
+
function getSafeWindowsPath() {
|
|
362
|
+
const { systemRoot } = getWindowsExecutablePaths();
|
|
363
|
+
const candidates = [
|
|
364
|
+
path2.win32.join(systemRoot, "System32"),
|
|
365
|
+
systemRoot,
|
|
366
|
+
...(process.env.PATH ?? "").split(";")
|
|
367
|
+
];
|
|
368
|
+
const seen = new Set;
|
|
369
|
+
const safeEntries = [];
|
|
370
|
+
for (const candidate of candidates) {
|
|
371
|
+
const normalized = normalizeInheritedPathEntry(candidate);
|
|
372
|
+
if (!normalized)
|
|
373
|
+
continue;
|
|
374
|
+
const identity = normalized.toLowerCase();
|
|
375
|
+
if (seen.has(identity))
|
|
376
|
+
continue;
|
|
377
|
+
seen.add(identity);
|
|
378
|
+
safeEntries.push(normalized);
|
|
379
|
+
}
|
|
380
|
+
return safeEntries.join(";");
|
|
381
|
+
}
|
|
382
|
+
function isPowerShellNativeCommand(command) {
|
|
383
|
+
return /^(?:Remove-Item|rm|del|erase|Copy-Item|cp|copy|Move-Item|mv|move|Rename-Item|ren|New-Item|ni|Get-Item|gi|Get-ChildItem|ls|dir|gci|Get-Content|cat|type|gc|Set-Content|sc|Add-Content|ac|Clear-Content|clc|Test-Path|Resolve-Path|Split-Path|Join-Path|Out-File|Get-Date)\b/i.test(command.trimStart());
|
|
384
|
+
}
|
|
385
|
+
function isSafePsCommandBody(command) {
|
|
386
|
+
return !/[;&|`$()\r\n]/.test(command);
|
|
387
|
+
}
|
|
388
|
+
function isPathInScopes(command, scopes) {
|
|
389
|
+
if (scopes.length === 0)
|
|
390
|
+
return true;
|
|
391
|
+
const pathPattern = /[A-Za-z]:(?:[^\\/:*?"<>|\r\n]+(?:\\[^\\/:*?"<>|\r\n]+)*)/g;
|
|
392
|
+
const paths = command.match(pathPattern) || [];
|
|
393
|
+
if (paths.length === 0)
|
|
394
|
+
return true;
|
|
395
|
+
const normalizedPaths = paths.map((p) => path2.win32.resolve(p));
|
|
396
|
+
const normalizedScopes = scopes.map((s) => s.toLowerCase().replace(/\\+$/, ""));
|
|
397
|
+
return normalizedPaths.every((p) => {
|
|
398
|
+
const lower = p.toLowerCase();
|
|
399
|
+
return normalizedScopes.some((scope) => lower.startsWith(scope));
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
class WindowsSandboxExecutor {
|
|
404
|
+
mechanism = "powershell-wrapper";
|
|
405
|
+
_scopePaths;
|
|
406
|
+
_tempDir;
|
|
407
|
+
_available;
|
|
408
|
+
_disabled;
|
|
409
|
+
_disabledReason;
|
|
410
|
+
constructor(scopePaths = [], tempDir) {
|
|
411
|
+
this._scopePaths = scopePaths;
|
|
412
|
+
this._tempDir = tempDir;
|
|
413
|
+
this._available = false;
|
|
414
|
+
this._disabled = false;
|
|
415
|
+
this._disabledReason = null;
|
|
416
|
+
try {
|
|
417
|
+
if (!_internals2.probeWindowsSandbox()) {
|
|
418
|
+
this._available = false;
|
|
419
|
+
this._disabledReason = "Windows sandbox not available or not functional";
|
|
420
|
+
warn(`Sandbox unavailable: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
421
|
+
} else {
|
|
422
|
+
this._available = true;
|
|
423
|
+
}
|
|
424
|
+
} catch (err) {
|
|
425
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
426
|
+
this._available = false;
|
|
427
|
+
this._disabledReason = `constructor probe threw: ${message}`;
|
|
428
|
+
warn(`Sandbox unavailable: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
isAvailable() {
|
|
432
|
+
return this._available && !this._disabled;
|
|
433
|
+
}
|
|
434
|
+
disable(reason) {
|
|
435
|
+
this._disabled = true;
|
|
436
|
+
this._disabledReason = reason;
|
|
437
|
+
warn(`Sandbox disabled: ${reason}. Falling through to tool-layer enforcement.`);
|
|
438
|
+
}
|
|
439
|
+
wrapCommand(command, scopePaths, tempDir, envOverrides) {
|
|
440
|
+
if (!this.isAvailable()) {
|
|
441
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
442
|
+
}
|
|
443
|
+
if (!_internals2.probeWindowsSandbox()) {
|
|
444
|
+
this._available = false;
|
|
445
|
+
this._disabledReason = "Windows sandbox became unavailable between calls";
|
|
446
|
+
warn(`Sandbox disabled: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
447
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
448
|
+
}
|
|
449
|
+
const temp = tempDir ?? this._tempDir ?? os2.tmpdir();
|
|
450
|
+
const _allScopes = [...this._scopePaths, ...scopePaths];
|
|
451
|
+
if (detectPowerShellEscape(command)) {
|
|
452
|
+
throw new SandboxError("Command contains PowerShell escape patterns", "DETECT_POWERSHELL_ESCAPE");
|
|
453
|
+
}
|
|
454
|
+
if (!isPathInScopes(command, _allScopes)) {
|
|
455
|
+
throw new SandboxError("Command targets paths outside authorized scopes", "PATH_ESCAPE_SCOPE");
|
|
456
|
+
}
|
|
457
|
+
if (isPowerShellNativeCommand(command) && !isSafePsCommandBody(command)) {
|
|
458
|
+
throw new SandboxError("PowerShell-native command body contains unsafe characters", "UNSAFE_PS_COMMAND");
|
|
459
|
+
}
|
|
460
|
+
const safePath = getSafeWindowsPath();
|
|
461
|
+
const { cmdExe, powerShellExe } = getWindowsExecutablePaths();
|
|
462
|
+
const commandBase64 = Buffer.from(command, "utf8").toString("base64");
|
|
463
|
+
const escapedTemp = psSingleQuoteEscape(temp);
|
|
464
|
+
const escapedPath = psSingleQuoteEscape(safePath);
|
|
465
|
+
const escapedCmdExe = psSingleQuoteEscape(cmdExe);
|
|
466
|
+
const envOverrideLines = [];
|
|
467
|
+
if (envOverrides) {
|
|
468
|
+
for (const [key, value] of Object.entries(envOverrides)) {
|
|
469
|
+
if (!isValidEnvKey(key)) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (value === null) {
|
|
473
|
+
envOverrideLines.push(`Remove-Item Env:${key} -Force -ErrorAction SilentlyContinue;`);
|
|
474
|
+
} else {
|
|
475
|
+
const psEscaped = psSingleQuoteEscape(value);
|
|
476
|
+
envOverrideLines.push(`$env:${key} = '${psEscaped}';`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const commandExec = isPowerShellNativeCommand(command) ? `Invoke-Expression $command;
|
|
481
|
+
exit 0;` : `$batchPath = $null;
|
|
482
|
+
$batchLocationPushed = $false;
|
|
483
|
+
try {
|
|
484
|
+
if ($command.Contains([char]13) -or $command.Contains([char]10)) {
|
|
485
|
+
$batchName = 'opencode-swarm-' + [Guid]::NewGuid().ToString('N') + '.cmd';
|
|
486
|
+
$batchPath = Join-Path $env:TEMP $batchName;
|
|
487
|
+
[IO.File]::WriteAllText($batchPath, $command, [Text.UTF8Encoding]::new($false));
|
|
488
|
+
Push-Location -LiteralPath $env:TEMP;
|
|
489
|
+
$batchLocationPushed = $true;
|
|
490
|
+
& '${escapedCmdExe}' /d /v:off /s /c ('call "' + $batchName + '"');
|
|
491
|
+
} else {
|
|
492
|
+
& '${escapedCmdExe}' /d /v:off /s /c $command;
|
|
493
|
+
}
|
|
494
|
+
$childExitCode = $LASTEXITCODE;
|
|
495
|
+
} finally {
|
|
496
|
+
if ($batchLocationPushed) {
|
|
497
|
+
Pop-Location;
|
|
498
|
+
}
|
|
499
|
+
if ($null -ne $batchPath) {
|
|
500
|
+
Remove-Item -LiteralPath $batchPath -Force -ErrorAction SilentlyContinue;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if ($null -eq $childExitCode) {
|
|
504
|
+
throw 'cmd.exe did not report an exit code';
|
|
505
|
+
}
|
|
506
|
+
exit [int]$childExitCode;`;
|
|
507
|
+
const envOverrideBlock = envOverrideLines.length > 0 ? `
|
|
508
|
+
${envOverrideLines.join(`
|
|
509
|
+
`)}` : "";
|
|
510
|
+
const psScript = `
|
|
511
|
+
$ErrorActionPreference = 'Stop';
|
|
512
|
+
$ProgressPreference = 'SilentlyContinue';
|
|
513
|
+
try {
|
|
514
|
+
$env:TEMP = '${escapedTemp}';
|
|
515
|
+
$env:TMP = '${escapedTemp}';
|
|
516
|
+
|
|
517
|
+
$env:PATH = '${escapedPath}';
|
|
518
|
+
|
|
519
|
+
$dangerousVars = @(
|
|
520
|
+
'LD_PRELOAD',
|
|
521
|
+
'DYLD_INSERT_LIBRARIES',
|
|
522
|
+
'DYLD_LIBRARY_PATH',
|
|
523
|
+
'DYLD_FRAMEWORK_PATH',
|
|
524
|
+
'DYLD_ROOT_PATH',
|
|
525
|
+
'DYLD_FORCE_FLAT_NAMESPACE'
|
|
526
|
+
);
|
|
527
|
+
foreach ($v in $dangerousVars) {
|
|
528
|
+
if (Test-Path Env:$v) {
|
|
529
|
+
Remove-Item Env:$v -Force -ErrorAction SilentlyContinue;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
${envOverrideBlock}
|
|
533
|
+
|
|
534
|
+
# Execute the command \u2014 PS-native cmdlets via Invoke-Expression, others via the standard command interpreter
|
|
535
|
+
$commandBytes = [Convert]::FromBase64String('${commandBase64}');
|
|
536
|
+
$command = [Text.Encoding]::UTF8.GetString($commandBytes);
|
|
537
|
+
${commandExec};
|
|
538
|
+
} catch {
|
|
539
|
+
[Console]::Error.WriteLine($_.Exception.Message);
|
|
540
|
+
exit 1;
|
|
541
|
+
}`;
|
|
542
|
+
const encodedScript = Buffer.from(psScript, "utf16le").toString("base64");
|
|
543
|
+
const escapedPowerShellExe = psSingleQuoteEscape(powerShellExe);
|
|
544
|
+
return `& '${escapedPowerShellExe}' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -EncodedCommand ${encodedScript}; exit $LASTEXITCODE`;
|
|
545
|
+
}
|
|
546
|
+
getEnvOverrides() {
|
|
547
|
+
return {
|
|
548
|
+
PATH: getSafeWindowsPath(),
|
|
549
|
+
TEMP: null,
|
|
550
|
+
TMP: null,
|
|
551
|
+
LD_PRELOAD: null,
|
|
552
|
+
DYLD_INSERT_LIBRARIES: null,
|
|
553
|
+
DYLD_LIBRARY_PATH: null,
|
|
554
|
+
DYLD_FRAMEWORK_PATH: null,
|
|
555
|
+
DYLD_ROOT_PATH: null,
|
|
556
|
+
DYLD_FORCE_FLAT_NAMESPACE: null
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
var SANDBOX_UNAVAILABLE_CODES2, DEFAULT_SYSTEM_ROOT = "C:\\Windows", UNSAFE_PATH_CHARACTERS, _internals2;
|
|
561
|
+
var init_restricted_environment_executor = __esm(() => {
|
|
562
|
+
init_logger();
|
|
563
|
+
init_executor();
|
|
564
|
+
init_edge_cases();
|
|
565
|
+
SANDBOX_UNAVAILABLE_CODES2 = new Set([
|
|
566
|
+
"ENOENT",
|
|
567
|
+
"EACCES",
|
|
568
|
+
"EPERM",
|
|
569
|
+
"ENOSPC"
|
|
570
|
+
]);
|
|
571
|
+
UNSAFE_PATH_CHARACTERS = new Set([
|
|
572
|
+
":",
|
|
573
|
+
'"',
|
|
574
|
+
"'",
|
|
575
|
+
";",
|
|
576
|
+
"&",
|
|
577
|
+
"|",
|
|
578
|
+
"<",
|
|
579
|
+
">",
|
|
580
|
+
"^",
|
|
581
|
+
"%",
|
|
582
|
+
"!",
|
|
583
|
+
"?",
|
|
584
|
+
"*",
|
|
585
|
+
"`",
|
|
586
|
+
"$"
|
|
587
|
+
]);
|
|
588
|
+
_internals2 = {
|
|
589
|
+
probeWindowsSandbox
|
|
590
|
+
};
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
// src/sandbox/win32/runner-client.ts
|
|
594
|
+
var exports_runner_client = {};
|
|
595
|
+
__export(exports_runner_client, {
|
|
596
|
+
probe: () => probe,
|
|
597
|
+
execute: () => execute,
|
|
598
|
+
buildDefaultPolicy: () => buildDefaultPolicy,
|
|
599
|
+
_resetProbeCache: () => _resetProbeCache,
|
|
600
|
+
_internals: () => _internals3,
|
|
601
|
+
RUNNER_EXIT_CODES: () => RUNNER_EXIT_CODES
|
|
602
|
+
});
|
|
603
|
+
import { spawn, spawnSync as spawnSync3 } from "child_process";
|
|
604
|
+
import * as fs from "fs";
|
|
605
|
+
import * as os3 from "os";
|
|
606
|
+
import * as path3 from "path";
|
|
607
|
+
import { fileURLToPath } from "url";
|
|
608
|
+
function findRunnerBinary() {
|
|
609
|
+
const arch = process.arch === "x64" ? "x64" : "arm64";
|
|
610
|
+
const platform = "win32";
|
|
611
|
+
const packagePaths = [
|
|
612
|
+
path3.resolve(_runtimeDir, "..", "..", "..", "binaries", `${platform}-${arch}`, "swarm-sandbox-runner.exe"),
|
|
613
|
+
path3.resolve(_runtimeDir, "..", "..", "..", "..", "binaries", `${platform}-${arch}`, "swarm-sandbox-runner.exe")
|
|
614
|
+
];
|
|
615
|
+
for (const p of packagePaths) {
|
|
616
|
+
try {
|
|
617
|
+
if (fs.existsSync(p)) {
|
|
618
|
+
return p;
|
|
619
|
+
}
|
|
620
|
+
} catch {}
|
|
621
|
+
}
|
|
622
|
+
try {
|
|
623
|
+
const result = spawnSync3("where", ["swarm-sandbox-runner.exe"], {
|
|
624
|
+
windowsHide: true,
|
|
625
|
+
encoding: "utf-8",
|
|
626
|
+
timeout: 2000,
|
|
627
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
628
|
+
});
|
|
629
|
+
if (result.status === 0 && result.stdout?.trim()) {
|
|
630
|
+
return result.stdout.trim().split(`
|
|
631
|
+
`)[0]?.trim() ?? null;
|
|
632
|
+
}
|
|
633
|
+
} catch {}
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
function probe() {
|
|
637
|
+
if (_cachedProbe !== undefined) {
|
|
638
|
+
return _cachedProbe;
|
|
639
|
+
}
|
|
640
|
+
if (process.platform !== "win32") {
|
|
641
|
+
_cachedProbe = {
|
|
642
|
+
available: false,
|
|
643
|
+
mode: "none",
|
|
644
|
+
capabilities: null,
|
|
645
|
+
error: "not Windows"
|
|
646
|
+
};
|
|
647
|
+
return _cachedProbe;
|
|
648
|
+
}
|
|
649
|
+
const binary = _internals3.findRunnerBinary();
|
|
650
|
+
if (!binary) {
|
|
651
|
+
_cachedProbe = {
|
|
652
|
+
available: false,
|
|
653
|
+
mode: "none",
|
|
654
|
+
capabilities: null,
|
|
655
|
+
error: "runner binary not found"
|
|
656
|
+
};
|
|
657
|
+
warn("Sandbox runner binary not found \u2014 degrading to weak sandbox");
|
|
658
|
+
return _cachedProbe;
|
|
659
|
+
}
|
|
660
|
+
try {
|
|
661
|
+
const result = _internals3.spawnRunner(binary, ["--probe"], {
|
|
662
|
+
windowsHide: true,
|
|
663
|
+
encoding: "utf-8",
|
|
664
|
+
timeout: 2000,
|
|
665
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
666
|
+
cwd: os3.tmpdir()
|
|
667
|
+
});
|
|
668
|
+
if (result.error) {
|
|
669
|
+
_cachedProbe = {
|
|
670
|
+
available: false,
|
|
671
|
+
mode: "none",
|
|
672
|
+
capabilities: null,
|
|
673
|
+
error: `probe spawn error: ${result.error.code ?? result.error.message}`
|
|
674
|
+
};
|
|
675
|
+
warn(`Sandbox runner probe failed: ${_cachedProbe.error}`);
|
|
676
|
+
return _cachedProbe;
|
|
677
|
+
}
|
|
678
|
+
if (result.status !== 0) {
|
|
679
|
+
_cachedProbe = {
|
|
680
|
+
available: false,
|
|
681
|
+
mode: "none",
|
|
682
|
+
capabilities: null,
|
|
683
|
+
error: `probe exited with code ${result.status}`
|
|
684
|
+
};
|
|
685
|
+
warn(`Sandbox runner probe failed: ${_cachedProbe.error}`);
|
|
686
|
+
return _cachedProbe;
|
|
687
|
+
}
|
|
688
|
+
const capabilities = JSON.parse(result.stdout?.trim() ?? "{}");
|
|
689
|
+
let mode = "none";
|
|
690
|
+
if (capabilities.app_container_available) {
|
|
691
|
+
mode = "app-container";
|
|
692
|
+
} else if (capabilities.restricted_token_available) {
|
|
693
|
+
mode = "restricted-token";
|
|
694
|
+
}
|
|
695
|
+
_cachedProbe = {
|
|
696
|
+
available: mode !== "none",
|
|
697
|
+
mode,
|
|
698
|
+
capabilities
|
|
699
|
+
};
|
|
700
|
+
return _cachedProbe;
|
|
701
|
+
} catch (err) {
|
|
702
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
703
|
+
_cachedProbe = {
|
|
704
|
+
available: false,
|
|
705
|
+
mode: "none",
|
|
706
|
+
capabilities: null,
|
|
707
|
+
error: `probe threw: ${msg}`
|
|
708
|
+
};
|
|
709
|
+
warn(`Sandbox runner probe threw: ${msg}`);
|
|
710
|
+
return _cachedProbe;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
async function execute(command, policy, mode = "auto") {
|
|
714
|
+
const binary = _internals3.findRunnerBinary();
|
|
715
|
+
if (!binary) {
|
|
716
|
+
throw new Error("runner binary not found");
|
|
717
|
+
}
|
|
718
|
+
const policyJson = JSON.stringify(policy);
|
|
719
|
+
const args = ["--policy-stdin", "--mode", mode, "--", ...command];
|
|
720
|
+
return new Promise((resolve2, reject) => {
|
|
721
|
+
let proc;
|
|
722
|
+
const timeout = setTimeout(() => {
|
|
723
|
+
proc?.kill();
|
|
724
|
+
reject(new Error("runner execution timeout"));
|
|
725
|
+
}, policy.wall_clock_timeout_ms + 5000);
|
|
726
|
+
const unref = timeout.unref;
|
|
727
|
+
if (typeof unref === "function") {
|
|
728
|
+
unref.call(timeout);
|
|
729
|
+
}
|
|
730
|
+
try {
|
|
731
|
+
proc = _internals3.spawnAsync(binary, args, {
|
|
732
|
+
windowsHide: true,
|
|
733
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
734
|
+
cwd: policy.workspace_roots[0] ?? os3.tmpdir()
|
|
735
|
+
});
|
|
736
|
+
} catch (err) {
|
|
737
|
+
clearTimeout(timeout);
|
|
738
|
+
reject(err);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
proc.stdin?.write(policyJson);
|
|
742
|
+
proc.stdin?.end();
|
|
743
|
+
let stdout = "";
|
|
744
|
+
let stderr = "";
|
|
745
|
+
const events = [];
|
|
746
|
+
proc.stdout?.on("data", (chunk) => {
|
|
747
|
+
stdout += chunk.toString();
|
|
748
|
+
});
|
|
749
|
+
proc.stderr?.on("data", (chunk) => {
|
|
750
|
+
const lines = chunk.toString().split(`
|
|
751
|
+
`);
|
|
752
|
+
for (const line of lines) {
|
|
753
|
+
const trimmed = line.trim();
|
|
754
|
+
if (!trimmed)
|
|
755
|
+
continue;
|
|
756
|
+
try {
|
|
757
|
+
const event = JSON.parse(trimmed);
|
|
758
|
+
if (event.type) {
|
|
759
|
+
events.push(event);
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
762
|
+
} catch {}
|
|
763
|
+
stderr += `${trimmed}
|
|
764
|
+
`;
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
proc.on("error", (err) => {
|
|
768
|
+
clearTimeout(timeout);
|
|
769
|
+
reject(err);
|
|
770
|
+
});
|
|
771
|
+
proc.on("close", (code) => {
|
|
772
|
+
clearTimeout(timeout);
|
|
773
|
+
const startEvent = events.find((e) => e.type === "start");
|
|
774
|
+
const runnerMode = startEvent?.mode ?? mode;
|
|
775
|
+
resolve2({
|
|
776
|
+
exitCode: code ?? 1,
|
|
777
|
+
stdout,
|
|
778
|
+
stderr,
|
|
779
|
+
events,
|
|
780
|
+
mode: runnerMode
|
|
781
|
+
});
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
function _resetProbeCache() {
|
|
786
|
+
_cachedProbe = undefined;
|
|
787
|
+
}
|
|
788
|
+
function buildDefaultPolicy(workspaceRoot, runId) {
|
|
789
|
+
const id = runId ?? `swarm-${crypto.randomUUID?.() ?? Date.now()}`;
|
|
790
|
+
const appData = process.env.LOCALAPPDATA ?? path3.join(os3.homedir(), "AppData", "Local");
|
|
791
|
+
const tempRoot = path3.join(appData, "opencode-swarm", "sandbox", id, "temp");
|
|
792
|
+
return {
|
|
793
|
+
schema_version: 1,
|
|
794
|
+
run_id: id,
|
|
795
|
+
workspace_roots: [workspaceRoot],
|
|
796
|
+
writable_roots: [workspaceRoot],
|
|
797
|
+
read_only_subpaths: [".git", ".codex", ".agents", ".swarm"],
|
|
798
|
+
temp_root: tempRoot,
|
|
799
|
+
temp_cap_bytes: 524288000,
|
|
800
|
+
memory_cap_bytes: 2147483648,
|
|
801
|
+
child_process_cap: 16,
|
|
802
|
+
wall_clock_timeout_ms: 600000,
|
|
803
|
+
network_mode: "off",
|
|
804
|
+
env_allowlist: ["PATH", "TEMP", "TMP", "USERPROFILE", "SYSTEMROOT"],
|
|
805
|
+
env_overrides: {
|
|
806
|
+
HTTP_PROXY: "http://127.0.0.1:1",
|
|
807
|
+
HTTPS_PROXY: "http://127.0.0.1:1"
|
|
808
|
+
},
|
|
809
|
+
path_stubs: ["ssh.exe", "curl.exe", "wget.exe", "scp.exe", "sftp.exe"],
|
|
810
|
+
private_desktop: true,
|
|
811
|
+
deny_alternate_data_streams: true,
|
|
812
|
+
deny_unc_paths: true,
|
|
813
|
+
deny_device_paths: true,
|
|
814
|
+
deny_symlink_egress: true
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
var _runtimeDir, RUNNER_EXIT_CODES, _cachedProbe, _internals3;
|
|
818
|
+
var init_runner_client = __esm(() => {
|
|
819
|
+
init_logger();
|
|
820
|
+
_runtimeDir = fileURLToPath(new URL(".", import.meta.url));
|
|
821
|
+
RUNNER_EXIT_CODES = {
|
|
822
|
+
SUCCESS: 0,
|
|
823
|
+
CHILD_NON_ZERO: 1,
|
|
824
|
+
POLICY_VIOLATION: 64,
|
|
825
|
+
QUOTA_EXCEEDED: 65,
|
|
826
|
+
WALL_CLOCK_TIMEOUT: 66,
|
|
827
|
+
LAUNCHER_MISCONFIG: 67,
|
|
828
|
+
OS_API_FAILURE: 68,
|
|
829
|
+
PROBE_FAILED: 69
|
|
830
|
+
};
|
|
831
|
+
_internals3 = {
|
|
832
|
+
findRunnerBinary,
|
|
833
|
+
spawnRunner: spawnSync3,
|
|
834
|
+
spawnAsync: spawn
|
|
835
|
+
};
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
// src/sandbox/win32/native-sandbox-executor.ts
|
|
839
|
+
import * as crypto2 from "crypto";
|
|
840
|
+
import * as fs2 from "fs";
|
|
841
|
+
import * as os4 from "os";
|
|
842
|
+
import * as path4 from "path";
|
|
843
|
+
|
|
844
|
+
class NativeWindowsSandboxExecutor {
|
|
845
|
+
mechanism;
|
|
846
|
+
_probeResult;
|
|
847
|
+
_fallbackExecutor;
|
|
848
|
+
_strength;
|
|
849
|
+
_disabled;
|
|
850
|
+
_disabledReason;
|
|
851
|
+
constructor(scopePaths = [], tempDir) {
|
|
852
|
+
this._disabled = false;
|
|
853
|
+
this._disabledReason = null;
|
|
854
|
+
this._fallbackExecutor = new WindowsSandboxExecutor(scopePaths, tempDir);
|
|
855
|
+
this._probeResult = probe();
|
|
856
|
+
if (this._probeResult.available) {
|
|
857
|
+
this._strength = "strong";
|
|
858
|
+
this.mechanism = `native-runner/${this._probeResult.mode}`;
|
|
859
|
+
} else if (this._fallbackExecutor.isAvailable()) {
|
|
860
|
+
this._strength = "weak";
|
|
861
|
+
this.mechanism = "powershell-wrapper";
|
|
862
|
+
warn(`Native sandbox runner unavailable (${this._probeResult.error ?? "unknown"}); ` + "falling back to PowerShell environment restrictions (weak sandbox)");
|
|
863
|
+
} else {
|
|
864
|
+
this._strength = "none";
|
|
865
|
+
this.mechanism = "none";
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
get strength() {
|
|
869
|
+
if (this._disabled)
|
|
870
|
+
return "none";
|
|
871
|
+
return this._strength;
|
|
872
|
+
}
|
|
873
|
+
isAvailable() {
|
|
874
|
+
return !this._disabled && this._strength !== "none";
|
|
875
|
+
}
|
|
876
|
+
disable(reason) {
|
|
877
|
+
this._disabled = true;
|
|
878
|
+
this._disabledReason = reason;
|
|
879
|
+
warn(`Sandbox disabled: ${reason}. Falling through to tool-layer enforcement.`);
|
|
880
|
+
}
|
|
881
|
+
wrapCommand(command, scopePaths, tempDir, envOverrides) {
|
|
882
|
+
if (!this.isAvailable()) {
|
|
883
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
884
|
+
}
|
|
885
|
+
if (this._strength === "strong") {
|
|
886
|
+
return this._wrapWithRunner(command, scopePaths, tempDir, envOverrides);
|
|
887
|
+
}
|
|
888
|
+
return this._fallbackExecutor.wrapCommand(command, scopePaths, tempDir, envOverrides);
|
|
889
|
+
}
|
|
890
|
+
_wrapWithRunner(command, scopePaths, tempDir, _envOverrides) {
|
|
891
|
+
const binary = _internals3.findRunnerBinary();
|
|
892
|
+
if (!binary) {
|
|
893
|
+
throw new SandboxError("Runner binary not found", "RUNNER_NOT_FOUND");
|
|
894
|
+
}
|
|
895
|
+
const workspaceRoot = scopePaths[0] ?? process.cwd();
|
|
896
|
+
const runId = `swarm-${crypto2.randomUUID?.() ?? Date.now()}`;
|
|
897
|
+
const policy = buildDefaultPolicy(workspaceRoot, runId);
|
|
898
|
+
if (tempDir) {
|
|
899
|
+
policy.temp_root = tempDir;
|
|
900
|
+
}
|
|
901
|
+
policy.workspace_roots = scopePaths.length > 0 ? scopePaths : [workspaceRoot];
|
|
902
|
+
policy.writable_roots = policy.workspace_roots;
|
|
903
|
+
if (_envOverrides) {
|
|
904
|
+
for (const [key, value] of Object.entries(_envOverrides)) {
|
|
905
|
+
if (!isValidEnvKey(key))
|
|
906
|
+
continue;
|
|
907
|
+
if (typeof value === "string") {
|
|
908
|
+
policy.env_overrides[key] = value;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
const policyJson = JSON.stringify(policy);
|
|
913
|
+
const policyDir = path4.join(os4.tmpdir(), "swarm-sandbox-policies");
|
|
914
|
+
try {
|
|
915
|
+
fs2.mkdirSync(policyDir, { recursive: true });
|
|
916
|
+
} catch {}
|
|
917
|
+
const policyFile = path4.join(policyDir, `${runId}.json`);
|
|
918
|
+
fs2.writeFileSync(policyFile, policyJson, "utf-8");
|
|
919
|
+
const mode = this._probeResult.mode === "none" ? "auto" : this._probeResult.mode;
|
|
920
|
+
const escapedBinary = binary.includes(" ") ? `"${binary}"` : binary;
|
|
921
|
+
const escapedPolicyFile = policyFile.includes(" ") ? `"${policyFile}"` : policyFile;
|
|
922
|
+
const escapedCommand = command.replace(/"/g, "\\\"");
|
|
923
|
+
return `cmd /c "type ${escapedPolicyFile} | ${escapedBinary} --policy-stdin --mode ${mode} -- ${escapedCommand} & del ${escapedPolicyFile} 2>nul"`;
|
|
924
|
+
}
|
|
925
|
+
getEnvOverrides() {
|
|
926
|
+
if (this._strength === "strong") {
|
|
927
|
+
return {
|
|
928
|
+
PATH: null,
|
|
929
|
+
TEMP: null,
|
|
930
|
+
TMP: null,
|
|
931
|
+
LD_PRELOAD: null,
|
|
932
|
+
DYLD_INSERT_LIBRARIES: null,
|
|
933
|
+
DYLD_LIBRARY_PATH: null,
|
|
934
|
+
DYLD_FRAMEWORK_PATH: null,
|
|
935
|
+
DYLD_ROOT_PATH: null,
|
|
936
|
+
DYLD_FORCE_FLAT_NAMESPACE: null
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
return this._fallbackExecutor.getEnvOverrides();
|
|
940
|
+
}
|
|
941
|
+
async executeNative(command, workspaceRoot, runId) {
|
|
942
|
+
if (this._strength !== "strong") {
|
|
943
|
+
throw new SandboxError("Native execution requires strong sandbox (runner binary)", "NATIVE_UNAVAILABLE");
|
|
944
|
+
}
|
|
945
|
+
const policy = buildDefaultPolicy(workspaceRoot, runId);
|
|
946
|
+
return execute(command, policy);
|
|
947
|
+
}
|
|
948
|
+
get hasNativeRunner() {
|
|
949
|
+
return this._strength === "strong";
|
|
950
|
+
}
|
|
951
|
+
get disabledReason() {
|
|
952
|
+
return this._disabledReason;
|
|
953
|
+
}
|
|
954
|
+
get probeResult() {
|
|
955
|
+
return this._probeResult;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
var init_native_sandbox_executor = __esm(() => {
|
|
959
|
+
init_logger();
|
|
960
|
+
init_executor();
|
|
961
|
+
init_restricted_environment_executor();
|
|
962
|
+
init_runner_client();
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
// src/sandbox/executors/windows.ts
|
|
966
|
+
var exports_windows = {};
|
|
967
|
+
__export(exports_windows, {
|
|
968
|
+
WindowsSandboxExecutor: () => NativeWindowsSandboxExecutor,
|
|
969
|
+
LegacyWindowsSandboxExecutor: () => WindowsSandboxExecutor
|
|
970
|
+
});
|
|
971
|
+
var init_windows = __esm(() => {
|
|
972
|
+
init_native_sandbox_executor();
|
|
973
|
+
init_restricted_environment_executor();
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
// src/sandbox/executor.ts
|
|
977
|
+
function isValidEnvKey(key) {
|
|
978
|
+
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key);
|
|
979
|
+
}
|
|
980
|
+
async function getExecutor() {
|
|
981
|
+
if (_cachedExecutorPromise !== undefined) {
|
|
982
|
+
return _cachedExecutorPromise;
|
|
983
|
+
}
|
|
984
|
+
_cachedExecutorPromise = _createExecutor();
|
|
985
|
+
return _cachedExecutorPromise;
|
|
986
|
+
}
|
|
987
|
+
async function _createExecutor() {
|
|
988
|
+
const platform = process.platform;
|
|
989
|
+
if (platform === "linux") {
|
|
990
|
+
return _createLinuxExecutor();
|
|
991
|
+
}
|
|
992
|
+
if (platform === "darwin") {
|
|
993
|
+
return _createMacOSExecutor();
|
|
994
|
+
}
|
|
995
|
+
if (platform === "win32") {
|
|
996
|
+
return _createWindowsExecutor();
|
|
997
|
+
}
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
async function _createLinuxExecutor() {
|
|
1001
|
+
const { SandboxCapabilityProbe, isBubblewrapAvailable } = await import("./capability-probe-976tt4ba.js");
|
|
1002
|
+
await new SandboxCapabilityProbe().detect();
|
|
1003
|
+
if (!isBubblewrapAvailable()) {
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
try {
|
|
1007
|
+
const { BubblewrapSandboxExecutor: BubblewrapSandboxExecutor2 } = (init_bubblewrap(), __toCommonJS(exports_bubblewrap));
|
|
1008
|
+
return new BubblewrapSandboxExecutor2([]);
|
|
1009
|
+
} catch {
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
async function _createMacOSExecutor() {
|
|
1014
|
+
if (!_macosSandboxEnabled) {
|
|
1015
|
+
if (!_hasWarnedMacOSSandboxDisabledByConfig) {
|
|
1016
|
+
_hasWarnedMacOSSandboxDisabledByConfig = true;
|
|
1017
|
+
warn("[sandbox] macOS sandbox-exec is disabled by config (guardrails.sandbox_macos_enabled=false). " + "Enable it only after verifying the production SBPL profile on a real macOS host \u2014 see docs/configuration.md.");
|
|
1018
|
+
}
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
const { SandboxCapabilityProbe, isSandboxExecAvailable } = await import("./capability-probe-976tt4ba.js");
|
|
1022
|
+
await new SandboxCapabilityProbe().detect();
|
|
1023
|
+
if (!isSandboxExecAvailable()) {
|
|
1024
|
+
return null;
|
|
1025
|
+
}
|
|
1026
|
+
try {
|
|
1027
|
+
const { MacOSSandboxExecutor: MacOSSandboxExecutor2 } = (init_macos(), __toCommonJS(exports_macos));
|
|
1028
|
+
return new MacOSSandboxExecutor2([]);
|
|
1029
|
+
} catch {
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
async function _createWindowsExecutor() {
|
|
1034
|
+
const { SandboxCapabilityProbe, isWindowsSandboxAvailable } = await import("./capability-probe-976tt4ba.js");
|
|
1035
|
+
await new SandboxCapabilityProbe().detect();
|
|
1036
|
+
if (!isWindowsSandboxAvailable()) {
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
try {
|
|
1040
|
+
const { WindowsSandboxExecutor: WindowsSandboxExecutor2 } = (init_windows(), __toCommonJS(exports_windows));
|
|
1041
|
+
return new WindowsSandboxExecutor2([]);
|
|
1042
|
+
} catch {
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
var SandboxError, _cachedExecutorPromise, _macosSandboxEnabled = false, _hasWarnedMacOSSandboxDisabledByConfig = false;
|
|
1047
|
+
var init_executor = __esm(() => {
|
|
1048
|
+
init_logger();
|
|
1049
|
+
SandboxError = class SandboxError extends Error {
|
|
1050
|
+
code;
|
|
1051
|
+
constructor(message, code) {
|
|
1052
|
+
super(message);
|
|
1053
|
+
this.code = code;
|
|
1054
|
+
this.name = "SandboxError";
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
// src/sandbox/linux/bubblewrap-executor.ts
|
|
1060
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
1061
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1062
|
+
function resolveBwrapBinary() {
|
|
1063
|
+
try {
|
|
1064
|
+
if (existsSync3(BWRAP_ABSOLUTE)) {
|
|
1065
|
+
return BWRAP_ABSOLUTE;
|
|
1066
|
+
}
|
|
1067
|
+
} catch {}
|
|
1068
|
+
return "bwrap";
|
|
1069
|
+
}
|
|
1070
|
+
function probeBwrap() {
|
|
1071
|
+
try {
|
|
1072
|
+
const binary = _internals4.resolveBwrapBinary();
|
|
1073
|
+
const result = spawnSync4(binary, ["--version"], {
|
|
1074
|
+
windowsHide: true,
|
|
1075
|
+
encoding: "utf-8",
|
|
1076
|
+
timeout: 5000,
|
|
1077
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1078
|
+
});
|
|
1079
|
+
if (result.error) {
|
|
1080
|
+
const code = result.error.code;
|
|
1081
|
+
if (code && BWRAP_UNAVAILABLE_CODES.has(code)) {
|
|
1082
|
+
warn(`Sandbox disabled: bwrap error (${code}). Falling through to tool-layer enforcement.`);
|
|
1083
|
+
return false;
|
|
1084
|
+
}
|
|
1085
|
+
warn(`Sandbox disabled: bwrap spawn error (${result.error.message}). Falling through to tool-layer enforcement.`);
|
|
1086
|
+
return false;
|
|
1087
|
+
}
|
|
1088
|
+
return result.status === BWRAP_VERSION_EXIT && result.stdout.trim().length > 0;
|
|
1089
|
+
} catch (err) {
|
|
1090
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1091
|
+
warn(`Sandbox disabled: probe threw (${message}). Falling through to tool-layer enforcement.`);
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function shellEscape2(s) {
|
|
1096
|
+
return s.replace(/'/g, "'\\''");
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
class BubblewrapSandboxExecutor {
|
|
1100
|
+
mechanism = "Bubblewrap";
|
|
1101
|
+
_scopePaths;
|
|
1102
|
+
_tempDir;
|
|
1103
|
+
_available;
|
|
1104
|
+
_disabledReason;
|
|
1105
|
+
constructor(scopePaths = [], tempDir) {
|
|
1106
|
+
this._scopePaths = scopePaths;
|
|
1107
|
+
this._tempDir = tempDir;
|
|
1108
|
+
this._available = false;
|
|
1109
|
+
this._disabledReason = null;
|
|
1110
|
+
try {
|
|
1111
|
+
if (!_internals4.probeBwrap()) {
|
|
1112
|
+
this._disabledReason = "bwrap not available or not functional";
|
|
1113
|
+
warn(`Sandbox disabled: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
1114
|
+
} else {
|
|
1115
|
+
this._available = true;
|
|
1116
|
+
}
|
|
1117
|
+
} catch (err) {
|
|
1118
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1119
|
+
this._disabledReason = `constructor threw: ${message}`;
|
|
1120
|
+
this._available = false;
|
|
1121
|
+
warn(`Sandbox disabled: ${this._disabledReason}. Falling through to tool-layer enforcement.`);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
isAvailable() {
|
|
1125
|
+
return this._available;
|
|
1126
|
+
}
|
|
1127
|
+
disable(reason) {
|
|
1128
|
+
this._available = false;
|
|
1129
|
+
this._disabledReason = reason;
|
|
1130
|
+
warn(`Sandbox disabled: ${reason}. Falling through to tool-layer enforcement.`);
|
|
1131
|
+
}
|
|
1132
|
+
wrapCommand(command, scopePaths, tempDir, envOverrides) {
|
|
1133
|
+
if (!this._available) {
|
|
1134
|
+
throw new SandboxError("Sandbox not available", "SANDBOX_UNAVAILABLE");
|
|
1135
|
+
}
|
|
1136
|
+
const temp = tempDir ?? this._tempDir ?? "/tmp";
|
|
1137
|
+
const allScopes = [...this._scopePaths, ...scopePaths];
|
|
1138
|
+
const bindArgs = allScopes.flatMap((p) => [
|
|
1139
|
+
"--bind",
|
|
1140
|
+
`'${shellEscape2(p)}'`,
|
|
1141
|
+
`'${shellEscape2(p)}'`
|
|
1142
|
+
]);
|
|
1143
|
+
const envArgs = [];
|
|
1144
|
+
if (envOverrides) {
|
|
1145
|
+
for (const [key, value] of Object.entries(envOverrides)) {
|
|
1146
|
+
if (!isValidEnvKey(key)) {
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
if (value === null) {
|
|
1150
|
+
envArgs.push("--unsetenv", key);
|
|
1151
|
+
} else {
|
|
1152
|
+
envArgs.push("--setenv", key, `'${shellEscape2(value)}'`);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
const args = [
|
|
1157
|
+
"--unshare-user",
|
|
1158
|
+
"--unshare-net",
|
|
1159
|
+
"--unshare-ipc",
|
|
1160
|
+
"--die-with-parent",
|
|
1161
|
+
"--new-session",
|
|
1162
|
+
"--cap-drop",
|
|
1163
|
+
"ALL",
|
|
1164
|
+
...bindArgs,
|
|
1165
|
+
"--dev",
|
|
1166
|
+
"/dev",
|
|
1167
|
+
"--size",
|
|
1168
|
+
String(TMPFS_SIZE_BYTES),
|
|
1169
|
+
"--tmpfs",
|
|
1170
|
+
`'${shellEscape2(temp)}'`,
|
|
1171
|
+
"--ro-bind",
|
|
1172
|
+
"/etc",
|
|
1173
|
+
"/etc",
|
|
1174
|
+
"--ro-bind",
|
|
1175
|
+
"/usr",
|
|
1176
|
+
"/usr",
|
|
1177
|
+
"--ro-bind",
|
|
1178
|
+
"/lib",
|
|
1179
|
+
"/lib",
|
|
1180
|
+
"--ro-bind",
|
|
1181
|
+
"/lib64",
|
|
1182
|
+
"/lib64",
|
|
1183
|
+
"--proc",
|
|
1184
|
+
"/proc",
|
|
1185
|
+
"--unshare-pid",
|
|
1186
|
+
...envArgs,
|
|
1187
|
+
"--",
|
|
1188
|
+
"bash",
|
|
1189
|
+
"-c",
|
|
1190
|
+
`'${shellEscape2(command)}'`
|
|
1191
|
+
];
|
|
1192
|
+
const binary = _internals4.resolveBwrapBinary();
|
|
1193
|
+
return `${binary} ${args.join(" ")}`;
|
|
1194
|
+
}
|
|
1195
|
+
getEnvOverrides() {
|
|
1196
|
+
return {};
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
var BWRAP_VERSION_EXIT = 0, BWRAP_UNAVAILABLE_CODES, BWRAP_ABSOLUTE = "/usr/bin/bwrap", TMPFS_SIZE_BYTES = 524288000, _internals4;
|
|
1200
|
+
var init_bubblewrap_executor = __esm(() => {
|
|
1201
|
+
init_logger();
|
|
1202
|
+
init_executor();
|
|
1203
|
+
BWRAP_UNAVAILABLE_CODES = new Set(["ENOENT", "EACCES", "ENOSPC"]);
|
|
1204
|
+
_internals4 = {
|
|
1205
|
+
probeBwrap,
|
|
1206
|
+
resolveBwrapBinary
|
|
1207
|
+
};
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
export { _internals4 as _internals, init_bubblewrap_executor, _internals as _internals1, init_sandbox_exec_executor, exports_runner_client, init_runner_client, isValidEnvKey, getExecutor, init_executor };
|