@probelabs/visor 0.1.144-ee → 0.1.145-ee

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 (68) hide show
  1. package/dist/config.d.ts.map +1 -1
  2. package/dist/docs/architecture.md +28 -0
  3. package/dist/docs/configuration.md +2 -0
  4. package/dist/docs/sandbox-engines.md +357 -0
  5. package/dist/docs/security.md +40 -0
  6. package/dist/generated/config-schema.d.ts +5 -0
  7. package/dist/generated/config-schema.d.ts.map +1 -1
  8. package/dist/generated/config-schema.json +9 -0
  9. package/dist/index.js +670 -162
  10. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  11. package/dist/sandbox/bubblewrap-sandbox.d.ts +30 -0
  12. package/dist/sandbox/bubblewrap-sandbox.d.ts.map +1 -0
  13. package/dist/sandbox/index.d.ts +3 -1
  14. package/dist/sandbox/index.d.ts.map +1 -1
  15. package/dist/sandbox/sandbox-manager.d.ts +3 -2
  16. package/dist/sandbox/sandbox-manager.d.ts.map +1 -1
  17. package/dist/sandbox/seatbelt-sandbox.d.ts +36 -0
  18. package/dist/sandbox/seatbelt-sandbox.d.ts.map +1 -0
  19. package/dist/sandbox/types.d.ts +3 -1
  20. package/dist/sandbox/types.d.ts.map +1 -1
  21. package/dist/sdk/{check-provider-registry-Q7D5SQAV.mjs → check-provider-registry-HFPKHYTG.mjs} +4 -4
  22. package/dist/sdk/{check-provider-registry-VTNNTMWC.mjs → check-provider-registry-TH25S2OB.mjs} +7 -7
  23. package/dist/sdk/{chunk-AUHRKE6Z.mjs → chunk-3BOOHJI5.mjs} +467 -100
  24. package/dist/sdk/chunk-3BOOHJI5.mjs.map +1 -0
  25. package/dist/sdk/{chunk-PXWWPPNF.mjs → chunk-GZMQPC6D.mjs} +459 -92
  26. package/dist/sdk/chunk-GZMQPC6D.mjs.map +1 -0
  27. package/dist/sdk/chunk-I42ZCVA5.mjs +1502 -0
  28. package/dist/sdk/chunk-I42ZCVA5.mjs.map +1 -0
  29. package/dist/sdk/chunk-L3XPYQ6I.mjs +739 -0
  30. package/dist/sdk/chunk-L3XPYQ6I.mjs.map +1 -0
  31. package/dist/sdk/chunk-OM3WYVFI.mjs +443 -0
  32. package/dist/sdk/chunk-OM3WYVFI.mjs.map +1 -0
  33. package/dist/sdk/{chunk-AKCHIYWU.mjs → chunk-YOKAA4IU.mjs} +96 -63
  34. package/dist/sdk/chunk-YOKAA4IU.mjs.map +1 -0
  35. package/dist/sdk/{config-KOKJ3PYE.mjs → config-AAB2FL22.mjs} +2 -2
  36. package/dist/sdk/failure-condition-evaluator-O464EJMD.mjs +17 -0
  37. package/dist/sdk/github-frontend-MSX6Q2WL.mjs +1356 -0
  38. package/dist/sdk/github-frontend-MSX6Q2WL.mjs.map +1 -0
  39. package/dist/sdk/{host-WGFJVD4L.mjs → host-GA76UESS.mjs} +2 -2
  40. package/dist/sdk/routing-RIHVCEIU.mjs +25 -0
  41. package/dist/sdk/{schedule-tool-handler-FBXABUWX.mjs → schedule-tool-handler-BTLEDYAI.mjs} +4 -4
  42. package/dist/sdk/{schedule-tool-handler-7RGTKO24.mjs → schedule-tool-handler-NYL2ONJB.mjs} +7 -7
  43. package/dist/sdk/sdk.d.mts +3 -1
  44. package/dist/sdk/sdk.d.ts +3 -1
  45. package/dist/sdk/sdk.js +578 -178
  46. package/dist/sdk/sdk.js.map +1 -1
  47. package/dist/sdk/sdk.mjs +5 -5
  48. package/dist/sdk/trace-helpers-QQSTZGDT.mjs +25 -0
  49. package/dist/sdk/trace-helpers-QQSTZGDT.mjs.map +1 -0
  50. package/dist/sdk/{workflow-check-provider-62MO2NB6.mjs → workflow-check-provider-3IIKJFM4.mjs} +4 -4
  51. package/dist/sdk/workflow-check-provider-3IIKJFM4.mjs.map +1 -0
  52. package/dist/sdk/{workflow-check-provider-FLBIJQ4Z.mjs → workflow-check-provider-LVUUL2PZ.mjs} +7 -7
  53. package/dist/sdk/workflow-check-provider-LVUUL2PZ.mjs.map +1 -0
  54. package/dist/slack/socket-runner.d.ts.map +1 -1
  55. package/dist/utils/workspace-manager.d.ts +9 -0
  56. package/dist/utils/workspace-manager.d.ts.map +1 -1
  57. package/package.json +2 -2
  58. package/dist/sdk/chunk-AKCHIYWU.mjs.map +0 -1
  59. package/dist/sdk/chunk-AUHRKE6Z.mjs.map +0 -1
  60. package/dist/sdk/chunk-PXWWPPNF.mjs.map +0 -1
  61. /package/dist/sdk/{check-provider-registry-Q7D5SQAV.mjs.map → check-provider-registry-HFPKHYTG.mjs.map} +0 -0
  62. /package/dist/sdk/{check-provider-registry-VTNNTMWC.mjs.map → check-provider-registry-TH25S2OB.mjs.map} +0 -0
  63. /package/dist/sdk/{config-KOKJ3PYE.mjs.map → config-AAB2FL22.mjs.map} +0 -0
  64. /package/dist/sdk/{schedule-tool-handler-7RGTKO24.mjs.map → failure-condition-evaluator-O464EJMD.mjs.map} +0 -0
  65. /package/dist/sdk/{host-WGFJVD4L.mjs.map → host-GA76UESS.mjs.map} +0 -0
  66. /package/dist/sdk/{schedule-tool-handler-FBXABUWX.mjs.map → routing-RIHVCEIU.mjs.map} +0 -0
  67. /package/dist/sdk/{workflow-check-provider-62MO2NB6.mjs.map → schedule-tool-handler-BTLEDYAI.mjs.map} +0 -0
  68. /package/dist/sdk/{workflow-check-provider-FLBIJQ4Z.mjs.map → schedule-tool-handler-NYL2ONJB.mjs.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/config.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,WAAW,EAGX,YAAY,EAIZ,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,YAAY,EAS9C,CAAC;AAEX;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,eAAe,CAgBrB;IACF,OAAO,CAAC,kBAAkB,CAA6C;IACvE,OAAO,CAAC,kBAAkB,CAAgE;IAC1F,OAAO,CAAC,mBAAmB,CAA2D;IAEtF;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACU,UAAU,CACrB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAwHvB;;;OAGG;IACU,oBAAoB,CAC/B,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,EACzB,OAAO,GAAE,iBAAiB,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACrD,OAAO,CAAC,WAAW,CAAC;IAoDvB;;OAEG;IACU,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IA4CrF;;OAEG;YACW,qBAAqB;IAiBnC;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBrD;;OAEG;IACI,wBAAwB,IAAI,WAAW,GAAG,IAAI;IA0FrD;;OAEG;IACH,OAAO,CAAC,eAAe;IAuBvB;;;OAGG;YACW,uBAAuB;IAiGrC;;OAEG;YACW,aAAa;IA6B3B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACI,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,YAAY;IAqB9F;;OAEG;IACU,0BAA0B,IAAI,OAAO,CAAC;QACjD,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,oBAAoB,EAAE,oBAAoB,CAAC;KAC5C,CAAC;IA2BF;;;;OAIG;IACI,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,UAAQ,GAAG,IAAI;IA4VzE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoH7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA8T3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmM5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA0DhC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqG7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6DzB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA6EhC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA+B5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CA6B1B"}
1
+ {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/config.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,WAAW,EAGX,YAAY,EAIZ,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,YAAY,EAS9C,CAAC;AAEX;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,eAAe,CAgBrB;IACF,OAAO,CAAC,kBAAkB,CAA6C;IACvE,OAAO,CAAC,kBAAkB,CAAgE;IAC1F,OAAO,CAAC,mBAAmB,CAA2D;IAEtF;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACU,UAAU,CACrB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAwHvB;;;OAGG;IACU,oBAAoB,CAC/B,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,EACzB,OAAO,GAAE,iBAAiB,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACrD,OAAO,CAAC,WAAW,CAAC;IAoDvB;;OAEG;IACU,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IA4CrF;;OAEG;YACW,qBAAqB;IAiBnC;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBrD;;OAEG;IACI,wBAAwB,IAAI,WAAW,GAAG,IAAI;IA0FrD;;OAEG;IACH,OAAO,CAAC,eAAe;IAuBvB;;;OAGG;YACW,uBAAuB;IAiGrC;;OAEG;YACW,aAAa;IA6B3B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACI,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,YAAY;IAqB9F;;OAEG;IACU,0BAA0B,IAAI,OAAO,CAAC;QACjD,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,oBAAoB,EAAE,oBAAoB,CAAC;KAC5C,CAAC;IA2BF;;;;OAIG;IACI,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,UAAQ,GAAG,IAAI;IA4VzE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAsJ7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA8T3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmM5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA0DhC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqG7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6DzB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA6EhC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA+B5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CA6B1B"}
@@ -897,6 +897,20 @@ workspace:
897
897
 
898
898
  This creates isolated directories for each execution, preventing cross-contamination.
899
899
 
900
+ ### Process Sandbox Engines
901
+
902
+ Visor supports three sandbox engines for isolating command execution:
903
+
904
+ | Engine | Platform | Isolation Model |
905
+ |--------|----------|-----------------|
906
+ | **Docker** | Linux, macOS, Windows | Full container isolation |
907
+ | **Bubblewrap** | Linux only | Linux kernel namespaces (PID, mount, network) |
908
+ | **Seatbelt** | macOS only | macOS `sandbox-exec` with SBPL profiles |
909
+
910
+ All three implement the `SandboxInstance` interface and are routed through `SandboxManager`. Configure via the `sandboxes:` block and `sandbox:` default in `.visor.yaml`.
911
+
912
+ See [Sandbox Engines](./sandbox-engines.md) for complete documentation.
913
+
900
914
  ### Environment Variable Handling
901
915
 
902
916
  Sensitive values can be passed via environment:
@@ -1045,6 +1059,8 @@ Currently, Visor does not cache AI responses between runs. For expensive operati
1045
1059
  ## Related Documentation
1046
1060
 
1047
1061
  - [Configuration](./configuration.md) - Configuration file reference
1062
+ - [Sandbox Engines](./sandbox-engines.md) - Docker, Bubblewrap, and Seatbelt isolation
1063
+ - [Security](./security.md) - Security overview and best practices
1048
1064
  - [Providers](./providers/) - Provider-specific documentation
1049
1065
  - [Custom Tools](./custom-tools.md) - Creating custom tools
1050
1066
  - [MCP Provider](./mcp-provider.md) - MCP integration details
@@ -1111,6 +1127,18 @@ src/
1111
1127
  github/ # GitHub integration frontend
1112
1128
  slack/ # Slack integration frontend
1113
1129
 
1130
+ sandbox/
1131
+ types.ts # SandboxInstance interface, SandboxConfig
1132
+ sandbox-manager.ts # Lifecycle management, engine routing
1133
+ docker-image-sandbox.ts # Docker image-based sandbox
1134
+ docker-compose-sandbox.ts # Docker Compose sandbox
1135
+ bubblewrap-sandbox.ts # Linux namespace isolation (bwrap)
1136
+ seatbelt-sandbox.ts # macOS sandbox-exec isolation
1137
+ check-runner.ts # Check execution in sandboxes
1138
+ env-filter.ts # Environment variable filtering
1139
+ cache-volume-manager.ts # Docker cache volumes
1140
+ sandbox-telemetry.ts # Telemetry for sandbox operations
1141
+
1114
1142
  utils/
1115
1143
  config-loader.ts # Remote config loading
1116
1144
  config-merger.ts # Configuration merging
@@ -425,6 +425,8 @@ The following global configuration options are available and documented in detai
425
425
  | `http_server` | HTTP server for receiving webhooks | [HTTP Integration](./http.md) |
426
426
  | `memory` | Memory storage configuration | [Memory](./memory.md) |
427
427
  | `output` | Output configuration (PR comments, file comments) | [Output Formats](./output-formats.md) |
428
+ | `sandbox` | Default sandbox name for all steps | [Sandbox Engines](./sandbox-engines.md) |
429
+ | `sandboxes` | Named sandbox definitions (Docker, Bubblewrap, Seatbelt) | [Sandbox Engines](./sandbox-engines.md) |
428
430
  | `workspace` | Workspace isolation configuration | [Workspace Isolation RFC](./rfc/workspace-isolation.md) |
429
431
 
430
432
  Example combining several options:
@@ -0,0 +1,357 @@
1
+ # Sandbox Engines
2
+
3
+ Visor supports three sandbox engines for isolating command execution. Each engine provides different tradeoffs between isolation strength, platform support, and performance.
4
+
5
+ ## Overview
6
+
7
+ | Engine | Platform | Startup Overhead | Dependencies | Isolation Model |
8
+ |--------|----------|-----------------|--------------|-----------------|
9
+ | **Docker** | Linux, macOS, Windows | ~500ms+ | Docker daemon | Full container |
10
+ | **Bubblewrap** | Linux only | ~5-50ms | `bwrap` binary | Linux namespaces |
11
+ | **Seatbelt** | macOS only | ~10-30ms | Built-in (`sandbox-exec`) | SBPL policy profiles |
12
+
13
+ All three engines implement the same `SandboxInstance` interface and are configured through the same `sandboxes:` config block. The `engine` field determines which backend handles execution.
14
+
15
+ ## Quick Start
16
+
17
+ ```yaml
18
+ # .visor.yaml
19
+ sandboxes:
20
+ # Linux: use bubblewrap for lightweight isolation
21
+ bwrap:
22
+ engine: bubblewrap
23
+ network: true
24
+
25
+ # macOS: use seatbelt for native isolation
26
+ mac:
27
+ engine: seatbelt
28
+ network: true
29
+
30
+ # Any platform: use Docker for full container isolation
31
+ docker:
32
+ image: node:20-alpine
33
+
34
+ # Default all steps to a sandbox
35
+ sandbox: bwrap # or mac, or docker
36
+
37
+ steps:
38
+ lint:
39
+ type: command
40
+ exec: eslint src/
41
+
42
+ build:
43
+ type: command
44
+ sandbox: docker # Override: use Docker for this step
45
+ exec: npm run build
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ ### Common Options
51
+
52
+ These options apply to all engine types:
53
+
54
+ | Field | Type | Default | Description |
55
+ |-------|------|---------|-------------|
56
+ | `engine` | `'docker' \| 'bubblewrap' \| 'seatbelt'` | `'docker'` | Sandbox engine backend |
57
+ | `network` | `boolean` | `true` | Enable/disable network access |
58
+ | `read_only` | `boolean` | `false` | Mount repository as read-only |
59
+ | `workdir` | `string` | `'/workspace'` | Working directory inside sandbox (Docker/Bubblewrap only) |
60
+ | `env_passthrough` | `string[]` | — | Glob patterns for host env vars to forward |
61
+
62
+ ### Docker-Only Options
63
+
64
+ These fields are only valid when `engine` is `'docker'` (or omitted):
65
+
66
+ | Field | Type | Description |
67
+ |-------|------|-------------|
68
+ | `image` | `string` | Docker image (e.g., `node:20-alpine`) |
69
+ | `dockerfile` | `string` | Path to Dockerfile |
70
+ | `dockerfile_inline` | `string` | Inline Dockerfile content |
71
+ | `compose` | `string` | Path to docker-compose file |
72
+ | `service` | `string` | Service name within compose file |
73
+ | `resources` | `object` | Memory/CPU limits (`memory: '512m'`, `cpu: 1.0`) |
74
+ | `cache` | `object` | Cache volume configuration |
75
+ | `visor_path` | `string` | Where visor is mounted inside container |
76
+
77
+ Using Docker-only fields with `engine: bubblewrap` or `engine: seatbelt` produces a validation error.
78
+
79
+ ---
80
+
81
+ ## Bubblewrap Engine
82
+
83
+ Bubblewrap (`bwrap`) provides lightweight process isolation using Linux kernel namespaces. It creates an isolated filesystem view, PID namespace, and optionally isolated network for each command execution.
84
+
85
+ ### Requirements
86
+
87
+ - **Linux only** (uses kernel namespaces, which are not available on macOS/Windows)
88
+ - `bwrap` binary must be installed:
89
+
90
+ ```bash
91
+ # Debian / Ubuntu
92
+ apt install bubblewrap
93
+
94
+ # Fedora / RHEL / CentOS
95
+ dnf install bubblewrap
96
+
97
+ # Arch Linux
98
+ pacman -S bubblewrap
99
+
100
+ # Alpine
101
+ apk add bubblewrap
102
+ ```
103
+
104
+ ### How It Works
105
+
106
+ Each `exec()` call spawns a fresh `bwrap` process with:
107
+
108
+ 1. **Mount namespace**: Read-only system dirs (`/usr`, `/bin`, `/lib`, `/etc`) + writable workspace at `/workspace`
109
+ 2. **PID namespace**: Sandboxed process cannot see host PIDs (`--unshare-pid`)
110
+ 3. **Clean environment**: `--clearenv` strips all host env vars; only explicitly passed vars are visible (`--setenv`)
111
+ 4. **Session isolation**: `--new-session` prevents terminal injection attacks
112
+ 5. **Orphan cleanup**: `--die-with-parent` kills sandbox if parent dies
113
+ 6. **Network isolation**: `--unshare-net` when `network: false`
114
+
115
+ ### Configuration
116
+
117
+ ```yaml
118
+ sandboxes:
119
+ bwrap:
120
+ engine: bubblewrap
121
+ network: true # Allow network access (default: true)
122
+ read_only: false # Writable workspace (default: false)
123
+ workdir: /workspace # Working directory inside sandbox (default: /workspace)
124
+ ```
125
+
126
+ ### Filesystem Layout Inside Sandbox
127
+
128
+ | Path | Access | Source |
129
+ |------|--------|--------|
130
+ | `/workspace` | Read-write (or read-only) | Host repository directory |
131
+ | `/usr`, `/bin`, `/lib` | Read-only | Host system directories |
132
+ | `/etc/resolv.conf`, `/etc/ssl` | Read-only | DNS and TLS certificates |
133
+ | `/tmp` | Read-write | Fresh tmpfs per execution |
134
+ | `/dev`, `/proc` | Minimal | Virtual filesystems |
135
+ | `~/.ssh`, `~/.aws`, `~/.config` | **Not mounted** | Inaccessible |
136
+
137
+ ### Security Properties
138
+
139
+ | Property | Status |
140
+ |----------|--------|
141
+ | Filesystem isolation | Commands cannot access files outside allowed paths |
142
+ | Process isolation | PID namespace hides other processes |
143
+ | Environment isolation | `--clearenv` prevents credential theft |
144
+ | Terminal injection | `--new-session` prevents TIOCSTI attacks |
145
+ | Orphan cleanup | `--die-with-parent` ensures cleanup |
146
+ | Network isolation | Optional via `--unshare-net` |
147
+ | Resource limits | Not enforced (use cgroups separately) |
148
+
149
+ ### CI/CD Notes
150
+
151
+ - Works in unprivileged CI runners (no Docker-in-Docker needed)
152
+ - May need `--cap-add SYS_ADMIN` or `--privileged` when running inside Docker containers
153
+ - On non-Linux platforms, `engine: bubblewrap` will fail at runtime with a clear error
154
+
155
+ ---
156
+
157
+ ## Seatbelt Engine
158
+
159
+ Seatbelt uses macOS's built-in `sandbox-exec` with dynamically-generated SBPL (Seatbelt Profile Language) profiles. Unlike bubblewrap, it does not create mount namespaces — commands see the real filesystem but are restricted by ACL-style policy rules.
160
+
161
+ ### Requirements
162
+
163
+ - **macOS only** (`sandbox-exec` ships with macOS)
164
+ - No additional installation needed
165
+
166
+ ### How It Works
167
+
168
+ Each `exec()` call:
169
+
170
+ 1. **Generates an SBPL profile** with `(deny default)` base policy and explicit `(allow ...)` rules
171
+ 2. **Runs** `sandbox-exec -p '<profile>' /usr/bin/env -i KEY=VAL ... /bin/sh -c '<command>'`
172
+ 3. **Resolves symlinks** via `realpathSync` (macOS uses `/var` -> `/private/var`, `/tmp` -> `/private/tmp`)
173
+ 4. **Cleans environment** using `env -i` (sandbox-exec inherits parent env, unlike bubblewrap's `--clearenv`)
174
+
175
+ ### Configuration
176
+
177
+ ```yaml
178
+ sandboxes:
179
+ mac:
180
+ engine: seatbelt
181
+ network: true # Allow network access (default: true)
182
+ read_only: false # Writable workspace (default: false)
183
+ ```
184
+
185
+ Note: The `workdir` field is ignored for seatbelt — commands run from the real repository path (no mount remapping).
186
+
187
+ ### SBPL Profile
188
+
189
+ The generated profile follows a deny-by-default model:
190
+
191
+ ```scheme
192
+ (version 1)
193
+ (deny default)
194
+
195
+ ;; Process execution
196
+ (allow process-exec)
197
+ (allow process-fork)
198
+
199
+ ;; System paths (read-only)
200
+ (allow file-read*
201
+ (literal "/")
202
+ (subpath "/usr") (subpath "/bin") (subpath "/sbin")
203
+ (subpath "/Library") (subpath "/System")
204
+ (subpath "/private") (subpath "/var") (subpath "/etc")
205
+ (subpath "/dev") (subpath "/tmp"))
206
+
207
+ ;; Temp and device writes
208
+ (allow file-write*
209
+ (subpath "/tmp") (subpath "/private/tmp") (subpath "/dev"))
210
+
211
+ ;; xcrun cache (macOS Xcode tools)
212
+ (allow file-write* (regex #"/private/var/folders/.*/T/xcrun_db"))
213
+
214
+ ;; Workspace access
215
+ (allow file-read* (subpath "/path/to/repo"))
216
+ (allow file-write* (subpath "/path/to/repo")) ;; omitted when read_only
217
+
218
+ ;; Network (omitted when network: false)
219
+ (allow network*)
220
+
221
+ ;; System operations
222
+ (allow sysctl-read)
223
+ (allow mach-lookup)
224
+ (allow signal)
225
+ ```
226
+
227
+ ### Filesystem Access Inside Sandbox
228
+
229
+ | Path | Access | Notes |
230
+ |------|--------|-------|
231
+ | Repository directory | Read-write (or read-only) | Real filesystem path |
232
+ | `/usr`, `/bin`, `/Library`, `/System` | Read-only | System binaries and libraries |
233
+ | `/private`, `/var`, `/etc` | Read-only | System config (symlink-resolved) |
234
+ | `/tmp` | Read-write | Temporary files |
235
+ | `~/Documents`, `~/Desktop` | **Denied** | "Operation not permitted" |
236
+ | `~/.ssh`, `~/.aws`, `~/.claude` | **Denied** | "Operation not permitted" |
237
+ | `~/.gitconfig`, `~/.zsh_history` | **Denied** | "Operation not permitted" |
238
+
239
+ ### Security Properties
240
+
241
+ | Property | Status |
242
+ |----------|--------|
243
+ | Filesystem isolation | ACL-style policy blocks access to unauthorized paths |
244
+ | Process isolation | Limited (no PID namespace) |
245
+ | Environment isolation | `env -i` strips inherited vars; only explicitly passed vars visible |
246
+ | Network isolation | Optional via omitting `(allow network*)` rule |
247
+ | Resource limits | Not enforced |
248
+ | Write protection | `read_only: true` omits file-write rules for workspace |
249
+
250
+ ### Known Limitations
251
+
252
+ - **No mount namespaces**: Commands see real filesystem paths (no `/workspace` remapping)
253
+ - **Git worktrees**: If the repository is a git worktree, the `.git` file points outside the repo directory. Git commands may fail because the parent `.git` directory is not in the allowed paths. Standalone git repos work fine.
254
+ - **Deprecated API**: Apple has deprecated `sandbox-exec` but it remains functional on current macOS versions. There is no replacement API for command-line use.
255
+
256
+ ---
257
+
258
+ ## Choosing an Engine
259
+
260
+ ### Use Docker When
261
+
262
+ - You need custom runtimes, specific OS packages, or language versions
263
+ - Full container isolation is required
264
+ - Cross-platform consistency matters
265
+ - You need cache volumes for persistent caches (e.g., `node_modules`)
266
+
267
+ ### Use Bubblewrap When
268
+
269
+ - Running on Linux and need fast, lightweight isolation
270
+ - CI runners don't have Docker available
271
+ - You're running many short-lived commands (the ~5-50ms overhead adds up much less than Docker's ~500ms)
272
+ - You need namespace-level isolation (PID, mount, network) without containers
273
+
274
+ ### Use Seatbelt When
275
+
276
+ - Running on macOS (local development, macOS CI runners)
277
+ - You want filesystem and network restrictions without Docker
278
+ - You want near-zero setup (sandbox-exec is built into macOS)
279
+
280
+ ### Mixing Engines
281
+
282
+ You can define multiple sandboxes with different engines and assign them per-step:
283
+
284
+ ```yaml
285
+ sandboxes:
286
+ fast:
287
+ engine: bubblewrap # Quick commands
288
+ network: false
289
+
290
+ full:
291
+ image: node:20-alpine # Heavy builds
292
+ cache:
293
+ paths: [node_modules]
294
+
295
+ sandbox: fast # Default to bubblewrap
296
+
297
+ steps:
298
+ lint:
299
+ type: command
300
+ exec: eslint src/ # Uses bubblewrap (fast)
301
+
302
+ build:
303
+ type: command
304
+ sandbox: full # Uses Docker (full isolation)
305
+ exec: npm run build
306
+
307
+ test:
308
+ type: command
309
+ exec: npm test # Uses bubblewrap (fast)
310
+ read_only: true
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Credential Propagation
316
+
317
+ All sandbox engines work with Visor's credential propagation system. The `injectGitHubCredentials()` function from `src/github-auth.ts` passes authentication via environment variables:
318
+
319
+ - `GITHUB_TOKEN` / `GH_TOKEN` for `gh` CLI
320
+ - `GIT_CONFIG_COUNT` / `GIT_CONFIG_KEY_*` / `GIT_CONFIG_VALUE_*` for authenticated `git` HTTPS access
321
+
322
+ No temp files are written and no global git config is modified, so credentials work inside any sandbox engine without special handling.
323
+
324
+ ---
325
+
326
+ ## Environment Variable Filtering
327
+
328
+ Before commands execute in any sandbox engine, environment variables pass through `filterEnvForSandbox()` from `src/sandbox/env-filter.ts`. This applies glob-based patterns from `env_passthrough` config and a built-in passthrough list (`PATH`, `HOME`, `USER`, `CI`, `NODE_ENV`, `LANG`).
329
+
330
+ Only filtered variables are passed into the sandbox:
331
+ - **Bubblewrap**: Via `--setenv KEY VALUE` args
332
+ - **Seatbelt**: Via `env -i KEY=VALUE` args
333
+ - **Docker**: Via `-e KEY=VALUE` args to `docker exec`
334
+
335
+ ---
336
+
337
+ ## Telemetry
338
+
339
+ All sandbox engines emit telemetry events:
340
+
341
+ | Event | Attributes |
342
+ |-------|-----------|
343
+ | `visor.sandbox.bwrap.exec` | `visor.sandbox.name`, `visor.sandbox.exit_code` |
344
+ | `visor.sandbox.seatbelt.exec` | `visor.sandbox.name`, `visor.sandbox.exit_code` |
345
+ | `visor.sandbox.docker.exec` | `visor.sandbox.name`, `visor.sandbox.exit_code` |
346
+
347
+ These integrate with Visor's OpenTelemetry tracing via `src/sandbox/sandbox-telemetry.ts`.
348
+
349
+ ---
350
+
351
+ ## Related Documentation
352
+
353
+ - [Configuration](./configuration.md) - General configuration and `sandboxes:` block
354
+ - [Security](./security.md) - Security overview and best practices
355
+ - [Command Provider](./command-provider.md) - Command execution in sandboxes
356
+ - [GitHub Authentication](./github-auth.md) - Credential propagation into sandboxes
357
+ - [Architecture](./architecture.md) - System architecture overview
@@ -226,6 +226,45 @@ This protection is implemented in the configuration loader and applies to:
226
226
 
227
227
  ---
228
228
 
229
+ ## Process Sandbox Engines
230
+
231
+ Visor supports three sandbox engines that isolate command execution from the host system:
232
+
233
+ | Engine | Platform | Isolation Model |
234
+ |--------|----------|-----------------|
235
+ | **Docker** | Linux, macOS, Windows | Full container isolation |
236
+ | **Bubblewrap** | Linux only | Linux kernel namespaces (PID, mount, network) |
237
+ | **Seatbelt** | macOS only | `sandbox-exec` with SBPL deny-by-default profiles |
238
+
239
+ ### What Sandboxes Protect Against
240
+
241
+ - **Filesystem escape**: Commands cannot access files outside allowed paths (`~/.ssh`, `~/.aws`, `~/.config` are inaccessible)
242
+ - **Environment leakage**: All engines strip inherited environment variables; only explicitly passed vars are visible
243
+ - **Network exfiltration**: Optional network isolation (`network: false`) blocks all network access
244
+ - **Process visibility**: Bubblewrap uses PID namespaces to hide host processes
245
+
246
+ ### What Sandboxes Do NOT Protect Against
247
+
248
+ - **CPU/Memory abuse**: No resource limits enforced by bubblewrap or seatbelt (use Docker `resources:` or external cgroups)
249
+ - **Kernel exploits**: Namespace escapes via kernel bugs (bubblewrap/seatbelt are not full VMs)
250
+ - **Network attacks**: When `network: true` (the default), sandboxed commands have full network access
251
+
252
+ ### Credential Isolation in Sandboxes
253
+
254
+ | Resource | Without Sandbox | With Sandbox |
255
+ |----------|----------------|--------------|
256
+ | `~/.ssh/` | Accessible | Not mounted / denied |
257
+ | `~/.aws/` | Accessible | Not mounted / denied |
258
+ | `~/.gitconfig` | Accessible | Not mounted / denied (git auth via env vars) |
259
+ | `~/.config/gh/` | Accessible | Not mounted / denied |
260
+ | Host env vars | All inherited | Only explicitly passed vars |
261
+
262
+ GitHub credentials are propagated securely via environment variables (`GITHUB_TOKEN`, `GIT_CONFIG_COUNT`/`KEY`/`VALUE`), so authenticated git and `gh` CLI operations work inside any sandbox engine without exposing credential files.
263
+
264
+ See [Sandbox Engines](./sandbox-engines.md) for complete configuration and usage documentation.
265
+
266
+ ---
267
+
229
268
  ## Command Provider Security
230
269
 
231
270
  The command provider executes shell commands with security safeguards.
@@ -465,6 +504,7 @@ See [Configuration](./configuration.md) for complete extends documentation.
465
504
 
466
505
  ## Related Documentation
467
506
 
507
+ - [Sandbox Engines](./sandbox-engines.md) - Process isolation with Docker, Bubblewrap, and Seatbelt
468
508
  - [GitHub Authentication](./github-auth.md) - Token and GitHub App auth setup, credential propagation
469
509
  - [AI Configuration](./ai-configuration.md) - AI provider security options
470
510
  - [HTTP Integration](./http.md) - HTTP authentication and TLS
@@ -2202,6 +2202,11 @@ export declare const configSchema: {
2202
2202
  readonly SandboxConfig: {
2203
2203
  readonly type: "object";
2204
2204
  readonly properties: {
2205
+ readonly engine: {
2206
+ readonly type: "string";
2207
+ readonly enum: readonly ["docker", "bubblewrap", "seatbelt"];
2208
+ readonly description: "Sandbox engine type: 'docker' (default), 'bubblewrap' (Linux namespaces), or 'seatbelt' (macOS sandbox-exec)";
2209
+ };
2205
2210
  readonly image: {
2206
2211
  readonly type: "string";
2207
2212
  readonly description: "Docker image to use (e.g., \"node:20-alpine\")";
@@ -1 +1 @@
1
- {"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/generated/config-schema.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAk4Ff,CAAC;AACX,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/generated/config-schema.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAw4Ff,CAAC;AACX,eAAe,YAAY,CAAC"}
@@ -2431,6 +2431,15 @@
2431
2431
  "SandboxConfig": {
2432
2432
  "type": "object",
2433
2433
  "properties": {
2434
+ "engine": {
2435
+ "type": "string",
2436
+ "enum": [
2437
+ "docker",
2438
+ "bubblewrap",
2439
+ "seatbelt"
2440
+ ],
2441
+ "description": "Sandbox engine type: 'docker' (default), 'bubblewrap' (Linux namespaces), or 'seatbelt' (macOS sandbox-exec)"
2442
+ },
2434
2443
  "image": {
2435
2444
  "type": "string",
2436
2445
  "description": "Docker image to use (e.g., \"node:20-alpine\")"