@sysid/sandbox-runtime-improved 0.0.42-sysid.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.
Files changed (83) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +676 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +166 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.d.ts +11 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +9 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/sandbox/generate-seccomp-filter.d.ts +71 -0
  12. package/dist/sandbox/generate-seccomp-filter.d.ts.map +1 -0
  13. package/dist/sandbox/generate-seccomp-filter.js +263 -0
  14. package/dist/sandbox/generate-seccomp-filter.js.map +1 -0
  15. package/dist/sandbox/http-proxy.d.ts +19 -0
  16. package/dist/sandbox/http-proxy.d.ts.map +1 -0
  17. package/dist/sandbox/http-proxy.js +295 -0
  18. package/dist/sandbox/http-proxy.js.map +1 -0
  19. package/dist/sandbox/linux-sandbox-utils.d.ts +158 -0
  20. package/dist/sandbox/linux-sandbox-utils.d.ts.map +1 -0
  21. package/dist/sandbox/linux-sandbox-utils.js +875 -0
  22. package/dist/sandbox/linux-sandbox-utils.js.map +1 -0
  23. package/dist/sandbox/macos-sandbox-utils.d.ts +41 -0
  24. package/dist/sandbox/macos-sandbox-utils.d.ts.map +1 -0
  25. package/dist/sandbox/macos-sandbox-utils.js +672 -0
  26. package/dist/sandbox/macos-sandbox-utils.js.map +1 -0
  27. package/dist/sandbox/sandbox-config.d.ts +307 -0
  28. package/dist/sandbox/sandbox-config.d.ts.map +1 -0
  29. package/dist/sandbox/sandbox-config.js +195 -0
  30. package/dist/sandbox/sandbox-config.js.map +1 -0
  31. package/dist/sandbox/sandbox-manager.d.ts +42 -0
  32. package/dist/sandbox/sandbox-manager.d.ts.map +1 -0
  33. package/dist/sandbox/sandbox-manager.js +796 -0
  34. package/dist/sandbox/sandbox-manager.js.map +1 -0
  35. package/dist/sandbox/sandbox-schemas.d.ts +57 -0
  36. package/dist/sandbox/sandbox-schemas.d.ts.map +1 -0
  37. package/dist/sandbox/sandbox-schemas.js +3 -0
  38. package/dist/sandbox/sandbox-schemas.js.map +1 -0
  39. package/dist/sandbox/sandbox-utils.d.ts +116 -0
  40. package/dist/sandbox/sandbox-utils.d.ts.map +1 -0
  41. package/dist/sandbox/sandbox-utils.js +463 -0
  42. package/dist/sandbox/sandbox-utils.js.map +1 -0
  43. package/dist/sandbox/sandbox-violation-store.d.ts +19 -0
  44. package/dist/sandbox/sandbox-violation-store.d.ts.map +1 -0
  45. package/dist/sandbox/sandbox-violation-store.js +54 -0
  46. package/dist/sandbox/sandbox-violation-store.js.map +1 -0
  47. package/dist/sandbox/socks-proxy.d.ts +13 -0
  48. package/dist/sandbox/socks-proxy.d.ts.map +1 -0
  49. package/dist/sandbox/socks-proxy.js +95 -0
  50. package/dist/sandbox/socks-proxy.js.map +1 -0
  51. package/dist/utils/config-loader.d.ts +11 -0
  52. package/dist/utils/config-loader.d.ts.map +1 -0
  53. package/dist/utils/config-loader.js +60 -0
  54. package/dist/utils/config-loader.js.map +1 -0
  55. package/dist/utils/debug.d.ts +7 -0
  56. package/dist/utils/debug.d.ts.map +1 -0
  57. package/dist/utils/debug.js +25 -0
  58. package/dist/utils/debug.js.map +1 -0
  59. package/dist/utils/platform.d.ts +15 -0
  60. package/dist/utils/platform.d.ts.map +1 -0
  61. package/dist/utils/platform.js +49 -0
  62. package/dist/utils/platform.js.map +1 -0
  63. package/dist/utils/ripgrep.d.ts +22 -0
  64. package/dist/utils/ripgrep.d.ts.map +1 -0
  65. package/dist/utils/ripgrep.js +45 -0
  66. package/dist/utils/ripgrep.js.map +1 -0
  67. package/dist/utils/which.d.ts +9 -0
  68. package/dist/utils/which.d.ts.map +1 -0
  69. package/dist/utils/which.js +25 -0
  70. package/dist/utils/which.js.map +1 -0
  71. package/dist/vendor/seccomp/arm64/apply-seccomp +0 -0
  72. package/dist/vendor/seccomp/arm64/unix-block.bpf +0 -0
  73. package/dist/vendor/seccomp/x64/apply-seccomp +0 -0
  74. package/dist/vendor/seccomp/x64/unix-block.bpf +0 -0
  75. package/dist/vendor/seccomp-src/apply-seccomp.c +98 -0
  76. package/dist/vendor/seccomp-src/seccomp-unix-block.c +97 -0
  77. package/package.json +88 -0
  78. package/vendor/seccomp/arm64/apply-seccomp +0 -0
  79. package/vendor/seccomp/arm64/unix-block.bpf +0 -0
  80. package/vendor/seccomp/x64/apply-seccomp +0 -0
  81. package/vendor/seccomp/x64/unix-block.bpf +0 -0
  82. package/vendor/seccomp-src/apply-seccomp.c +98 -0
  83. package/vendor/seccomp-src/seccomp-unix-block.c +97 -0
@@ -0,0 +1,463 @@
1
+ import { homedir } from 'os';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { getPlatform } from '../utils/platform.js';
5
+ import { logForDebugging } from '../utils/debug.js';
6
+ /**
7
+ * Dangerous files that should be protected from writes.
8
+ * These files can be used for code execution or data exfiltration.
9
+ */
10
+ export const DANGEROUS_FILES = [
11
+ '.gitconfig',
12
+ '.gitmodules',
13
+ '.bashrc',
14
+ '.bash_profile',
15
+ '.zshrc',
16
+ '.zprofile',
17
+ '.profile',
18
+ '.ripgreprc',
19
+ '.mcp.json',
20
+ ];
21
+ /**
22
+ * Dangerous directories that should be protected from writes.
23
+ * These directories contain sensitive configuration or executable files.
24
+ */
25
+ export const DANGEROUS_DIRECTORIES = ['.git', '.vscode', '.idea'];
26
+ /**
27
+ * Get the list of dangerous directories to deny writes to.
28
+ * Excludes .git since we need it writable for git operations -
29
+ * instead we block specific paths within .git (hooks and config).
30
+ */
31
+ export function getDangerousDirectories() {
32
+ return [
33
+ ...DANGEROUS_DIRECTORIES.filter(d => d !== '.git'),
34
+ '.claude/commands',
35
+ '.claude/agents',
36
+ ];
37
+ }
38
+ /**
39
+ * Normalizes a path for case-insensitive comparison.
40
+ * This prevents bypassing security checks using mixed-case paths on case-insensitive
41
+ * filesystems (macOS/Windows) like `.cLauDe/Settings.locaL.json`.
42
+ *
43
+ * We always normalize to lowercase regardless of platform for consistent security.
44
+ * @param path The path to normalize
45
+ * @returns The lowercase path for safe comparison
46
+ */
47
+ export function normalizeCaseForComparison(pathStr) {
48
+ return pathStr.toLowerCase();
49
+ }
50
+ /**
51
+ * Check if a path pattern contains glob characters
52
+ */
53
+ export function containsGlobChars(pathPattern) {
54
+ return (pathPattern.includes('*') ||
55
+ pathPattern.includes('?') ||
56
+ pathPattern.includes('[') ||
57
+ pathPattern.includes(']'));
58
+ }
59
+ /**
60
+ * Remove trailing /** glob suffix from a path pattern
61
+ * Used to normalize path patterns since /** just means "directory and everything under it"
62
+ */
63
+ export function removeTrailingGlobSuffix(pathPattern) {
64
+ const stripped = pathPattern.replace(/\/\*\*$/, '');
65
+ return stripped || '/';
66
+ }
67
+ /**
68
+ * Check if a symlink resolution crosses expected path boundaries.
69
+ *
70
+ * When resolving symlinks for sandbox path normalization, we need to ensure
71
+ * the resolved path doesn't unexpectedly broaden the scope. This function
72
+ * returns true if the resolved path is an ancestor of the original path
73
+ * or resolves to a system root, which would indicate the symlink points
74
+ * outside expected boundaries.
75
+ *
76
+ * @param originalPath - The original path before symlink resolution
77
+ * @param resolvedPath - The path after fs.realpathSync() resolution
78
+ * @returns true if the resolved path is outside expected boundaries
79
+ */
80
+ export function isSymlinkOutsideBoundary(originalPath, resolvedPath) {
81
+ const normalizedOriginal = path.normalize(originalPath);
82
+ const normalizedResolved = path.normalize(resolvedPath);
83
+ // Same path after normalization - OK
84
+ if (normalizedResolved === normalizedOriginal) {
85
+ return false;
86
+ }
87
+ // Handle macOS /tmp -> /private/tmp canonical resolution
88
+ // This is a legitimate system symlink that should be allowed
89
+ // /tmp/claude -> /private/tmp/claude is OK
90
+ // /var/folders/... -> /private/var/folders/... is OK
91
+ if (normalizedOriginal.startsWith('/tmp/') &&
92
+ normalizedResolved === '/private' + normalizedOriginal) {
93
+ return false;
94
+ }
95
+ if (normalizedOriginal.startsWith('/var/') &&
96
+ normalizedResolved === '/private' + normalizedOriginal) {
97
+ return false;
98
+ }
99
+ // Also handle the reverse: /private/tmp/... resolving to itself
100
+ if (normalizedOriginal.startsWith('/private/tmp/') &&
101
+ normalizedResolved === normalizedOriginal) {
102
+ return false;
103
+ }
104
+ if (normalizedOriginal.startsWith('/private/var/') &&
105
+ normalizedResolved === normalizedOriginal) {
106
+ return false;
107
+ }
108
+ // If resolved path is "/" it's outside expected boundaries
109
+ if (normalizedResolved === '/') {
110
+ return true;
111
+ }
112
+ // If resolved path is very short (single component like /tmp, /usr, /var),
113
+ // it's likely outside expected boundaries
114
+ const resolvedParts = normalizedResolved.split('/').filter(Boolean);
115
+ if (resolvedParts.length <= 1) {
116
+ return true;
117
+ }
118
+ // If original path starts with resolved path, the resolved path is an ancestor
119
+ // e.g., /tmp/claude -> /tmp means the symlink points to a broader scope
120
+ if (normalizedOriginal.startsWith(normalizedResolved + '/')) {
121
+ return true;
122
+ }
123
+ // Also check the canonical form of the original path for macOS
124
+ // e.g., /tmp/claude should also be checked as /private/tmp/claude
125
+ let canonicalOriginal = normalizedOriginal;
126
+ if (normalizedOriginal.startsWith('/tmp/')) {
127
+ canonicalOriginal = '/private' + normalizedOriginal;
128
+ }
129
+ else if (normalizedOriginal.startsWith('/var/')) {
130
+ canonicalOriginal = '/private' + normalizedOriginal;
131
+ }
132
+ if (canonicalOriginal !== normalizedOriginal &&
133
+ canonicalOriginal.startsWith(normalizedResolved + '/')) {
134
+ return true;
135
+ }
136
+ // STRICT CHECK: Only allow resolutions that stay within the expected path tree
137
+ // The resolved path must either:
138
+ // 1. Start with the original path (deeper/same) - already covered by returning false below
139
+ // 2. Start with the canonical original (deeper/same under canonical form)
140
+ // 3. BE the canonical form of the original (e.g., /tmp/x -> /private/tmp/x)
141
+ // Any other resolution (e.g., /tmp/claude -> /Users/dworken) is outside expected bounds
142
+ const resolvedStartsWithOriginal = normalizedResolved.startsWith(normalizedOriginal + '/');
143
+ const resolvedStartsWithCanonical = canonicalOriginal !== normalizedOriginal &&
144
+ normalizedResolved.startsWith(canonicalOriginal + '/');
145
+ const resolvedIsCanonical = canonicalOriginal !== normalizedOriginal &&
146
+ normalizedResolved === canonicalOriginal;
147
+ const resolvedIsSame = normalizedResolved === normalizedOriginal;
148
+ // If resolved path is not within expected tree, it's outside boundary
149
+ if (!resolvedIsSame &&
150
+ !resolvedIsCanonical &&
151
+ !resolvedStartsWithOriginal &&
152
+ !resolvedStartsWithCanonical) {
153
+ return true;
154
+ }
155
+ // Allow resolution to same directory level or deeper within expected tree
156
+ return false;
157
+ }
158
+ /**
159
+ * Normalize a path for use in sandbox configurations
160
+ * Handles:
161
+ * - Tilde (~) expansion for home directory
162
+ * - Relative paths (./foo, ../foo, etc.) converted to absolute
163
+ * - Absolute paths remain unchanged
164
+ * - Symlinks are resolved to their real paths for non-glob patterns
165
+ * - Glob patterns preserve wildcards after path normalization
166
+ *
167
+ * Returns the absolute path with symlinks resolved (or normalized glob pattern)
168
+ */
169
+ export function normalizePathForSandbox(pathPattern) {
170
+ const cwd = process.cwd();
171
+ let normalizedPath = pathPattern;
172
+ // Expand ~ to home directory
173
+ if (pathPattern === '~') {
174
+ normalizedPath = homedir();
175
+ }
176
+ else if (pathPattern.startsWith('~/')) {
177
+ normalizedPath = homedir() + pathPattern.slice(1);
178
+ }
179
+ else if (pathPattern.startsWith('./') || pathPattern.startsWith('../')) {
180
+ // Convert relative to absolute based on current working directory
181
+ normalizedPath = path.resolve(cwd, pathPattern);
182
+ }
183
+ else if (!path.isAbsolute(pathPattern)) {
184
+ // Handle other relative paths (e.g., ".", "..", "foo/bar")
185
+ normalizedPath = path.resolve(cwd, pathPattern);
186
+ }
187
+ // For glob patterns, resolve symlinks for the directory portion only
188
+ if (containsGlobChars(normalizedPath)) {
189
+ // Extract the static directory prefix before glob characters
190
+ const staticPrefix = normalizedPath.split(/[*?[\]]/)[0];
191
+ if (staticPrefix && staticPrefix !== '/') {
192
+ // Get the directory containing the glob pattern
193
+ // If staticPrefix ends with /, remove it to get the directory
194
+ const baseDir = staticPrefix.endsWith('/')
195
+ ? staticPrefix.slice(0, -1)
196
+ : path.dirname(staticPrefix);
197
+ // Try to resolve symlinks for the base directory
198
+ try {
199
+ const resolvedBaseDir = fs.realpathSync(baseDir);
200
+ // Validate that resolution stays within expected boundaries
201
+ if (!isSymlinkOutsideBoundary(baseDir, resolvedBaseDir)) {
202
+ // Reconstruct the pattern with the resolved directory
203
+ const patternSuffix = normalizedPath.slice(baseDir.length);
204
+ return resolvedBaseDir + patternSuffix;
205
+ }
206
+ // If resolution would broaden scope, keep original pattern
207
+ }
208
+ catch {
209
+ // If directory doesn't exist or can't be resolved, keep the original pattern
210
+ }
211
+ }
212
+ return normalizedPath;
213
+ }
214
+ // Resolve symlinks to real paths to avoid bwrap issues
215
+ // Validate that the resolution stays within expected boundaries
216
+ try {
217
+ const resolvedPath = fs.realpathSync(normalizedPath);
218
+ // Only use resolved path if it doesn't cross boundary (e.g., symlink to parent dir)
219
+ if (isSymlinkOutsideBoundary(normalizedPath, resolvedPath)) {
220
+ // Symlink points outside expected boundaries - keep original path
221
+ }
222
+ else {
223
+ normalizedPath = resolvedPath;
224
+ }
225
+ }
226
+ catch {
227
+ // If path doesn't exist or can't be resolved, keep the normalized path
228
+ }
229
+ return normalizedPath;
230
+ }
231
+ /**
232
+ * Get recommended system paths that should be writable for commands to work properly
233
+ *
234
+ * WARNING: These default paths are intentionally broad for compatibility but may
235
+ * allow access to files from other processes. In highly security-sensitive
236
+ * environments, you should configure more restrictive write paths.
237
+ */
238
+ export function getDefaultWritePaths() {
239
+ const homeDir = homedir();
240
+ const recommendedPaths = [
241
+ '/dev/stdout',
242
+ '/dev/stderr',
243
+ '/dev/null',
244
+ '/dev/tty',
245
+ '/dev/dtracehelper',
246
+ '/dev/autofs_nowait',
247
+ '/tmp/claude',
248
+ '/private/tmp/claude',
249
+ path.join(homeDir, '.npm/_logs'),
250
+ path.join(homeDir, '.claude/debug'),
251
+ ];
252
+ return recommendedPaths;
253
+ }
254
+ /**
255
+ * Ensure the sandbox TMPDIR exists so tools like mktemp work inside the sandbox.
256
+ * When TMPDIR is set to a non-existent path, mktemp silently returns an empty
257
+ * string; any subsequent use of that empty string as a redirect target (e.g.
258
+ * `cat $tmp`) reads from stdin and hangs the shell session indefinitely.
259
+ */
260
+ export function ensureSandboxTmpdir() {
261
+ const tmpdir = process.env.CLAUDE_TMPDIR || '/tmp/claude';
262
+ try {
263
+ fs.mkdirSync(tmpdir, { recursive: true });
264
+ }
265
+ catch (err) {
266
+ logForDebugging(`Warning: could not create sandbox TMPDIR ${tmpdir}: ${err}`);
267
+ }
268
+ }
269
+ /**
270
+ * Generate proxy environment variables for sandboxed processes
271
+ */
272
+ export function generateProxyEnvVars(httpProxyPort, socksProxyPort) {
273
+ // Respect CLAUDE_TMPDIR if set, otherwise default to /tmp/claude
274
+ const tmpdir = process.env.CLAUDE_TMPDIR || '/tmp/claude';
275
+ const envVars = [`SANDBOX_RUNTIME=1`, `TMPDIR=${tmpdir}`];
276
+ // If no proxy ports provided, return minimal env vars
277
+ if (!httpProxyPort && !socksProxyPort) {
278
+ return envVars;
279
+ }
280
+ // Make Node's built-in fetch() (undici) honour HTTP_PROXY / HTTPS_PROXY.
281
+ // By default, undici uses a plain Agent that makes direct TCP connections and
282
+ // ignores proxy env vars — unlike curl and other CLI tools. The --use-env-proxy
283
+ // flag (Node 22+) tells the internal undici instance to read these variables.
284
+ // We prepend to any existing NODE_OPTIONS so we don't clobber user flags.
285
+ const nodeMajor = parseInt(process.versions.node.split('.')[0], 10);
286
+ if (nodeMajor >= 22) {
287
+ const existingNodeOptions = process.env.NODE_OPTIONS ?? '';
288
+ const nodeOptions = existingNodeOptions
289
+ ? `${existingNodeOptions} --use-env-proxy`
290
+ : '--use-env-proxy';
291
+ envVars.push(`NODE_OPTIONS=${nodeOptions}`);
292
+ }
293
+ // Always set NO_PROXY to exclude localhost and private networks from proxying
294
+ const noProxyAddresses = [
295
+ 'localhost',
296
+ '127.0.0.1',
297
+ '::1',
298
+ '*.local',
299
+ '.local',
300
+ '169.254.0.0/16', // Link-local
301
+ '10.0.0.0/8', // Private network
302
+ '172.16.0.0/12', // Private network
303
+ '192.168.0.0/16', // Private network
304
+ ].join(',');
305
+ envVars.push(`NO_PROXY=${noProxyAddresses}`);
306
+ envVars.push(`no_proxy=${noProxyAddresses}`);
307
+ if (httpProxyPort) {
308
+ envVars.push(`HTTP_PROXY=http://localhost:${httpProxyPort}`);
309
+ envVars.push(`HTTPS_PROXY=http://localhost:${httpProxyPort}`);
310
+ // Lowercase versions for compatibility with some tools
311
+ envVars.push(`http_proxy=http://localhost:${httpProxyPort}`);
312
+ envVars.push(`https_proxy=http://localhost:${httpProxyPort}`);
313
+ }
314
+ if (socksProxyPort) {
315
+ // Use socks5h:// for proper DNS resolution through proxy
316
+ envVars.push(`ALL_PROXY=socks5h://localhost:${socksProxyPort}`);
317
+ envVars.push(`all_proxy=socks5h://localhost:${socksProxyPort}`);
318
+ // Configure Git to use SSH through the proxy so DNS resolution happens outside the sandbox
319
+ const platform = getPlatform();
320
+ if (platform === 'macos') {
321
+ // macOS: use BSD nc SOCKS5 proxy support (-X 5 -x)
322
+ envVars.push(`GIT_SSH_COMMAND=ssh -o ProxyCommand='nc -X 5 -x localhost:${socksProxyPort} %h %p'`);
323
+ }
324
+ else if (platform === 'linux' && httpProxyPort) {
325
+ // Linux: use socat HTTP CONNECT via the HTTP proxy bridge.
326
+ // socat is already a required Linux sandbox dependency, and PROXY: is
327
+ // portable across all socat versions (unlike SOCKS5-CONNECT which needs >= 1.8.0).
328
+ envVars.push(`GIT_SSH_COMMAND=ssh -o ProxyCommand='socat - PROXY:localhost:%h:%p,proxyport=${httpProxyPort}'`);
329
+ }
330
+ // FTP proxy support (use socks5h for DNS resolution through proxy)
331
+ envVars.push(`FTP_PROXY=socks5h://localhost:${socksProxyPort}`);
332
+ envVars.push(`ftp_proxy=socks5h://localhost:${socksProxyPort}`);
333
+ // rsync proxy support
334
+ envVars.push(`RSYNC_PROXY=localhost:${socksProxyPort}`);
335
+ // Database tools NOTE: Most database clients don't have built-in proxy support
336
+ // You typically need to use SSH tunneling or a SOCKS wrapper like tsocks/proxychains
337
+ // Docker CLI uses HTTP for the API
338
+ // This makes Docker use the HTTP proxy for registry operations
339
+ envVars.push(`DOCKER_HTTP_PROXY=http://localhost:${httpProxyPort || socksProxyPort}`);
340
+ envVars.push(`DOCKER_HTTPS_PROXY=http://localhost:${httpProxyPort || socksProxyPort}`);
341
+ // Kubernetes kubectl - uses standard HTTPS_PROXY
342
+ // kubectl respects HTTPS_PROXY which we already set above
343
+ // AWS CLI - uses standard HTTPS_PROXY (v2 supports it well)
344
+ // AWS CLI v2 respects HTTPS_PROXY which we already set above
345
+ // Google Cloud SDK - has specific proxy settings
346
+ // Use HTTPS proxy to match other HTTP-based tools
347
+ if (httpProxyPort) {
348
+ envVars.push(`CLOUDSDK_PROXY_TYPE=https`);
349
+ envVars.push(`CLOUDSDK_PROXY_ADDRESS=localhost`);
350
+ envVars.push(`CLOUDSDK_PROXY_PORT=${httpProxyPort}`);
351
+ }
352
+ // Azure CLI - uses HTTPS_PROXY
353
+ // Azure CLI respects HTTPS_PROXY which we already set above
354
+ // Terraform - uses standard HTTP/HTTPS proxy vars
355
+ // Terraform respects HTTP_PROXY/HTTPS_PROXY which we already set above
356
+ // gRPC-based tools - use standard proxy vars
357
+ envVars.push(`GRPC_PROXY=socks5h://localhost:${socksProxyPort}`);
358
+ envVars.push(`grpc_proxy=socks5h://localhost:${socksProxyPort}`);
359
+ }
360
+ // WARNING: Do not set HTTP_PROXY/HTTPS_PROXY to SOCKS URLs when only SOCKS proxy is available
361
+ // Most HTTP clients do not support SOCKS URLs in these variables and will fail, and we want
362
+ // to avoid overriding the client otherwise respecting the ALL_PROXY env var which points to SOCKS.
363
+ return envVars;
364
+ }
365
+ /**
366
+ * Encode a command for sandbox monitoring
367
+ * Truncates to 100 chars and base64 encodes to avoid parsing issues
368
+ */
369
+ export function encodeSandboxedCommand(command) {
370
+ const truncatedCommand = command.slice(0, 100);
371
+ return Buffer.from(truncatedCommand).toString('base64');
372
+ }
373
+ /**
374
+ * Decode a base64-encoded command from sandbox monitoring
375
+ */
376
+ export function decodeSandboxedCommand(encodedCommand) {
377
+ return Buffer.from(encodedCommand, 'base64').toString('utf8');
378
+ }
379
+ /**
380
+ * Convert a glob pattern to a regular expression
381
+ *
382
+ * This implements gitignore-style pattern matching to match the behavior of the
383
+ * `ignore` library used by the permission system.
384
+ *
385
+ * Supported patterns:
386
+ * - * matches any characters except / (e.g., *.ts matches foo.ts but not foo/bar.ts)
387
+ * - ** matches any characters including / (e.g., src/**\/*.ts matches all .ts files in src/)
388
+ * - ? matches any single character except / (e.g., file?.txt matches file1.txt)
389
+ * - [abc] matches any character in the set (e.g., file[0-9].txt matches file3.txt)
390
+ *
391
+ * Exported for testing and shared between macOS sandbox profiles and Linux glob expansion.
392
+ */
393
+ export function globToRegex(globPattern) {
394
+ return ('^' +
395
+ globPattern
396
+ // Escape regex special characters (except glob chars * ? [ ])
397
+ .replace(/[.^$+{}()|\\]/g, '\\$&')
398
+ // Escape unclosed brackets (no matching ])
399
+ .replace(/\[([^\]]*?)$/g, '\\[$1')
400
+ // Convert glob patterns to regex (order matters - ** before *)
401
+ .replace(/\*\*\//g, '__GLOBSTAR_SLASH__') // Placeholder for **/
402
+ .replace(/\*\*/g, '__GLOBSTAR__') // Placeholder for **
403
+ .replace(/\*/g, '[^/]*') // * matches anything except /
404
+ .replace(/\?/g, '[^/]') // ? matches single character except /
405
+ // Restore placeholders
406
+ .replace(/__GLOBSTAR_SLASH__/g, '(.*/)?') // **/ matches zero or more dirs
407
+ .replace(/__GLOBSTAR__/g, '.*') + // ** matches anything including /
408
+ '$');
409
+ }
410
+ /**
411
+ * Expand a glob pattern into concrete file paths.
412
+ *
413
+ * Used on Linux where bubblewrap doesn't support glob patterns natively.
414
+ * Resolves the static directory prefix, lists files recursively, and filters
415
+ * using globToRegex().
416
+ *
417
+ * @param globPath - A path pattern containing glob characters (e.g., ~/test/*.env)
418
+ * @returns Array of absolute paths matching the glob pattern
419
+ */
420
+ export function expandGlobPattern(globPath) {
421
+ const normalizedPattern = normalizePathForSandbox(globPath);
422
+ // Extract the static directory prefix before any glob characters
423
+ const staticPrefix = normalizedPattern.split(/[*?[\]]/)[0];
424
+ if (!staticPrefix || staticPrefix === '/') {
425
+ logForDebugging(`[Sandbox] Glob pattern too broad, skipping: ${globPath}`);
426
+ return [];
427
+ }
428
+ // Get the base directory from the static prefix
429
+ const baseDir = staticPrefix.endsWith('/')
430
+ ? staticPrefix.slice(0, -1)
431
+ : path.dirname(staticPrefix);
432
+ if (!fs.existsSync(baseDir)) {
433
+ logForDebugging(`[Sandbox] Base directory for glob does not exist: ${baseDir}`);
434
+ return [];
435
+ }
436
+ // Build regex from the normalized glob pattern
437
+ const regex = new RegExp(globToRegex(normalizedPattern));
438
+ // List all entries recursively under the base directory
439
+ const results = [];
440
+ try {
441
+ const entries = fs.readdirSync(baseDir, {
442
+ recursive: true,
443
+ withFileTypes: true,
444
+ });
445
+ for (const entry of entries) {
446
+ // Build the full path for this entry
447
+ // entry.parentPath is the directory containing this entry (available in Node 20+/Bun)
448
+ // For compatibility, fall back to entry.path if parentPath is not available
449
+ const parentDir = entry.parentPath ??
450
+ entry.path ??
451
+ baseDir;
452
+ const fullPath = path.join(parentDir, entry.name);
453
+ if (regex.test(fullPath)) {
454
+ results.push(fullPath);
455
+ }
456
+ }
457
+ }
458
+ catch (err) {
459
+ logForDebugging(`[Sandbox] Error expanding glob pattern ${globPath}: ${err}`);
460
+ }
461
+ return results;
462
+ }
463
+ //# sourceMappingURL=sandbox-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-utils.js","sourceRoot":"","sources":["../../src/sandbox/sandbox-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type SandboxViolationEvent } from './macos-sandbox-utils.js';
2
+ /**
3
+ * In-memory tail for sandbox violations
4
+ */
5
+ export declare class SandboxViolationStore {
6
+ private violations;
7
+ private totalCount;
8
+ private readonly maxSize;
9
+ private listeners;
10
+ addViolation(violation: SandboxViolationEvent): void;
11
+ getViolations(limit?: number): SandboxViolationEvent[];
12
+ getCount(): number;
13
+ getTotalCount(): number;
14
+ getViolationsForCommand(command: string): SandboxViolationEvent[];
15
+ clear(): void;
16
+ subscribe(listener: (violations: SandboxViolationEvent[]) => void): () => void;
17
+ private notifyListeners;
18
+ }
19
+ //# sourceMappingURL=sandbox-violation-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-violation-store.d.ts","sourceRoot":"","sources":["../../src/sandbox/sandbox-violation-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAGrE;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,SAAS,CACN;IAEX,YAAY,CAAC,SAAS,EAAE,qBAAqB,GAAG,IAAI;IASpD,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,qBAAqB,EAAE;IAOtD,QAAQ,IAAI,MAAM;IAIlB,aAAa,IAAI,MAAM;IAIvB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE;IAKjE,KAAK,IAAI,IAAI;IAMb,SAAS,CACP,QAAQ,EAAE,CAAC,UAAU,EAAE,qBAAqB,EAAE,KAAK,IAAI,GACtD,MAAM,IAAI;IAQb,OAAO,CAAC,eAAe;CAKxB"}
@@ -0,0 +1,54 @@
1
+ import { encodeSandboxedCommand } from './sandbox-utils.js';
2
+ /**
3
+ * In-memory tail for sandbox violations
4
+ */
5
+ export class SandboxViolationStore {
6
+ constructor() {
7
+ this.violations = [];
8
+ this.totalCount = 0;
9
+ this.maxSize = 100;
10
+ this.listeners = new Set();
11
+ }
12
+ addViolation(violation) {
13
+ this.violations.push(violation);
14
+ this.totalCount++;
15
+ if (this.violations.length > this.maxSize) {
16
+ this.violations = this.violations.slice(-this.maxSize);
17
+ }
18
+ this.notifyListeners();
19
+ }
20
+ getViolations(limit) {
21
+ if (limit === undefined) {
22
+ return [...this.violations];
23
+ }
24
+ return this.violations.slice(-limit);
25
+ }
26
+ getCount() {
27
+ return this.violations.length;
28
+ }
29
+ getTotalCount() {
30
+ return this.totalCount;
31
+ }
32
+ getViolationsForCommand(command) {
33
+ const commandBase64 = encodeSandboxedCommand(command);
34
+ return this.violations.filter(v => v.encodedCommand === commandBase64);
35
+ }
36
+ clear() {
37
+ this.violations = [];
38
+ // Don't reset totalCount when clearing
39
+ this.notifyListeners();
40
+ }
41
+ subscribe(listener) {
42
+ this.listeners.add(listener);
43
+ listener(this.getViolations());
44
+ return () => {
45
+ this.listeners.delete(listener);
46
+ };
47
+ }
48
+ notifyListeners() {
49
+ // Always notify with all violations so listeners can track the full count
50
+ const violations = this.getViolations();
51
+ this.listeners.forEach(listener => listener(violations));
52
+ }
53
+ }
54
+ //# sourceMappingURL=sandbox-violation-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-violation-store.js","sourceRoot":"","sources":["../../src/sandbox/sandbox-violation-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAE3D;;GAEG;AACH,MAAM,OAAO,qBAAqB;IAAlC;QACU,eAAU,GAA4B,EAAE,CAAA;QACxC,eAAU,GAAG,CAAC,CAAA;QACL,YAAO,GAAG,GAAG,CAAA;QACtB,cAAS,GACf,IAAI,GAAG,EAAE,CAAA;IAoDb,CAAC;IAlDC,YAAY,CAAC,SAAgC;QAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,UAAU,EAAE,CAAA;QACjB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,CAAC,eAAe,EAAE,CAAA;IACxB,CAAC;IAED,aAAa,CAAC,KAAc;QAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAA;QAC7B,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAA;IACtC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAA;IAC/B,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IAED,uBAAuB,CAAC,OAAe;QACrC,MAAM,aAAa,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAA;QACrD,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,aAAa,CAAC,CAAA;IACxE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,EAAE,CAAA;QACpB,uCAAuC;QACvC,IAAI,CAAC,eAAe,EAAE,CAAA;IACxB,CAAC;IAED,SAAS,CACP,QAAuD;QAEvD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC5B,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;QAC9B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACjC,CAAC,CAAA;IACH,CAAC;IAEO,eAAe;QACrB,0EAA0E;QAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;QACvC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAA;IAC1D,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { Socks5Server } from '@pondwader/socks5-server';
2
+ export interface SocksProxyServerOptions {
3
+ filter(port: number, host: string): Promise<boolean> | boolean;
4
+ }
5
+ export interface SocksProxyWrapper {
6
+ server: Socks5Server;
7
+ getPort(): number | undefined;
8
+ listen(port: number, hostname: string): Promise<number>;
9
+ close(): Promise<void>;
10
+ unref(): void;
11
+ }
12
+ export declare function createSocksProxyServer(options: SocksProxyServerOptions): SocksProxyWrapper;
13
+ //# sourceMappingURL=socks-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socks-proxy.d.ts","sourceRoot":"","sources":["../../src/sandbox/socks-proxy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAI5D,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CAC/D;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAA;IACpB,OAAO,IAAI,MAAM,GAAG,SAAS,CAAA;IAC7B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,iBAAiB,CAqGnB"}