@vibgrate/cli 2026.722.1 → 2026.727.1
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/DOCS.md +418 -196
- package/README.md +34 -7
- package/dist/baseline-K7YBFKZI.js +7 -0
- package/dist/{baseline-J44M7MWP.js.map → baseline-K7YBFKZI.js.map} +1 -1
- package/dist/chunk-3BVSDMHV.js +2496 -0
- package/dist/chunk-3BVSDMHV.js.map +1 -0
- package/dist/{chunk-PY3DNX5H.js → chunk-3Q7QBWFW.js} +13 -2
- package/dist/chunk-3Q7QBWFW.js.map +1 -0
- package/dist/chunk-4CQ3MGNN.js +136 -0
- package/dist/chunk-4CQ3MGNN.js.map +1 -0
- package/dist/chunk-5I4VSBWQ.js +764 -0
- package/dist/chunk-5I4VSBWQ.js.map +1 -0
- package/dist/chunk-5Q54GEHM.js +29 -0
- package/dist/chunk-5Q54GEHM.js.map +1 -0
- package/dist/{chunk-XKXKWYJF.js → chunk-65MEOA4E.js} +21 -18
- package/dist/chunk-65MEOA4E.js.map +1 -0
- package/dist/{chunk-WNIIKCNF.js → chunk-6IOQJGFT.js} +29 -238
- package/dist/chunk-6IOQJGFT.js.map +1 -0
- package/dist/{chunk-CS37OBE3.js → chunk-7JHPQ6WF.js} +791 -783
- package/dist/chunk-7JHPQ6WF.js.map +1 -0
- package/dist/chunk-BPF3YX2U.js +64 -0
- package/dist/chunk-BPF3YX2U.js.map +1 -0
- package/dist/chunk-BWPBB45M.js +88 -0
- package/dist/chunk-BWPBB45M.js.map +1 -0
- package/dist/chunk-C4CKTAZP.js +1695 -0
- package/dist/chunk-C4CKTAZP.js.map +1 -0
- package/dist/chunk-EDAAG7BL.js +612 -0
- package/dist/chunk-EDAAG7BL.js.map +1 -0
- package/dist/chunk-EDBV33B7.js +57 -0
- package/dist/chunk-EDBV33B7.js.map +1 -0
- package/dist/chunk-HABUT7HW.js +233 -0
- package/dist/chunk-HABUT7HW.js.map +1 -0
- package/dist/{chunk-EXQV26MF.js → chunk-HYZVHJ3Q.js} +3 -3
- package/dist/{chunk-EXQV26MF.js.map → chunk-HYZVHJ3Q.js.map} +1 -1
- package/dist/chunk-IS7VTH2Q.js +627 -0
- package/dist/chunk-IS7VTH2Q.js.map +1 -0
- package/dist/chunk-IZDH67DX.js +289 -0
- package/dist/chunk-IZDH67DX.js.map +1 -0
- package/dist/chunk-J7LKEB2R.js +51 -0
- package/dist/chunk-J7LKEB2R.js.map +1 -0
- package/dist/chunk-JIBOJTGS.js +313 -0
- package/dist/chunk-JIBOJTGS.js.map +1 -0
- package/dist/chunk-JZYGEZTU.js +82 -0
- package/dist/chunk-JZYGEZTU.js.map +1 -0
- package/dist/chunk-K7REHDQS.js +776 -0
- package/dist/chunk-K7REHDQS.js.map +1 -0
- package/dist/chunk-KHJO4D5N.js +108 -0
- package/dist/chunk-KHJO4D5N.js.map +1 -0
- package/dist/chunk-NDMDSPFX.js +69 -0
- package/dist/chunk-NDMDSPFX.js.map +1 -0
- package/dist/chunk-OOIG3RUM.js +276 -0
- package/dist/chunk-OOIG3RUM.js.map +1 -0
- package/dist/{chunk-6CXTPC74.js → chunk-OXQNQW5J.js} +27 -6
- package/dist/chunk-OXQNQW5J.js.map +1 -0
- package/dist/chunk-PMYWZRRS.js +62 -0
- package/dist/chunk-PMYWZRRS.js.map +1 -0
- package/dist/chunk-PXHNTC6D.js +382 -0
- package/dist/chunk-PXHNTC6D.js.map +1 -0
- package/dist/{chunk-VXT6LUGP.js → chunk-S6CYDZEW.js} +1395 -1975
- package/dist/chunk-S6CYDZEW.js.map +1 -0
- package/dist/chunk-SZLF66FJ.js +843 -0
- package/dist/chunk-SZLF66FJ.js.map +1 -0
- package/dist/chunk-VXGV6NTD.js +476 -0
- package/dist/chunk-VXGV6NTD.js.map +1 -0
- package/dist/{chunk-JSNHZCIV.js → chunk-WLETRGAC.js} +16 -9
- package/dist/chunk-WLETRGAC.js.map +1 -0
- package/dist/{chunk-2EVQKZTO.js → chunk-YDAT7LD2.js} +190 -13
- package/dist/chunk-YDAT7LD2.js.map +1 -0
- package/dist/cli.js +3451 -509
- package/dist/cli.js.map +1 -1
- package/dist/execution-env-3BN7Z737.js +3 -0
- package/dist/execution-env-3BN7Z737.js.map +1 -0
- package/dist/federation-EPZDUWCK.js +6 -0
- package/dist/federation-EPZDUWCK.js.map +1 -0
- package/dist/git-ref-HPRLUFFW.js +3 -0
- package/dist/git-ref-HPRLUFFW.js.map +1 -0
- package/dist/graph-backend-ZMSYOZMW.js +10 -0
- package/dist/graph-backend-ZMSYOZMW.js.map +1 -0
- package/dist/index.d.ts +432 -126
- package/dist/index.js +14 -7
- package/dist/index.js.map +1 -1
- package/dist/{interactive-736PBC7J.js → interactive-ICL7D7LO.js} +185 -365
- package/dist/interactive-ICL7D7LO.js.map +1 -0
- package/dist/llm-host-2RAYQSDQ.js +8 -0
- package/dist/llm-host-2RAYQSDQ.js.map +1 -0
- package/dist/load-OHVKDX4R.js +7 -0
- package/dist/load-OHVKDX4R.js.map +1 -0
- package/dist/local-runtime-OJFLX2HI.js +4 -0
- package/dist/local-runtime-OJFLX2HI.js.map +1 -0
- package/dist/model-execution-profile-MQ2QCP24.js +3 -0
- package/dist/model-execution-profile-MQ2QCP24.js.map +1 -0
- package/dist/model-orchestrator-FFTZI3U2.js +8 -0
- package/dist/model-orchestrator-FFTZI3U2.js.map +1 -0
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +1 -1
- package/dist/paths-MCH75O3G.js +5 -0
- package/dist/paths-MCH75O3G.js.map +1 -0
- package/dist/resolve-gguf-4UPIGPEE.js +7 -0
- package/dist/resolve-gguf-4UPIGPEE.js.map +1 -0
- package/dist/runtime-session-IDU5BDUJ.js +17 -0
- package/dist/runtime-session-IDU5BDUJ.js.map +1 -0
- package/dist/session-L2OSDRPI.js +10 -0
- package/dist/{session-POJUDFPH.js.map → session-L2OSDRPI.js.map} +1 -1
- package/dist/{stream-json-Q2JGWPHB.js → stream-json-F74W5FCK.js} +16 -6
- package/dist/stream-json-F74W5FCK.js.map +1 -0
- package/dist/{types-Jl6RJ175.d.ts → types-ZMg1mSuu.d.ts} +3 -1
- package/dist/vgd-EGBQD7BW.js +16 -0
- package/dist/vgd-EGBQD7BW.js.map +1 -0
- package/package.json +9 -6
- package/dist/baseline-J44M7MWP.js +0 -7
- package/dist/chunk-2EVQKZTO.js.map +0 -1
- package/dist/chunk-6CXTPC74.js.map +0 -1
- package/dist/chunk-CS37OBE3.js.map +0 -1
- package/dist/chunk-GGJZA3Q6.js +0 -961
- package/dist/chunk-GGJZA3Q6.js.map +0 -1
- package/dist/chunk-JBXNQCGE.js +0 -484
- package/dist/chunk-JBXNQCGE.js.map +0 -1
- package/dist/chunk-JSNHZCIV.js.map +0 -1
- package/dist/chunk-PY3DNX5H.js.map +0 -1
- package/dist/chunk-VXT6LUGP.js.map +0 -1
- package/dist/chunk-WNIIKCNF.js.map +0 -1
- package/dist/chunk-XKXKWYJF.js.map +0 -1
- package/dist/interactive-736PBC7J.js.map +0 -1
- package/dist/session-POJUDFPH.js +0 -6
- package/dist/stream-json-Q2JGWPHB.js.map +0 -1
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
import * as fs3 from 'fs';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import * as path3 from 'path';
|
|
4
|
+
import { spawnSync } from 'child_process';
|
|
5
|
+
|
|
6
|
+
// src/runtime/execution-env.ts
|
|
7
|
+
function buildFirecrackerConfig(paths, options) {
|
|
8
|
+
const bootArgs = [
|
|
9
|
+
"console=ttyS0",
|
|
10
|
+
"reboot=k",
|
|
11
|
+
"panic=1",
|
|
12
|
+
"pci=off",
|
|
13
|
+
"init=/sbin/vg-agent-init",
|
|
14
|
+
`vg_cmd=${encodeURIComponent(options.command)}`
|
|
15
|
+
];
|
|
16
|
+
if (options.denyNetwork !== false) bootArgs.push("vg_net=off");
|
|
17
|
+
const cfg = {
|
|
18
|
+
"boot-source": {
|
|
19
|
+
kernel_image_path: paths.kernel,
|
|
20
|
+
boot_args: bootArgs.join(" ")
|
|
21
|
+
},
|
|
22
|
+
drives: [
|
|
23
|
+
{
|
|
24
|
+
drive_id: "rootfs",
|
|
25
|
+
path_on_host: paths.rootfs,
|
|
26
|
+
is_root_device: true,
|
|
27
|
+
is_read_only: false
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"machine-config": {
|
|
31
|
+
vcpu_count: options.vcpuCount ?? 1,
|
|
32
|
+
mem_size_mib: options.memSizeMib ?? 512,
|
|
33
|
+
smt: false
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
cfg["vg-writable-roots"] = [...options.writableRoots].map((r) => path3.resolve(r)).sort((a, b) => a.localeCompare(b));
|
|
37
|
+
if (options.denyNetwork === false) {
|
|
38
|
+
cfg["network-interfaces"] = [
|
|
39
|
+
{
|
|
40
|
+
iface_id: "eth0",
|
|
41
|
+
guest_mac: "06:00:00:00:00:01",
|
|
42
|
+
host_dev_name: "vmtap0"
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
return cfg;
|
|
47
|
+
}
|
|
48
|
+
function firecrackerArgv(binary, configPath) {
|
|
49
|
+
return [binary, "--config-file", configPath, "--no-api"];
|
|
50
|
+
}
|
|
51
|
+
function resolveFirecrackerPaths(env = process.env, probeExists = (p) => {
|
|
52
|
+
try {
|
|
53
|
+
return fs3.existsSync(p);
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}) {
|
|
58
|
+
const binary = env.VIBGRATE_FIRECRACKER_BIN || which("firecracker") || "";
|
|
59
|
+
const kernel = env.VIBGRATE_FIRECRACKER_KERNEL || "";
|
|
60
|
+
const rootfs = env.VIBGRATE_FIRECRACKER_ROOTFS || "";
|
|
61
|
+
if (!binary || !kernel || !rootfs) return null;
|
|
62
|
+
if (!probeExists(binary) || !probeExists(kernel) || !probeExists(rootfs)) return null;
|
|
63
|
+
return { binary, kernel, rootfs };
|
|
64
|
+
}
|
|
65
|
+
function tryCreateFirecrackerEnv(options) {
|
|
66
|
+
const paths = options.paths === void 0 ? resolveFirecrackerPaths() : options.paths;
|
|
67
|
+
if (!paths) return null;
|
|
68
|
+
const denyNetwork = options.denyNetwork !== false;
|
|
69
|
+
const reason = options.reason ?? "L3 Firecracker microVM";
|
|
70
|
+
return {
|
|
71
|
+
tier: "L3",
|
|
72
|
+
label: "firecracker",
|
|
73
|
+
reason,
|
|
74
|
+
run(command, runOpts) {
|
|
75
|
+
const roots = options.writableRoots.length ? options.writableRoots : [runOpts.cwd];
|
|
76
|
+
const configPath = path3.join(
|
|
77
|
+
process.env.TMPDIR || "/tmp",
|
|
78
|
+
`vg-fc-${process.pid}-${Date.now()}.json`
|
|
79
|
+
);
|
|
80
|
+
const cfg = buildFirecrackerConfig(paths, {
|
|
81
|
+
writableRoots: roots,
|
|
82
|
+
command,
|
|
83
|
+
denyNetwork});
|
|
84
|
+
try {
|
|
85
|
+
fs3.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
86
|
+
`, {
|
|
87
|
+
encoding: "utf8",
|
|
88
|
+
mode: 384
|
|
89
|
+
});
|
|
90
|
+
const argv = firecrackerArgv(paths.binary, configPath);
|
|
91
|
+
const res = spawnSync(argv[0], argv.slice(1), {
|
|
92
|
+
encoding: "utf8",
|
|
93
|
+
timeout: runOpts.timeoutMs ?? 12e4,
|
|
94
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
95
|
+
env: process.env
|
|
96
|
+
});
|
|
97
|
+
const stdout = (res.stdout ?? "") + (res.stderr ? `
|
|
98
|
+
${res.stderr}` : "");
|
|
99
|
+
if (res.error) {
|
|
100
|
+
return {
|
|
101
|
+
stdout: `firecracker failed to start: ${res.error.message}`,
|
|
102
|
+
exitCode: 1
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return { stdout, exitCode: res.status ?? 1 };
|
|
106
|
+
} finally {
|
|
107
|
+
try {
|
|
108
|
+
fs3.unlinkSync(configPath);
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function which(bin) {
|
|
116
|
+
try {
|
|
117
|
+
const res = spawnSync(process.platform === "win32" ? "where" : "which", [bin], {
|
|
118
|
+
encoding: "utf8"
|
|
119
|
+
});
|
|
120
|
+
if (res.status !== 0) return null;
|
|
121
|
+
const line = (res.stdout ?? "").trim().split("\n")[0]?.trim();
|
|
122
|
+
return line || null;
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/runtime/sandbox-backend.ts
|
|
129
|
+
function detectSandboxCapabilities(platform = process.platform) {
|
|
130
|
+
const backends = [];
|
|
131
|
+
if (platform === "darwin") {
|
|
132
|
+
const seatbelt = commandOnPath("sandbox-exec");
|
|
133
|
+
backends.push({
|
|
134
|
+
id: "seatbelt",
|
|
135
|
+
tier: "L1",
|
|
136
|
+
available: seatbelt,
|
|
137
|
+
reason: seatbelt ? "sandbox-exec present" : "sandbox-exec not found"
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (platform === "linux") {
|
|
141
|
+
const bwrap = commandOnPath("bwrap");
|
|
142
|
+
backends.push({
|
|
143
|
+
id: "bwrap",
|
|
144
|
+
tier: "L1",
|
|
145
|
+
available: bwrap,
|
|
146
|
+
reason: bwrap ? "bubblewrap present" : "bwrap not found"
|
|
147
|
+
});
|
|
148
|
+
const firejail = commandOnPath("firejail");
|
|
149
|
+
backends.push({
|
|
150
|
+
id: "firejail",
|
|
151
|
+
tier: "L2",
|
|
152
|
+
available: firejail,
|
|
153
|
+
reason: firejail ? "firejail present" : "firejail not found"
|
|
154
|
+
});
|
|
155
|
+
const runsc = commandOnPath("runsc");
|
|
156
|
+
backends.push({
|
|
157
|
+
id: "gvisor",
|
|
158
|
+
tier: "L2",
|
|
159
|
+
available: runsc,
|
|
160
|
+
reason: runsc ? "gVisor runsc present" : "runsc not found"
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const fc = resolveFirecrackerPaths();
|
|
164
|
+
backends.push({
|
|
165
|
+
id: "firecracker",
|
|
166
|
+
tier: "L3",
|
|
167
|
+
available: !!fc,
|
|
168
|
+
reason: fc ? `Firecracker configured (${fc.binary})` : "Firecracker unset \u2014 set VIBGRATE_FIRECRACKER_BIN, _KERNEL, _ROOTFS"
|
|
169
|
+
});
|
|
170
|
+
backends.push({
|
|
171
|
+
id: "host",
|
|
172
|
+
tier: "L0",
|
|
173
|
+
available: true,
|
|
174
|
+
reason: "always available"
|
|
175
|
+
});
|
|
176
|
+
let bestTier = "L0";
|
|
177
|
+
for (const b of backends) {
|
|
178
|
+
if (!b.available) continue;
|
|
179
|
+
if (tierRank(b.tier) > tierRank(bestTier)) bestTier = b.tier;
|
|
180
|
+
}
|
|
181
|
+
return { platform, backends, bestTier };
|
|
182
|
+
}
|
|
183
|
+
function selectSandboxBackend(requested, caps = detectSandboxCapabilities()) {
|
|
184
|
+
const want = tierRank(requested);
|
|
185
|
+
const available = caps.backends.filter((b) => b.available);
|
|
186
|
+
const exact = available.find((b) => b.tier === requested && b.id !== "host");
|
|
187
|
+
if (exact) return exact;
|
|
188
|
+
const stronger = available.filter((b) => tierRank(b.tier) >= want && b.id !== "host").sort((a, b) => tierRank(a.tier) - tierRank(b.tier));
|
|
189
|
+
if (stronger[0]) return stronger[0];
|
|
190
|
+
const weaker = available.filter((b) => tierRank(b.tier) < want).sort((a, b) => tierRank(b.tier) - tierRank(a.tier));
|
|
191
|
+
if (weaker[0]) return weaker[0];
|
|
192
|
+
return available.find((b) => b.id === "host") ?? {
|
|
193
|
+
id: "host",
|
|
194
|
+
tier: "L0",
|
|
195
|
+
available: true,
|
|
196
|
+
reason: "fallback host"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function firejailArgv(writableRoots, command, options = {}) {
|
|
200
|
+
const args = [
|
|
201
|
+
"firejail",
|
|
202
|
+
"--quiet",
|
|
203
|
+
"--noprofile",
|
|
204
|
+
"--private-tmp",
|
|
205
|
+
"--nonewprivs",
|
|
206
|
+
"--nogroups"
|
|
207
|
+
];
|
|
208
|
+
if (options.denyNetwork !== false) args.push("--net=none");
|
|
209
|
+
for (const root of writableRoots) {
|
|
210
|
+
args.push(`--whitelist=${root}`);
|
|
211
|
+
}
|
|
212
|
+
if (options.cwd) args.push(`--whitelist=${options.cwd}`);
|
|
213
|
+
args.push("--", "/bin/sh", "-c", command);
|
|
214
|
+
return args;
|
|
215
|
+
}
|
|
216
|
+
function tierRank(t) {
|
|
217
|
+
if (t === "L0") return 0;
|
|
218
|
+
if (t === "L1") return 1;
|
|
219
|
+
if (t === "L2") return 2;
|
|
220
|
+
return 3;
|
|
221
|
+
}
|
|
222
|
+
function commandOnPath(bin) {
|
|
223
|
+
try {
|
|
224
|
+
const res = spawnSync(process.platform === "win32" ? "where" : "which", [bin], { encoding: "utf8" });
|
|
225
|
+
return res.status === 0 && Boolean(res.stdout?.trim());
|
|
226
|
+
} catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function gvisorArgv(paths, options) {
|
|
231
|
+
const args = [
|
|
232
|
+
paths.binary,
|
|
233
|
+
"--rootless=true",
|
|
234
|
+
"--network=" + (options.denyNetwork === false ? "host" : "none"),
|
|
235
|
+
"do",
|
|
236
|
+
"--rootfs-path",
|
|
237
|
+
paths.rootfs
|
|
238
|
+
];
|
|
239
|
+
for (const root of [...options.writableRoots].map((r) => path3.resolve(r)).sort()) {
|
|
240
|
+
args.push("--bind", `${root}:${root}:rw`);
|
|
241
|
+
}
|
|
242
|
+
if (options.cwd) {
|
|
243
|
+
args.push("--cwd", path3.resolve(options.cwd));
|
|
244
|
+
}
|
|
245
|
+
args.push("--", "/bin/sh", "-c", options.command);
|
|
246
|
+
return args;
|
|
247
|
+
}
|
|
248
|
+
function resolveGvisorPaths(env = process.env, probeExists = (p) => {
|
|
249
|
+
try {
|
|
250
|
+
return fs3.existsSync(p);
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}, which2 = whichBin) {
|
|
255
|
+
const binary = env.VIBGRATE_GVISOR_BIN || which2("runsc") || "";
|
|
256
|
+
const rootfs = env.VIBGRATE_GVISOR_ROOTFS || "";
|
|
257
|
+
if (!binary || !rootfs) return null;
|
|
258
|
+
if (!probeExists(binary) || !probeExists(rootfs)) return null;
|
|
259
|
+
return { binary, rootfs };
|
|
260
|
+
}
|
|
261
|
+
function tryCreateGvisorEnv(options) {
|
|
262
|
+
const paths = options.paths === void 0 ? resolveGvisorPaths() : options.paths;
|
|
263
|
+
if (!paths) return null;
|
|
264
|
+
const denyNetwork = options.denyNetwork !== false;
|
|
265
|
+
return {
|
|
266
|
+
tier: "L2",
|
|
267
|
+
label: "gvisor",
|
|
268
|
+
reason: options.reason ?? "L2 gVisor runsc",
|
|
269
|
+
run(command, runOpts) {
|
|
270
|
+
const roots = options.writableRoots.length ? options.writableRoots : [runOpts.cwd];
|
|
271
|
+
const argv = gvisorArgv(paths, {
|
|
272
|
+
writableRoots: roots,
|
|
273
|
+
command,
|
|
274
|
+
denyNetwork,
|
|
275
|
+
cwd: runOpts.cwd
|
|
276
|
+
});
|
|
277
|
+
const res = spawnSync(argv[0], argv.slice(1), {
|
|
278
|
+
encoding: "utf8",
|
|
279
|
+
timeout: runOpts.timeoutMs ?? 12e4,
|
|
280
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
281
|
+
env: process.env
|
|
282
|
+
});
|
|
283
|
+
if (res.error) {
|
|
284
|
+
return { stdout: `gvisor failed to start: ${res.error.message}`, exitCode: 1 };
|
|
285
|
+
}
|
|
286
|
+
const stdout = (res.stdout ?? "") + (res.stderr ? `
|
|
287
|
+
${res.stderr}` : "");
|
|
288
|
+
return { stdout, exitCode: res.status ?? 1 };
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function whichBin(bin) {
|
|
293
|
+
try {
|
|
294
|
+
const res = spawnSync(process.platform === "win32" ? "where" : "which", [bin], {
|
|
295
|
+
encoding: "utf8"
|
|
296
|
+
});
|
|
297
|
+
if (res.status !== 0) return null;
|
|
298
|
+
return (res.stdout ?? "").trim().split("\n")[0]?.trim() || null;
|
|
299
|
+
} catch {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/runtime/execution-env.ts
|
|
305
|
+
function detectSecurityCapabilities(platform = process.platform) {
|
|
306
|
+
if (platform === "linux") {
|
|
307
|
+
return {
|
|
308
|
+
platform,
|
|
309
|
+
landlock: linuxLandlockAvailable(),
|
|
310
|
+
seatbelt: false,
|
|
311
|
+
bubblewrap: commandOnPath2("bwrap"),
|
|
312
|
+
firejail: commandOnPath2("firejail"),
|
|
313
|
+
gvisor: commandOnPath2("runsc")
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
if (platform === "darwin") {
|
|
317
|
+
return {
|
|
318
|
+
platform,
|
|
319
|
+
landlock: false,
|
|
320
|
+
seatbelt: macSeatbeltAvailable(),
|
|
321
|
+
bubblewrap: false,
|
|
322
|
+
firejail: false,
|
|
323
|
+
gvisor: false
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
return { platform, landlock: false, seatbelt: false, bubblewrap: false, firejail: false, gvisor: false };
|
|
327
|
+
}
|
|
328
|
+
function resolveExecutionEnv(requested = "L0", options = {}) {
|
|
329
|
+
const caps = options.capabilities ?? detectSecurityCapabilities();
|
|
330
|
+
const writableRoots = normalizeRoots(options.writableRoots);
|
|
331
|
+
const denyNetwork = options.denyNetwork !== false;
|
|
332
|
+
if (requested === "L0") return createHostExecutionEnv("explicit L0");
|
|
333
|
+
if (requested === "L3") {
|
|
334
|
+
const l3 = tryCreateFirecrackerEnv({
|
|
335
|
+
writableRoots,
|
|
336
|
+
denyNetwork,
|
|
337
|
+
reason: "L3 Firecracker microVM"
|
|
338
|
+
});
|
|
339
|
+
if (l3) return l3;
|
|
340
|
+
const l2 = tryCreateL2Env(caps, writableRoots, denyNetwork, requested);
|
|
341
|
+
if (l2) return l2;
|
|
342
|
+
const l1 = tryCreateL1Env(caps, writableRoots, denyNetwork, requested);
|
|
343
|
+
if (l1) return l1;
|
|
344
|
+
return createHostExecutionEnv("L3 not available (Firecracker images unset) \u2014 falling back to L0");
|
|
345
|
+
}
|
|
346
|
+
if (requested === "L2") {
|
|
347
|
+
const l2 = tryCreateL2Env(caps, writableRoots, denyNetwork, requested);
|
|
348
|
+
if (l2) return l2;
|
|
349
|
+
const l1 = tryCreateL1Env(caps, writableRoots, denyNetwork, requested);
|
|
350
|
+
if (l1) return l1;
|
|
351
|
+
return createHostExecutionEnv(`${requested} not available \u2014 falling back to L0`);
|
|
352
|
+
}
|
|
353
|
+
if (requested === "L1") {
|
|
354
|
+
const l1 = tryCreateL1Env(caps, writableRoots, denyNetwork, requested);
|
|
355
|
+
if (l1) return l1;
|
|
356
|
+
return createHostExecutionEnv("L1 requested but no Seatbelt/bubblewrap \u2014 falling back to L0");
|
|
357
|
+
}
|
|
358
|
+
return createHostExecutionEnv("unknown tier \u2014 falling back to L0");
|
|
359
|
+
}
|
|
360
|
+
function createHostExecutionEnv(reason = "host process") {
|
|
361
|
+
return {
|
|
362
|
+
tier: "L0",
|
|
363
|
+
label: "host",
|
|
364
|
+
reason,
|
|
365
|
+
run(command, options) {
|
|
366
|
+
return hostRun(command, options);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function buildSeatbeltProfile(writableRoots, options = {}) {
|
|
371
|
+
const roots = uniqueResolved([...writableRoots, ...options.tempRoots ?? defaultTempRoots()]);
|
|
372
|
+
const lines = [
|
|
373
|
+
"(version 1)",
|
|
374
|
+
"(deny default)",
|
|
375
|
+
"(allow process*)",
|
|
376
|
+
"(allow sysctl-read)",
|
|
377
|
+
"(allow mach*)",
|
|
378
|
+
"(allow system-socket)",
|
|
379
|
+
"(allow file-read*)",
|
|
380
|
+
'(allow file-write-data (literal "/dev/null"))',
|
|
381
|
+
'(allow file-write-data (literal "/dev/zero"))',
|
|
382
|
+
"(allow file-ioctl)",
|
|
383
|
+
'(allow file-write* (literal "/dev/tty"))',
|
|
384
|
+
'(allow file-write* (literal "/dev/dtracehelper"))'
|
|
385
|
+
];
|
|
386
|
+
for (const root of roots) {
|
|
387
|
+
const escaped = escapeSeatbeltPath(root);
|
|
388
|
+
lines.push(`(allow file-write* (subpath "${escaped}"))`);
|
|
389
|
+
if (root.startsWith("/var/") || root.startsWith("/tmp")) {
|
|
390
|
+
lines.push(`(allow file-write* (subpath "${escapeSeatbeltPath(`/private${root}`)}"))`);
|
|
391
|
+
}
|
|
392
|
+
if (root.startsWith("/private/var/") || root.startsWith("/private/tmp")) {
|
|
393
|
+
const short = root.slice("/private".length);
|
|
394
|
+
lines.push(`(allow file-write* (subpath "${escapeSeatbeltPath(short)}"))`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (options.denyNetwork !== false) {
|
|
398
|
+
lines.push("(deny network*)");
|
|
399
|
+
} else {
|
|
400
|
+
lines.push("(allow network*)");
|
|
401
|
+
}
|
|
402
|
+
lines.push("(allow ipc*)");
|
|
403
|
+
lines.push("(allow signal)");
|
|
404
|
+
lines.push("(allow pseudo-tty)");
|
|
405
|
+
return `${lines.join("\n")}
|
|
406
|
+
`;
|
|
407
|
+
}
|
|
408
|
+
function seatbeltArgv(profilePath, command) {
|
|
409
|
+
return ["sandbox-exec", "-f", profilePath, "/bin/sh", "-c", command];
|
|
410
|
+
}
|
|
411
|
+
function bubblewrapArgv(writableRoots, command, options = {}) {
|
|
412
|
+
const args = [
|
|
413
|
+
"bwrap",
|
|
414
|
+
"--die-with-parent",
|
|
415
|
+
"--ro-bind",
|
|
416
|
+
"/",
|
|
417
|
+
"/",
|
|
418
|
+
"--dev",
|
|
419
|
+
"/dev",
|
|
420
|
+
"--proc",
|
|
421
|
+
"/proc",
|
|
422
|
+
"--tmpfs",
|
|
423
|
+
"/tmp"
|
|
424
|
+
];
|
|
425
|
+
const roots = uniqueResolved(writableRoots);
|
|
426
|
+
for (const root of roots) {
|
|
427
|
+
args.push("--bind", root, root);
|
|
428
|
+
}
|
|
429
|
+
for (const t of defaultTempRoots()) {
|
|
430
|
+
if (fs3.existsSync(t)) args.push("--bind", t, t);
|
|
431
|
+
}
|
|
432
|
+
if (options.denyNetwork !== false) {
|
|
433
|
+
args.push("--unshare-net");
|
|
434
|
+
}
|
|
435
|
+
if (options.cwd) {
|
|
436
|
+
args.push("--chdir", options.cwd);
|
|
437
|
+
}
|
|
438
|
+
args.push("--", "/bin/sh", "-c", command);
|
|
439
|
+
return args;
|
|
440
|
+
}
|
|
441
|
+
function tryCreateL2Env(caps, writableRoots, denyNetwork, requested) {
|
|
442
|
+
if (caps.firejail) {
|
|
443
|
+
return createFirejailEnv(
|
|
444
|
+
requested === "L2" ? "L2 firejail process jail" : `${requested} requested; using L2 firejail`,
|
|
445
|
+
writableRoots,
|
|
446
|
+
denyNetwork
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
if (caps.gvisor) {
|
|
450
|
+
const gv = tryCreateGvisorEnv({
|
|
451
|
+
writableRoots,
|
|
452
|
+
denyNetwork,
|
|
453
|
+
reason: requested === "L2" ? "L2 gVisor runsc" : `${requested} requested; using L2 gVisor`
|
|
454
|
+
});
|
|
455
|
+
if (gv) return gv;
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
function tryCreateL1Env(caps, writableRoots, denyNetwork, requested) {
|
|
460
|
+
if (caps.seatbelt) {
|
|
461
|
+
return createSeatbeltEnv(
|
|
462
|
+
requested === "L1" ? "L1 Seatbelt (sandbox-exec) path isolation" : `${requested} requested; using L1 Seatbelt (sandbox-exec)`,
|
|
463
|
+
writableRoots,
|
|
464
|
+
denyNetwork
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
if (caps.bubblewrap) {
|
|
468
|
+
return createBubblewrapEnv(
|
|
469
|
+
requested === "L1" ? "L1 bubblewrap path isolation" : `${requested} requested; using L1 bubblewrap`,
|
|
470
|
+
writableRoots,
|
|
471
|
+
denyNetwork,
|
|
472
|
+
caps.landlock
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
if (caps.landlock) {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
function createFirejailEnv(reason, writableRoots, denyNetwork) {
|
|
481
|
+
return {
|
|
482
|
+
tier: "L2",
|
|
483
|
+
label: "firejail",
|
|
484
|
+
reason,
|
|
485
|
+
run(command, options) {
|
|
486
|
+
const roots = writableRoots.length ? writableRoots : [options.cwd];
|
|
487
|
+
if (!roots.some((r) => isPathInside(options.cwd, r))) {
|
|
488
|
+
roots.push(path3.resolve(options.cwd));
|
|
489
|
+
}
|
|
490
|
+
const argv = firejailArgv(roots, command, { denyNetwork, cwd: options.cwd });
|
|
491
|
+
const res = spawnSync(argv[0], argv.slice(1), {
|
|
492
|
+
encoding: "utf8",
|
|
493
|
+
timeout: options.timeoutMs ?? 12e4,
|
|
494
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
495
|
+
env: process.env
|
|
496
|
+
});
|
|
497
|
+
const stdout = (res.stdout ?? "") + (res.stderr ? `
|
|
498
|
+
${res.stderr}` : "");
|
|
499
|
+
return { stdout, exitCode: res.status ?? 1 };
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function createSeatbeltEnv(reason, writableRoots, denyNetwork) {
|
|
504
|
+
return {
|
|
505
|
+
tier: "L1",
|
|
506
|
+
label: "seatbelt",
|
|
507
|
+
reason,
|
|
508
|
+
run(command, options) {
|
|
509
|
+
const roots = writableRoots.length ? writableRoots : [options.cwd];
|
|
510
|
+
const profile = buildSeatbeltProfile(roots, { denyNetwork });
|
|
511
|
+
const profilePath = path3.join(os.tmpdir(), `vg-seatbelt-${process.pid}-${Date.now()}.sb`);
|
|
512
|
+
try {
|
|
513
|
+
fs3.writeFileSync(profilePath, profile, { encoding: "utf8", mode: 384 });
|
|
514
|
+
const argv = seatbeltArgv(profilePath, command);
|
|
515
|
+
const res = spawnSync(argv[0], argv.slice(1), {
|
|
516
|
+
cwd: options.cwd,
|
|
517
|
+
encoding: "utf8",
|
|
518
|
+
timeout: options.timeoutMs ?? 12e4,
|
|
519
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
520
|
+
env: process.env
|
|
521
|
+
});
|
|
522
|
+
const stdout = (res.stdout ?? "") + (res.stderr ? `
|
|
523
|
+
${res.stderr}` : "");
|
|
524
|
+
return { stdout, exitCode: res.status ?? 1 };
|
|
525
|
+
} finally {
|
|
526
|
+
try {
|
|
527
|
+
fs3.unlinkSync(profilePath);
|
|
528
|
+
} catch {
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
function createBubblewrapEnv(reason, writableRoots, denyNetwork, landlockPresent) {
|
|
535
|
+
return {
|
|
536
|
+
tier: "L1",
|
|
537
|
+
label: landlockPresent ? "bwrap+landlock-host" : "bwrap",
|
|
538
|
+
reason,
|
|
539
|
+
run(command, options) {
|
|
540
|
+
const roots = writableRoots.length ? writableRoots : [options.cwd];
|
|
541
|
+
if (!roots.some((r) => isPathInside(options.cwd, r))) {
|
|
542
|
+
roots.push(path3.resolve(options.cwd));
|
|
543
|
+
}
|
|
544
|
+
const argv = bubblewrapArgv(roots, command, { denyNetwork, cwd: options.cwd });
|
|
545
|
+
const res = spawnSync(argv[0], argv.slice(1), {
|
|
546
|
+
encoding: "utf8",
|
|
547
|
+
timeout: options.timeoutMs ?? 12e4,
|
|
548
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
549
|
+
env: process.env
|
|
550
|
+
});
|
|
551
|
+
const stdout = (res.stdout ?? "") + (res.stderr ? `
|
|
552
|
+
${res.stderr}` : "");
|
|
553
|
+
return { stdout, exitCode: res.status ?? 1 };
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function hostRun(command, options) {
|
|
558
|
+
const res = spawnSync(command, {
|
|
559
|
+
cwd: options.cwd,
|
|
560
|
+
shell: true,
|
|
561
|
+
encoding: "utf8",
|
|
562
|
+
timeout: options.timeoutMs ?? 12e4,
|
|
563
|
+
maxBuffer: 10 * 1024 * 1024
|
|
564
|
+
});
|
|
565
|
+
const stdout = (res.stdout ?? "") + (res.stderr ? `
|
|
566
|
+
${res.stderr}` : "");
|
|
567
|
+
return { stdout, exitCode: res.status ?? 1 };
|
|
568
|
+
}
|
|
569
|
+
function linuxLandlockAvailable() {
|
|
570
|
+
try {
|
|
571
|
+
return fs3.existsSync("/sys/kernel/security/landlock") || fs3.existsSync("/proc/sys/kernel/landlock");
|
|
572
|
+
} catch {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function macSeatbeltAvailable() {
|
|
577
|
+
return commandOnPath2("sandbox-exec");
|
|
578
|
+
}
|
|
579
|
+
function commandOnPath2(bin) {
|
|
580
|
+
try {
|
|
581
|
+
const res = spawnSync(process.platform === "win32" ? "where" : "which", [bin], { encoding: "utf8" });
|
|
582
|
+
return res.status === 0 && Boolean(res.stdout?.trim());
|
|
583
|
+
} catch {
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function defaultTempRoots() {
|
|
588
|
+
const roots = [];
|
|
589
|
+
try {
|
|
590
|
+
roots.push(os.tmpdir());
|
|
591
|
+
} catch {
|
|
592
|
+
}
|
|
593
|
+
if (process.env.TMPDIR) roots.push(process.env.TMPDIR);
|
|
594
|
+
if (process.env.TMP) roots.push(process.env.TMP);
|
|
595
|
+
if (process.env.TEMP) roots.push(process.env.TEMP);
|
|
596
|
+
roots.push("/tmp", "/private/tmp");
|
|
597
|
+
return uniqueResolved(roots.filter((r) => typeof r === "string" && r.length > 0));
|
|
598
|
+
}
|
|
599
|
+
function normalizeRoots(roots) {
|
|
600
|
+
if (!roots?.length) return [];
|
|
601
|
+
return uniqueResolved(roots.filter((r) => typeof r === "string" && r.trim()).map((r) => r.trim()));
|
|
602
|
+
}
|
|
603
|
+
function uniqueResolved(paths) {
|
|
604
|
+
const seen = /* @__PURE__ */ new Set();
|
|
605
|
+
const out = [];
|
|
606
|
+
for (const p of paths) {
|
|
607
|
+
try {
|
|
608
|
+
const abs = path3.resolve(p);
|
|
609
|
+
if (seen.has(abs)) continue;
|
|
610
|
+
seen.add(abs);
|
|
611
|
+
out.push(abs);
|
|
612
|
+
} catch {
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
616
|
+
}
|
|
617
|
+
function escapeSeatbeltPath(p) {
|
|
618
|
+
return p.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
619
|
+
}
|
|
620
|
+
function isPathInside(child, parent) {
|
|
621
|
+
const rel = path3.relative(path3.resolve(parent), path3.resolve(child));
|
|
622
|
+
return rel === "" || !rel.startsWith("..") && !path3.isAbsolute(rel);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export { bubblewrapArgv, buildSeatbeltProfile, createHostExecutionEnv, detectSandboxCapabilities, detectSecurityCapabilities, firejailArgv, resolveExecutionEnv, seatbeltArgv, selectSandboxBackend };
|
|
626
|
+
//# sourceMappingURL=chunk-IS7VTH2Q.js.map
|
|
627
|
+
//# sourceMappingURL=chunk-IS7VTH2Q.js.map
|