@h-rig/isolation-plugin 0.0.6-alpha.157 → 0.0.6-alpha.159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/src/embedded-native-assets.d.ts +7 -0
  2. package/dist/src/embedded-native-assets.js +6 -0
  3. package/dist/src/image-fingerprint-sidecar.d.ts +1 -0
  4. package/dist/src/image-fingerprint-sidecar.js +515 -0
  5. package/dist/src/image.d.ts +40 -0
  6. package/dist/src/image.js +1498 -0
  7. package/dist/src/index.js +4220 -20
  8. package/dist/src/isolation/binary-build-worker.d.ts +1 -0
  9. package/dist/src/isolation/binary-build-worker.js +323 -0
  10. package/dist/src/isolation/discovery.d.ts +7 -0
  11. package/dist/src/isolation/discovery.js +477 -0
  12. package/dist/src/isolation/git-native.d.ts +28 -0
  13. package/dist/src/isolation/git-native.js +598 -0
  14. package/dist/src/isolation/home.d.ts +25 -0
  15. package/dist/src/isolation/home.js +929 -0
  16. package/dist/src/isolation/index.d.ts +43 -0
  17. package/dist/src/isolation/index.js +4062 -0
  18. package/dist/src/isolation/provisioning-env.d.ts +1 -0
  19. package/dist/src/isolation/provisioning-env.js +6 -0
  20. package/dist/src/isolation/runner.d.ts +20 -0
  21. package/dist/src/isolation/runner.js +1881 -0
  22. package/dist/src/isolation/runtime-binary-build.d.ts +88 -0
  23. package/dist/src/isolation/runtime-binary-build.js +480 -0
  24. package/dist/src/isolation/shared.d.ts +29 -0
  25. package/dist/src/isolation/shared.js +283 -0
  26. package/dist/src/isolation/toolchain.d.ts +71 -0
  27. package/dist/src/isolation/toolchain.js +1348 -0
  28. package/dist/src/isolation/types.d.ts +15 -0
  29. package/dist/src/isolation/types.js +1 -0
  30. package/dist/src/isolation/worktree.d.ts +22 -0
  31. package/dist/src/isolation/worktree.js +353 -0
  32. package/dist/src/native-extract.d.ts +2 -0
  33. package/dist/src/native-extract.js +44 -0
  34. package/dist/src/plugin.d.ts +2 -2
  35. package/dist/src/plugin.js +4219 -19
  36. package/dist/src/runtime-config.d.ts +3 -0
  37. package/dist/src/runtime-config.js +215 -0
  38. package/dist/src/runtime-native-sidecar.d.ts +8 -0
  39. package/dist/src/runtime-native-sidecar.js +368 -0
  40. package/dist/src/runtime-native.d.ts +51 -0
  41. package/dist/src/runtime-native.js +485 -0
  42. package/dist/src/sandbox/backend-bwrap.d.ts +20 -0
  43. package/dist/src/sandbox/backend-bwrap.js +268 -0
  44. package/dist/src/sandbox/backend-none.d.ts +11 -0
  45. package/dist/src/sandbox/backend-none.js +20 -0
  46. package/dist/src/sandbox/backend-seatbelt.d.ts +13 -0
  47. package/dist/src/sandbox/backend-seatbelt.js +225 -0
  48. package/dist/src/sandbox/backend.d.ts +117 -0
  49. package/dist/src/sandbox/backend.js +864 -0
  50. package/dist/src/sandbox/orchestrator.d.ts +21 -0
  51. package/dist/src/sandbox/orchestrator.js +895 -0
  52. package/dist/src/sandbox/utils.d.ts +43 -0
  53. package/dist/src/sandbox/utils.js +94 -0
  54. package/dist/src/service.d.ts +10 -5
  55. package/dist/src/service.js +4145 -2
  56. package/dist/src/sidecar-arg.d.ts +7 -0
  57. package/dist/src/sidecar-arg.js +6 -0
  58. package/dist/src/sidecar-entrypoint.d.ts +9 -0
  59. package/dist/src/sidecar-entrypoint.js +401 -0
  60. package/dist/src/snapshot-sidecar.d.ts +2 -0
  61. package/dist/src/snapshot-sidecar.js +566 -0
  62. package/dist/src/snapshot.d.ts +64 -0
  63. package/dist/src/snapshot.js +515 -0
  64. package/dist/src/task-run-snapshot.d.ts +26 -0
  65. package/dist/src/task-run-snapshot.js +713 -0
  66. package/native/darwin-arm64/rig-git +0 -0
  67. package/native/darwin-arm64/rig-git.build-manifest.json +4 -0
  68. package/native/darwin-arm64/runtime-native.dylib +0 -0
  69. package/native/darwin-x64/rig-git +0 -0
  70. package/native/darwin-x64/runtime-native.dylib +0 -0
  71. package/native/linux-arm64/rig-git +0 -0
  72. package/native/linux-arm64/runtime-native.so +0 -0
  73. package/native/linux-x64/rig-git +0 -0
  74. package/native/linux-x64/runtime-native.so +0 -0
  75. package/native/win32-x64/rig-git.exe +0 -0
  76. package/native/win32-x64/runtime-native.dll +0 -0
  77. package/package.json +45 -5
@@ -0,0 +1,864 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ function __accessProp(key) {
7
+ return this[key];
8
+ }
9
+ var __toCommonJS = (from) => {
10
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
11
+ if (entry)
12
+ return entry;
13
+ entry = __defProp({}, "__esModule", { value: true });
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (var key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(entry, key))
17
+ __defProp(entry, key, {
18
+ get: __accessProp.bind(from, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ __moduleCache.set(from, entry);
23
+ return entry;
24
+ };
25
+ var __moduleCache;
26
+ var __returnValue = (v) => v;
27
+ function __exportSetter(name, newValue) {
28
+ this[name] = __returnValue.bind(null, newValue);
29
+ }
30
+ var __export = (target, all) => {
31
+ for (var name in all)
32
+ __defProp(target, name, {
33
+ get: all[name],
34
+ enumerable: true,
35
+ configurable: true,
36
+ set: __exportSetter.bind(all, name)
37
+ });
38
+ };
39
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
40
+ var __require = import.meta.require;
41
+
42
+ // packages/isolation-plugin/src/sandbox/utils.ts
43
+ import { existsSync as existsSync2, readdirSync, realpathSync } from "fs";
44
+ import { resolve as resolve2 } from "path";
45
+ import { resolveMonorepoRoot } from "@rig/core/layout";
46
+ function toRealPath(path) {
47
+ if (!existsSync2(path)) {
48
+ return resolve2(path);
49
+ }
50
+ try {
51
+ return realpathSync.native(path);
52
+ } catch {
53
+ return resolve2(path);
54
+ }
55
+ }
56
+ function resolveHostGitMetadataPaths(projectRoot, workspaceDir) {
57
+ const candidates = new Set;
58
+ const addPath = (candidate) => {
59
+ if (existsSync2(candidate)) {
60
+ candidates.add(toRealPath(candidate));
61
+ }
62
+ };
63
+ addPath(resolve2(projectRoot, ".git"));
64
+ addPath(resolve2(workspaceDir, "..", "..", ".git"));
65
+ for (const repoRoot of resolveHostRepoRootPaths(projectRoot)) {
66
+ addPath(resolve2(repoRoot, ".git"));
67
+ }
68
+ const workspaceGit = resolve2(workspaceDir, ".git");
69
+ if (existsSync2(workspaceGit)) {
70
+ addPath(workspaceGit);
71
+ }
72
+ return [...candidates];
73
+ }
74
+ function resolveHostRepoRootPaths(projectRoot) {
75
+ const candidates = new Set;
76
+ const addPath = (candidate) => {
77
+ if (existsSync2(candidate)) {
78
+ candidates.add(toRealPath(candidate));
79
+ }
80
+ };
81
+ try {
82
+ const monorepoRoot = resolveMonorepoRoot(projectRoot);
83
+ if (toRealPath(monorepoRoot) !== toRealPath(projectRoot)) {
84
+ addPath(monorepoRoot);
85
+ }
86
+ } catch {}
87
+ const reposDir = resolve2(projectRoot, "repos");
88
+ if (existsSync2(reposDir)) {
89
+ for (const entry of readdirSync(reposDir, { withFileTypes: true })) {
90
+ if (entry.isDirectory() || entry.isSymbolicLink()) {
91
+ addPath(resolve2(reposDir, entry.name));
92
+ }
93
+ }
94
+ }
95
+ return [...candidates];
96
+ }
97
+ function resolveNetworkWithPolicy(sandboxConfig, envOverride) {
98
+ if (envOverride) {
99
+ const envValue = parseBooleanEnv(envOverride, sandboxConfig.network);
100
+ if (envValue !== sandboxConfig.network) {
101
+ console.warn(`[sandbox] RIG_RUNTIME_SANDBOX_NETWORK=${envOverride} overrides policy sandbox.network=${sandboxConfig.network}`);
102
+ }
103
+ return envValue;
104
+ }
105
+ return sandboxConfig.network;
106
+ }
107
+ function parseBooleanEnv(raw, fallback) {
108
+ if (!raw) {
109
+ return fallback;
110
+ }
111
+ const normalized = raw.trim().toLowerCase();
112
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
113
+ return true;
114
+ }
115
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
116
+ return false;
117
+ }
118
+ return fallback;
119
+ }
120
+ function uniq(values) {
121
+ return [...new Set(values)];
122
+ }
123
+ function seatbeltString(value) {
124
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
125
+ }
126
+ var init_utils = () => {};
127
+
128
+ // packages/isolation-plugin/src/sandbox/backend-seatbelt.ts
129
+ var exports_backend_seatbelt = {};
130
+ __export(exports_backend_seatbelt, {
131
+ SeatbeltBackend: () => SeatbeltBackend
132
+ });
133
+ import { mkdirSync, writeFileSync } from "fs";
134
+ import { resolve as resolve3 } from "path";
135
+
136
+ class SeatbeltBackend {
137
+ kind = "macos-seatbelt";
138
+ binaryPath;
139
+ config;
140
+ ctx;
141
+ resolvedPaths;
142
+ constructor(binaryPath, config, ctx, resolvedPaths) {
143
+ this.binaryPath = binaryPath;
144
+ this.config = config;
145
+ this.ctx = ctx;
146
+ this.resolvedPaths = resolvedPaths;
147
+ }
148
+ wrap(options) {
149
+ const profilePath = this.writeSeatbeltProfile(options);
150
+ return {
151
+ command: [this.binaryPath, "-f", profilePath, ...options.command],
152
+ enabled: true,
153
+ backend: "macos-seatbelt",
154
+ profilePath
155
+ };
156
+ }
157
+ writeSeatbeltProfile(options) {
158
+ const sandboxDir = resolve3(options.runtime.rootDir, "sandbox");
159
+ mkdirSync(sandboxDir, { recursive: true });
160
+ const profilePath = resolve3(sandboxDir, "seatbelt.sb");
161
+ const profile = this.renderProfile(options);
162
+ writeFileSync(profilePath, `${profile}
163
+ `, "utf-8");
164
+ return profilePath;
165
+ }
166
+ renderProfile(options) {
167
+ const { runtime, projectRoot } = options;
168
+ const { ctx, resolvedPaths, config } = this;
169
+ const workspaceReal = ctx.realPath(runtime.workspaceDir);
170
+ const runtimeRootReal = ctx.realPath(runtime.rootDir);
171
+ const homeReal = ctx.realPath(runtime.homeDir);
172
+ const tmpReal = ctx.realPath(runtime.tmpDir);
173
+ const cacheReal = ctx.realPath(runtime.cacheDir);
174
+ const hostGitDirs = resolveHostGitMetadataPaths(projectRoot, runtime.workspaceDir);
175
+ const hostRepoRoots = resolveHostRepoRootPaths(projectRoot).map((repoRoot) => ctx.realPath(repoRoot));
176
+ const bunDir = ctx.realPath(resolvedPaths.bunDir);
177
+ const claudeDir = resolvedPaths.claudeDir ? ctx.realPath(resolvedPaths.claudeDir) : null;
178
+ const allowNetwork = resolveNetworkWithPolicy(config, process.env.RIG_RUNTIME_SANDBOX_NETWORK);
179
+ const lines = [
180
+ "(version 1)",
181
+ "(deny default)",
182
+ '(import "system.sb")',
183
+ "(allow process*)",
184
+ "(allow process-info*)",
185
+ "(allow signal)",
186
+ "(allow sysctl-read)",
187
+ "(allow file-read-metadata)"
188
+ ];
189
+ if (allowNetwork) {
190
+ lines.push("(allow network*)");
191
+ }
192
+ for (const sysPath of [
193
+ "/usr/lib",
194
+ "/usr/bin",
195
+ "/usr/sbin",
196
+ "/usr/share",
197
+ "/bin",
198
+ "/sbin",
199
+ "/System",
200
+ "/Library",
201
+ "/Library/Frameworks",
202
+ "/Library/Developer",
203
+ "/Library/Apple",
204
+ "/Applications",
205
+ "/private/var/db",
206
+ "/opt/homebrew"
207
+ ]) {
208
+ lines.push(`(allow file-read* (subpath ${seatbeltString(sysPath)}))`);
209
+ }
210
+ lines.push(`(allow file-read* (subpath ${seatbeltString(bunDir)}))`);
211
+ if (claudeDir) {
212
+ lines.push(`(allow file-read* (subpath ${seatbeltString(claudeDir)}))`);
213
+ }
214
+ if (resolvedPaths.nodeDir) {
215
+ lines.push(`(allow file-read* (subpath ${seatbeltString(resolvedPaths.nodeDir)}))`);
216
+ }
217
+ for (const depPath of resolvedPaths.depRoots) {
218
+ lines.push(`(allow file-read* (subpath ${seatbeltString(depPath)}))`);
219
+ }
220
+ for (const rwPath of uniq([
221
+ workspaceReal,
222
+ runtimeRootReal,
223
+ homeReal,
224
+ tmpReal,
225
+ cacheReal
226
+ ])) {
227
+ lines.push(`(allow file-read* (subpath ${seatbeltString(rwPath)}))`);
228
+ lines.push(`(allow file-write* (subpath ${seatbeltString(rwPath)}))`);
229
+ }
230
+ for (const gitPath of hostGitDirs) {
231
+ lines.push(`(allow file-read* (subpath ${seatbeltString(gitPath)}))`);
232
+ lines.push(`(allow file-write* (subpath ${seatbeltString(gitPath)}))`);
233
+ }
234
+ const projectRootReal = ctx.realPath(projectRoot);
235
+ if (projectRootReal !== workspaceReal && !projectRootReal.startsWith(workspaceReal + "/")) {
236
+ lines.push(`(allow file-read* (subpath ${seatbeltString(projectRootReal)}))`);
237
+ }
238
+ for (const repoRoot of hostRepoRoots) {
239
+ if (!ctx.pathExists(repoRoot) || repoRoot === workspaceReal || repoRoot.startsWith(workspaceReal + "/") || repoRoot === projectRootReal || repoRoot.startsWith(projectRootReal + "/")) {
240
+ continue;
241
+ }
242
+ lines.push(`(allow file-read* (subpath ${seatbeltString(repoRoot)}))`);
243
+ }
244
+ const realHome = process.env.HOME?.trim();
245
+ if (realHome) {
246
+ for (const binSubdir of [".local/bin", ".cargo/bin"]) {
247
+ const binPath = resolve3(realHome, binSubdir);
248
+ if (ctx.pathExists(binPath)) {
249
+ lines.push(`(allow file-read* (subpath ${seatbeltString(ctx.realPath(binPath))}))`);
250
+ }
251
+ }
252
+ }
253
+ for (const tempPath of [
254
+ "/dev",
255
+ "/tmp",
256
+ "/private/tmp",
257
+ "/var/folders",
258
+ "/private/var/folders"
259
+ ]) {
260
+ lines.push(`(allow file-read* (subpath ${seatbeltString(tempPath)}))`);
261
+ lines.push(`(allow file-write* (subpath ${seatbeltString(tempPath)}))`);
262
+ }
263
+ return lines.join(`
264
+ `);
265
+ }
266
+ }
267
+ var init_backend_seatbelt = __esm(() => {
268
+ init_utils();
269
+ });
270
+
271
+ // packages/isolation-plugin/src/sandbox/backend-bwrap.ts
272
+ var exports_backend_bwrap = {};
273
+ __export(exports_backend_bwrap, {
274
+ BwrapBackend: () => BwrapBackend
275
+ });
276
+ import { mkdirSync as mkdirSync2 } from "fs";
277
+ import { resolve as resolve4 } from "path";
278
+
279
+ class BwrapBackend {
280
+ kind = "linux-bwrap";
281
+ binaryPath;
282
+ config;
283
+ ctx;
284
+ resolvedPaths;
285
+ which;
286
+ constructor(binaryPath, config, ctx, resolvedPaths, which) {
287
+ this.binaryPath = binaryPath;
288
+ this.config = config;
289
+ this.ctx = ctx;
290
+ this.resolvedPaths = resolvedPaths;
291
+ this.which = which ?? ((bin) => Bun.which(bin));
292
+ }
293
+ wrap(options) {
294
+ const command = this.buildCommand(options);
295
+ return {
296
+ command,
297
+ enabled: true,
298
+ backend: "linux-bwrap"
299
+ };
300
+ }
301
+ buildCommand(options) {
302
+ const { runtime, projectRoot, command } = options;
303
+ const { ctx, resolvedPaths, config } = this;
304
+ const workspaceReal = ctx.realPath(runtime.workspaceDir);
305
+ const runtimeRootReal = ctx.realPath(runtime.rootDir);
306
+ const homeReal = ctx.realPath(runtime.homeDir);
307
+ const tmpReal = ctx.realPath(runtime.tmpDir);
308
+ const cacheReal = ctx.realPath(runtime.cacheDir);
309
+ const hostGitDirs = resolveHostGitMetadataPaths(projectRoot, runtime.workspaceDir);
310
+ const hostRepoRoots = resolveHostRepoRootPaths(projectRoot).map((repoRoot) => ctx.realPath(repoRoot));
311
+ const bunDir = ctx.realPath(resolvedPaths.bunDir);
312
+ const claudeDir = resolvedPaths.claudeDir ? ctx.realPath(resolvedPaths.claudeDir) : null;
313
+ const allowNetwork = resolveNetworkWithPolicy(config, process.env.RIG_RUNTIME_SANDBOX_NETWORK);
314
+ const args = [
315
+ this.binaryPath,
316
+ "--die-with-parent",
317
+ "--new-session",
318
+ "--unshare-pid",
319
+ "--tmpfs",
320
+ "/",
321
+ "--ro-bind",
322
+ "/usr",
323
+ "/usr",
324
+ "--ro-bind",
325
+ "/bin",
326
+ "/bin",
327
+ "--ro-bind",
328
+ "/sbin",
329
+ "/sbin"
330
+ ];
331
+ for (const libPath of ["/lib", "/lib64"]) {
332
+ if (ctx.pathExists(libPath)) {
333
+ args.push("--ro-bind", libPath, libPath);
334
+ }
335
+ }
336
+ for (const etcEntry of [
337
+ "/etc/ld.so.cache",
338
+ "/etc/ld.so.conf",
339
+ "/etc/ld.so.conf.d",
340
+ "/etc/resolv.conf",
341
+ "/etc/hosts",
342
+ "/etc/nsswitch.conf",
343
+ "/etc/gai.conf",
344
+ "/etc/host.conf",
345
+ "/etc/ssl",
346
+ "/etc/ca-certificates",
347
+ "/etc/pki",
348
+ "/etc/passwd",
349
+ "/etc/group",
350
+ "/etc/localtime",
351
+ "/etc/timezone",
352
+ "/etc/locale.conf",
353
+ "/etc/default/locale"
354
+ ]) {
355
+ if (ctx.pathExists(etcEntry)) {
356
+ args.push("--ro-bind", etcEntry, etcEntry);
357
+ }
358
+ }
359
+ if (ctx.pathExists("/run/systemd/resolve")) {
360
+ args.push("--ro-bind", "/run/systemd/resolve", "/run/systemd/resolve");
361
+ }
362
+ if (ctx.pathExists("/run/nscd")) {
363
+ args.push("--ro-bind", "/run/nscd", "/run/nscd");
364
+ }
365
+ args.push("--ro-bind", bunDir, bunDir);
366
+ if (claudeDir) {
367
+ args.push("--ro-bind", claudeDir, claudeDir);
368
+ }
369
+ if (resolvedPaths.nodeDir && ctx.pathExists(resolvedPaths.nodeDir)) {
370
+ args.push("--ro-bind", resolvedPaths.nodeDir, resolvedPaths.nodeDir);
371
+ }
372
+ for (const depPath of resolvedPaths.depRoots) {
373
+ if (ctx.pathExists(depPath)) {
374
+ args.push("--ro-bind", depPath, depPath);
375
+ }
376
+ }
377
+ const projectRootReal = ctx.realPath(projectRoot);
378
+ if (projectRootReal !== workspaceReal && !projectRootReal.startsWith(workspaceReal + "/") && ctx.pathExists(projectRootReal)) {
379
+ args.push("--ro-bind", projectRootReal, projectRootReal);
380
+ }
381
+ for (const repoRoot of hostRepoRoots) {
382
+ if (!ctx.pathExists(repoRoot) || repoRoot === workspaceReal || repoRoot.startsWith(workspaceReal + "/") || repoRoot === projectRootReal || repoRoot.startsWith(projectRootReal + "/")) {
383
+ continue;
384
+ }
385
+ args.push("--ro-bind", repoRoot, repoRoot);
386
+ }
387
+ args.push("--bind", workspaceReal, workspaceReal);
388
+ args.push("--bind", runtimeRootReal, runtimeRootReal);
389
+ for (const rwPath of uniq([homeReal, tmpReal, cacheReal])) {
390
+ if (rwPath !== runtimeRootReal && !rwPath.startsWith(runtimeRootReal + "/")) {
391
+ args.push("--bind", rwPath, rwPath);
392
+ }
393
+ }
394
+ for (const gitPath of hostGitDirs) {
395
+ if (!ctx.pathExists(gitPath))
396
+ continue;
397
+ if (gitPath === runtimeRootReal || gitPath.startsWith(runtimeRootReal + "/"))
398
+ continue;
399
+ if (gitPath === workspaceReal || gitPath.startsWith(workspaceReal + "/"))
400
+ continue;
401
+ args.push("--bind", gitPath, gitPath);
402
+ }
403
+ const realHome = process.env.HOME?.trim();
404
+ if (realHome) {
405
+ for (const binSubdir of [".local/bin", ".local/lib", ".cargo/bin"]) {
406
+ const binPath = ctx.realPath(resolve4(realHome, binSubdir));
407
+ if (ctx.pathExists(binPath)) {
408
+ args.push("--ro-bind", binPath, binPath);
409
+ }
410
+ }
411
+ const agentSshDir = resolve4(homeReal, ".ssh");
412
+ if (ctx.pathExists(agentSshDir)) {
413
+ args.push("--ro-bind", agentSshDir, agentSshDir);
414
+ } else {
415
+ const hostSshDir = resolve4(realHome, ".ssh");
416
+ if (ctx.pathExists(hostSshDir)) {
417
+ mkdirSync2(agentSshDir, { recursive: true });
418
+ args.push("--ro-bind", hostSshDir, agentSshDir);
419
+ args.push("--ro-bind", hostSshDir, hostSshDir);
420
+ }
421
+ }
422
+ }
423
+ args.push("--proc", "/proc");
424
+ args.push("--dev", "/dev");
425
+ args.push("--tmpfs", "/tmp");
426
+ args.push("--unsetenv", "CLAUDECODE");
427
+ args.push("--setenv", "HOME", homeReal);
428
+ args.push("--setenv", "TMPDIR", "/tmp");
429
+ args.push("--chdir", workspaceReal);
430
+ if (!allowNetwork) {
431
+ args.push("--unshare-net");
432
+ }
433
+ args.push("--", ...this.resolveCommandBinary(command));
434
+ return args;
435
+ }
436
+ resolveCommandBinary(command) {
437
+ if (command.length === 0)
438
+ return command;
439
+ const [bin, ...rest] = command;
440
+ if (!bin)
441
+ return command;
442
+ const resolved = this.which(bin);
443
+ if (!resolved)
444
+ return command;
445
+ try {
446
+ const { realpathSync: realpathSync2 } = __require("fs");
447
+ const resolvedBinary = realpathSync2(resolved);
448
+ return [resolvedBinary, ...rest];
449
+ } catch {
450
+ return [resolved, ...rest];
451
+ }
452
+ }
453
+ }
454
+ var init_backend_bwrap = __esm(() => {
455
+ init_utils();
456
+ });
457
+
458
+ // packages/isolation-plugin/src/sandbox/backend.ts
459
+ import { existsSync as existsSync3 } from "fs";
460
+
461
+ // packages/isolation-plugin/src/runtime-config.ts
462
+ import { existsSync, readFileSync, statSync } from "fs";
463
+ import { resolve } from "path";
464
+ import {
465
+ POLICY_VERSION
466
+ } from "@rig/contracts";
467
+ var DEFAULT_SCOPE = {
468
+ fail_closed: true,
469
+ harness_paths_exempt: true,
470
+ runtime_paths_exempt: true
471
+ };
472
+ var DEFAULT_SANDBOX = {
473
+ mode: "enforce",
474
+ network: true,
475
+ read_deny: [],
476
+ write_allow_from_runtime: true
477
+ };
478
+ var DEFAULT_ISOLATION = {
479
+ default_mode: "worktree",
480
+ repo_symlink_fallback: false,
481
+ strict_provisioning: true,
482
+ fail_closed_on_provision_error: true
483
+ };
484
+ var DEFAULT_COMPLETION = {
485
+ derive_checks_from_scope: true,
486
+ checks: [],
487
+ typescript_config_probe: ["tsconfig.json"],
488
+ eslint_config_probe: [".eslintrc.js", ".eslintrc.json", "eslint.config.js"]
489
+ };
490
+ var DEFAULT_RUNTIME_IMAGE = {
491
+ deps: { monorepo_install: false, hp_next_install: false },
492
+ plugins_require_binaries: true
493
+ };
494
+ var DEFAULT_RUNTIME_SNAPSHOT = { enabled: true };
495
+ var policyCache = null;
496
+ var policyCachePath = null;
497
+ function loadSandboxConfig(projectRoot) {
498
+ return loadPolicy(projectRoot).sandbox;
499
+ }
500
+ function defaultPolicy() {
501
+ return {
502
+ version: POLICY_VERSION,
503
+ mode: "enforce",
504
+ scope: { ...DEFAULT_SCOPE },
505
+ rules: [],
506
+ sandbox: { ...DEFAULT_SANDBOX },
507
+ isolation: { ...DEFAULT_ISOLATION },
508
+ completion: { ...DEFAULT_COMPLETION },
509
+ runtime_image: {
510
+ deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
511
+ plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
512
+ },
513
+ runtime_snapshot: { ...DEFAULT_RUNTIME_SNAPSHOT }
514
+ };
515
+ }
516
+ function loadPolicy(projectRoot) {
517
+ const configPath = resolve(projectRoot, "rig/policy/policy.json");
518
+ if (!existsSync(configPath))
519
+ return defaultPolicy();
520
+ let mtimeMs;
521
+ try {
522
+ mtimeMs = statSync(configPath).mtimeMs;
523
+ } catch {
524
+ return defaultPolicy();
525
+ }
526
+ if (policyCache && policyCachePath === configPath && policyCache.mtimeMs === mtimeMs) {
527
+ return policyCache.config;
528
+ }
529
+ try {
530
+ const config = mergeWithDefaults(JSON.parse(readFileSync(configPath, "utf-8")));
531
+ policyCache = { mtimeMs, config };
532
+ policyCachePath = configPath;
533
+ return config;
534
+ } catch {
535
+ return defaultPolicy();
536
+ }
537
+ }
538
+ function mergeWithDefaults(parsed) {
539
+ const base = defaultPolicy();
540
+ if (typeof parsed.mode === "string" && isValidMode(parsed.mode))
541
+ base.mode = parsed.mode;
542
+ if (parsed.scope && typeof parsed.scope === "object" && !Array.isArray(parsed.scope)) {
543
+ const scope = parsed.scope;
544
+ if (typeof scope.fail_closed === "boolean")
545
+ base.scope.fail_closed = scope.fail_closed;
546
+ if (typeof scope.harness_paths_exempt === "boolean")
547
+ base.scope.harness_paths_exempt = scope.harness_paths_exempt;
548
+ if (typeof scope.runtime_paths_exempt === "boolean")
549
+ base.scope.runtime_paths_exempt = scope.runtime_paths_exempt;
550
+ }
551
+ if (Array.isArray(parsed.rules))
552
+ base.rules = precompilePolicyRuleRegexes(parsed.rules.filter(isValidRule));
553
+ if (Array.isArray(parsed.deny) && base.rules.length === 0) {
554
+ base.rules = precompilePolicyRuleRegexes(migrateLegacyDeny(parsed.deny));
555
+ }
556
+ if (parsed.sandbox && typeof parsed.sandbox === "object" && !Array.isArray(parsed.sandbox)) {
557
+ const sandbox = parsed.sandbox;
558
+ if (typeof sandbox.mode === "string" && isValidMode(sandbox.mode))
559
+ base.sandbox.mode = sandbox.mode;
560
+ if (typeof sandbox.network === "boolean")
561
+ base.sandbox.network = sandbox.network;
562
+ if (Array.isArray(sandbox.read_deny))
563
+ base.sandbox.read_deny = sandbox.read_deny.filter((value) => typeof value === "string");
564
+ if (typeof sandbox.write_allow_from_runtime === "boolean")
565
+ base.sandbox.write_allow_from_runtime = sandbox.write_allow_from_runtime;
566
+ }
567
+ if (parsed.isolation && typeof parsed.isolation === "object" && !Array.isArray(parsed.isolation)) {
568
+ const isolation = parsed.isolation;
569
+ if (isolation.default_mode === "worktree")
570
+ base.isolation.default_mode = isolation.default_mode;
571
+ if (typeof isolation.repo_symlink_fallback === "boolean")
572
+ base.isolation.repo_symlink_fallback = isolation.repo_symlink_fallback;
573
+ if (typeof isolation.strict_provisioning === "boolean")
574
+ base.isolation.strict_provisioning = isolation.strict_provisioning;
575
+ if (typeof isolation.fail_closed_on_provision_error === "boolean")
576
+ base.isolation.fail_closed_on_provision_error = isolation.fail_closed_on_provision_error;
577
+ }
578
+ if (parsed.completion && typeof parsed.completion === "object" && !Array.isArray(parsed.completion)) {
579
+ const completion = parsed.completion;
580
+ if (typeof completion.derive_checks_from_scope === "boolean")
581
+ base.completion.derive_checks_from_scope = completion.derive_checks_from_scope;
582
+ if (Array.isArray(completion.checks))
583
+ base.completion.checks = completion.checks.filter((value) => typeof value === "string");
584
+ if (Array.isArray(completion.typescript_config_probe))
585
+ base.completion.typescript_config_probe = completion.typescript_config_probe.filter((value) => typeof value === "string");
586
+ if (Array.isArray(completion.eslint_config_probe))
587
+ base.completion.eslint_config_probe = completion.eslint_config_probe.filter((value) => typeof value === "string");
588
+ }
589
+ if (parsed.runtime_image && typeof parsed.runtime_image === "object" && !Array.isArray(parsed.runtime_image)) {
590
+ const runtimeImage = parsed.runtime_image;
591
+ if (runtimeImage.deps && typeof runtimeImage.deps === "object" && !Array.isArray(runtimeImage.deps)) {
592
+ const deps = runtimeImage.deps;
593
+ if (typeof deps.monorepo_install === "boolean")
594
+ base.runtime_image.deps.monorepo_install = deps.monorepo_install;
595
+ if (typeof deps.hp_next_install === "boolean")
596
+ base.runtime_image.deps.hp_next_install = deps.hp_next_install;
597
+ }
598
+ if (typeof runtimeImage.plugins_require_binaries === "boolean")
599
+ base.runtime_image.plugins_require_binaries = runtimeImage.plugins_require_binaries;
600
+ }
601
+ if (parsed.runtime_snapshot && typeof parsed.runtime_snapshot === "object" && !Array.isArray(parsed.runtime_snapshot)) {
602
+ const runtimeSnapshot = parsed.runtime_snapshot;
603
+ if (typeof runtimeSnapshot.enabled === "boolean")
604
+ base.runtime_snapshot.enabled = runtimeSnapshot.enabled;
605
+ }
606
+ return base;
607
+ }
608
+ function isValidMode(value) {
609
+ return value === "off" || value === "observe" || value === "enforce";
610
+ }
611
+ function isValidRule(value) {
612
+ if (!value || typeof value !== "object" || Array.isArray(value))
613
+ return false;
614
+ const rule = value;
615
+ return typeof rule.id === "string" && typeof rule.category === "string" && !!rule.match && typeof rule.match === "object";
616
+ }
617
+ function migrateLegacyDeny(deny) {
618
+ const rules = [];
619
+ for (const entry of deny) {
620
+ if (typeof entry.id !== "string")
621
+ continue;
622
+ const match = {};
623
+ if (typeof entry.pattern === "string")
624
+ match.pattern = entry.pattern;
625
+ if (typeof entry.regex === "string")
626
+ match.regex = entry.regex;
627
+ if (!match.pattern && !match.regex)
628
+ continue;
629
+ const rule = {
630
+ id: entry.id,
631
+ category: "command",
632
+ match,
633
+ action: entry.action === "warn" ? "warn" : "block"
634
+ };
635
+ if (typeof entry.reason === "string") {
636
+ rule.description = entry.reason;
637
+ }
638
+ rules.push(rule);
639
+ }
640
+ return rules;
641
+ }
642
+ function precompilePolicyRuleRegexes(rules) {
643
+ return rules.map((rule) => {
644
+ const compiled = { ...rule };
645
+ const matchRegex = compileRegex(rule.match?.regex);
646
+ const unlessRegex = compileRegex(rule.unless?.regex);
647
+ if (matchRegex) {
648
+ compiled.compiledRegex = matchRegex;
649
+ }
650
+ if (unlessRegex) {
651
+ compiled.compiledUnlessRegex = unlessRegex;
652
+ }
653
+ return compiled;
654
+ });
655
+ }
656
+ function compileRegex(pattern) {
657
+ if (!pattern)
658
+ return;
659
+ try {
660
+ return new RegExp(pattern);
661
+ } catch {
662
+ return;
663
+ }
664
+ }
665
+
666
+ // packages/isolation-plugin/src/sandbox/backend.ts
667
+ init_utils();
668
+ import {
669
+ resolveBunInstallDir,
670
+ resolveClaudeInstallDir,
671
+ resolveNodeInstallDir,
672
+ resolveRuntimeDependencyRoots
673
+ } from "@rig/core/runtime-paths";
674
+
675
+ // packages/isolation-plugin/src/sandbox/backend-none.ts
676
+ class NoSandboxBackend {
677
+ kind = "none";
678
+ reason;
679
+ constructor(reason) {
680
+ this.reason = reason;
681
+ }
682
+ wrap(options) {
683
+ return {
684
+ command: options.command,
685
+ enabled: false,
686
+ backend: "none",
687
+ ...this.reason !== undefined ? { reason: this.reason } : {}
688
+ };
689
+ }
690
+ }
691
+
692
+ // packages/isolation-plugin/src/sandbox/backend.ts
693
+ class SandboxError extends Error {
694
+ code;
695
+ constructor(code, message) {
696
+ super(message);
697
+ this.code = code;
698
+ this.name = "SandboxError";
699
+ }
700
+ }
701
+ function resolveRuntimeSandboxModeWithPolicy(sandboxConfig, envOverride) {
702
+ if (envOverride) {
703
+ const normalized = envOverride.trim().toLowerCase();
704
+ if (normalized === "off" || normalized === "auto" || normalized === "enforce") {
705
+ if (normalized !== sandboxConfig.mode) {
706
+ console.warn(`[sandbox] RIG_RUNTIME_SANDBOX=${normalized} overrides policy sandbox.mode=${sandboxConfig.mode}`);
707
+ }
708
+ return normalized;
709
+ }
710
+ }
711
+ const policyMode = sandboxConfig.mode;
712
+ if (policyMode === "off")
713
+ return "off";
714
+ if (policyMode === "observe")
715
+ return "auto";
716
+ return "enforce";
717
+ }
718
+ var bwrapProbeCache = null;
719
+ async function probeBubblewrap(binary) {
720
+ if (bwrapProbeCache !== null) {
721
+ return bwrapProbeCache;
722
+ }
723
+ const probe = await Bun.$`${binary} ${["--ro-bind", "/", "/", "--proc", "/proc", "--dev", "/dev", "--", "true"]}`.quiet().nothrow();
724
+ bwrapProbeCache = probe.exitCode === 0;
725
+ return bwrapProbeCache;
726
+ }
727
+ async function resolveBackend(projectRoot, options) {
728
+ const config = loadSandboxConfig(projectRoot);
729
+ const mode = resolveRuntimeSandboxModeWithPolicy(config, options?.envOverride);
730
+ const probed = [];
731
+ if (mode === "off") {
732
+ return {
733
+ backend: new NoSandboxBackend,
734
+ selectedKind: "none",
735
+ probed,
736
+ reason: "disabled-by-config"
737
+ };
738
+ }
739
+ const explicitBackend = options?.backendOverride ?? process.env.RIG_SANDBOX_BACKEND?.trim().toLowerCase();
740
+ const requestedBackend = resolveExplicitBackend(explicitBackend);
741
+ if (requestedBackend) {
742
+ if (requestedBackend === "docker") {
743
+ throw new SandboxError("backend-unavailable", `Backend "docker" is not yet implemented.`);
744
+ }
745
+ if (requestedBackend === "none") {
746
+ return {
747
+ backend: new NoSandboxBackend("explicit-none"),
748
+ selectedKind: "none",
749
+ probed,
750
+ reason: "explicit-none"
751
+ };
752
+ }
753
+ }
754
+ const bunDir = resolveBunInstallDir();
755
+ const claudeDir = (() => {
756
+ try {
757
+ return resolveClaudeInstallDir();
758
+ } catch {
759
+ return null;
760
+ }
761
+ })();
762
+ const nodeDir = resolveNodeInstallDir();
763
+ const depRoots = resolveRuntimeDependencyRoots([bunDir, claudeDir, nodeDir].filter(Boolean));
764
+ const resolvedPaths = {
765
+ bunDir,
766
+ claudeDir,
767
+ nodeDir,
768
+ depRoots
769
+ };
770
+ const fsContext = {
771
+ pathExists: (p) => existsSync3(p),
772
+ realPath: toRealPath
773
+ };
774
+ if (process.platform === "darwin" && (!requestedBackend || requestedBackend === "macos-seatbelt")) {
775
+ const seatbelt = Bun.which("sandbox-exec");
776
+ probed.push("sandbox-exec");
777
+ if (seatbelt && existsSync3(seatbelt)) {
778
+ const SeatbeltBackendClass = loadSeatbeltBackend();
779
+ if (SeatbeltBackendClass) {
780
+ return {
781
+ backend: new SeatbeltBackendClass(seatbelt, config, fsContext, resolvedPaths),
782
+ selectedKind: "macos-seatbelt",
783
+ probed,
784
+ reason: "detected-seatbelt"
785
+ };
786
+ }
787
+ return handleUnavailableBackend(mode, probed, "macos-seatbelt", "Seatbelt sandbox backend module failed to load.", "seatbelt-backend-module-unavailable", { explicit: requestedBackend === "macos-seatbelt" });
788
+ }
789
+ }
790
+ if (process.platform === "linux" && (!requestedBackend || requestedBackend === "linux-bwrap")) {
791
+ const bwrap = Bun.which("bwrap");
792
+ probed.push("bwrap");
793
+ if (bwrap && await probeBubblewrap(bwrap)) {
794
+ const BwrapBackendClass = loadBwrapBackend();
795
+ if (BwrapBackendClass) {
796
+ return {
797
+ backend: new BwrapBackendClass(bwrap, config, fsContext, resolvedPaths),
798
+ selectedKind: "linux-bwrap",
799
+ probed,
800
+ reason: "detected-bwrap"
801
+ };
802
+ }
803
+ return handleUnavailableBackend(mode, probed, "linux-bwrap", "Bubblewrap sandbox backend module failed to load.", "bwrap-backend-module-unavailable", { explicit: requestedBackend === "linux-bwrap" });
804
+ }
805
+ }
806
+ if (requestedBackend) {
807
+ return handleUnavailableBackend(mode, probed, requestedBackend, `Explicit sandbox backend "${requestedBackend}" is unavailable on ${process.platform}.`, "explicit-backend-unavailable", { explicit: true });
808
+ }
809
+ if (mode === "enforce") {
810
+ throw new SandboxError("backend-unavailable", `Runtime sandbox required (mode=enforce) but no backend available. Probed: ${probed.join(", ")}`);
811
+ }
812
+ return {
813
+ backend: new NoSandboxBackend("sandbox-backend-unavailable"),
814
+ selectedKind: "none",
815
+ probed,
816
+ reason: "sandbox-backend-unavailable"
817
+ };
818
+ }
819
+ function resolveExplicitBackend(explicitBackend) {
820
+ if (!explicitBackend) {
821
+ return null;
822
+ }
823
+ switch (explicitBackend) {
824
+ case "none":
825
+ case "macos-seatbelt":
826
+ case "linux-bwrap":
827
+ case "docker":
828
+ return explicitBackend;
829
+ default:
830
+ throw new SandboxError("backend-unavailable", `Unknown sandbox backend "${explicitBackend}".`);
831
+ }
832
+ }
833
+ function loadSeatbeltBackend() {
834
+ try {
835
+ const mod = (init_backend_seatbelt(), __toCommonJS(exports_backend_seatbelt));
836
+ return mod.SeatbeltBackend ?? null;
837
+ } catch {
838
+ return null;
839
+ }
840
+ }
841
+ function loadBwrapBackend() {
842
+ try {
843
+ const mod = (init_backend_bwrap(), __toCommonJS(exports_backend_bwrap));
844
+ return mod.BwrapBackend ?? null;
845
+ } catch {
846
+ return null;
847
+ }
848
+ }
849
+ function handleUnavailableBackend(mode, probed, detectedKind, message, reason, options) {
850
+ if (mode === "enforce" || options?.explicit) {
851
+ throw new SandboxError("backend-unavailable", `${message} Probed: ${probed.join(", ")}`);
852
+ }
853
+ return {
854
+ backend: new NoSandboxBackend(reason),
855
+ selectedKind: "none",
856
+ probed,
857
+ reason: `${reason}:${detectedKind}`
858
+ };
859
+ }
860
+ export {
861
+ resolveRuntimeSandboxModeWithPolicy,
862
+ resolveBackend,
863
+ SandboxError
864
+ };