diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/claude-code-default-sandbox.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/claude-code-default-sandbox.json new file mode 100644 index 00000000..4450fd04 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/claude-code-default-sandbox.json @@ -0,0 +1,12 @@ +{ + "network": { + "allowedDomains": [], + "deniedDomains": [] + }, + "filesystem": { + "denyRead": [], + "allowRead": [], + "allowWrite": ["."], + "denyWrite": [] + } +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/input.txt b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/input.txt new file mode 100644 index 00000000..23fde028 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/input.txt @@ -0,0 +1 @@ +tracked input diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/package.json new file mode 100644 index 00000000..e13f11cf --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/package.json @@ -0,0 +1,4 @@ +{ + "name": "sandboxed-fspy", + "private": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots.toml new file mode 100644 index 00000000..a99b8ea2 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots.toml @@ -0,0 +1,78 @@ +[[e2e]] +name = "fspy_under_codex_sandbox" +comment = """ +Runs `vt run inner` under Codex CLI's built-in `:workspace` permission profile, representing its default workspace-editing posture for a trusted repository. The profile makes the workspace roots and system temp directories writable without adding network or Unix socket access. See [Codex permissions](https://learn.chatgpt.com/docs/permissions#define-and-select-a-profile). + +The nested `vt` enables fspy for automatic input inference; changing the file read inside the sandbox checks whether it invalidates the cache. +""" +platform = "macos" +ignore = true +steps = [ + [ + "codex", + "sandbox", + "-P", + ":workspace", + "vt", + "run", + "inner", + ], + [ + "vtt", + "replace-file-content", + "input.txt", + "tracked", + "modified", + ], + [ + "codex", + "sandbox", + "-P", + ":workspace", + "vt", + "run", + "inner", + ], +] + +[[e2e]] +name = "fspy_under_anthropic_sandbox_runtime" +comment = """ +Runs `vt run inner` under a profile matching Claude Code's default enabled Bash sandbox: the working directory and session temp directory are writable, with no pre-allowed network domains or extra Unix socket access. See [Claude Code sandboxing](https://code.claude.com/docs/en/sandboxing#filesystem-isolation). + +Claude Code normally creates the writable session temp before invoking Sandbox Runtime, so the harness creates the runtime's default `/tmp/claude` directory before calling `srt` directly. The fixture profile provides only `allowWrite: ["."]`; Sandbox Runtime supplies `/tmp/claude` and its other built-in compatibility paths. See [`getDefaultWritePaths` and `generateProxyEnvVars`](https://github.com/anthropic-experimental/sandbox-runtime/blob/main/src/sandbox/sandbox-utils.ts). + +The nested `vt` enables fspy for automatic input inference; changing the file read inside the sandbox checks whether it invalidates the cache. +""" +platform = "macos" +ignore = true +steps = [ + { argv = [ + "mkdir", + "-p", + "/tmp/claude", + ], comment = "create the session temp that Claude Code supplies before sandboxed Bash commands" }, + [ + "srt", + "--settings", + "claude-code-default-sandbox.json", + "vt", + "run", + "inner", + ], + [ + "vtt", + "replace-file-content", + "input.txt", + "tracked", + "modified", + ], + [ + "srt", + "--settings", + "claude-code-default-sandbox.json", + "vt", + "run", + "inner", + ], +] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots/fspy_under_anthropic_sandbox_runtime.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots/fspy_under_anthropic_sandbox_runtime.md new file mode 100644 index 00000000..5dfc3230 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots/fspy_under_anthropic_sandbox_runtime.md @@ -0,0 +1,37 @@ +# fspy_under_anthropic_sandbox_runtime + +Runs `vt run inner` under a profile matching Claude Code's default enabled Bash sandbox: the working directory and session temp directory are writable, with no pre-allowed network domains or extra Unix socket access. See [Claude Code sandboxing](https://code.claude.com/docs/en/sandboxing#filesystem-isolation). + +Claude Code normally creates the writable session temp before invoking Sandbox Runtime, so the harness creates the runtime's default `/tmp/claude` directory before calling `srt` directly. The fixture profile provides only `allowWrite: ["."]`; Sandbox Runtime supplies `/tmp/claude` and its other built-in compatibility paths. See [`getDefaultWritePaths` and `generateProxyEnvVars`](https://github.com/anthropic-experimental/sandbox-runtime/blob/main/src/sandbox/sandbox-utils.ts). + +The nested `vt` enables fspy for automatic input inference; changing the file read inside the sandbox checks whether it invalidates the cache. + +## `mkdir -p /tmp/claude` + +create the session temp that Claude Code supplies before sandboxed Bash commands + +``` +``` + +## `srt --settings claude-code-default-sandbox.json vt run inner` + +**Exit code:** 1 + +``` +$ vtt print-file input.txt +✗ Failed to set up task communication: Operation not permitted (os error 1) +``` + +## `vtt replace-file-content input.txt tracked modified` + +``` +``` + +## `srt --settings claude-code-default-sandbox.json vt run inner` + +**Exit code:** 1 + +``` +$ vtt print-file input.txt +✗ Failed to set up task communication: Operation not permitted (os error 1) +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots/fspy_under_codex_sandbox.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots/fspy_under_codex_sandbox.md new file mode 100644 index 00000000..05426b33 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/snapshots/fspy_under_codex_sandbox.md @@ -0,0 +1,28 @@ +# fspy_under_codex_sandbox + +Runs `vt run inner` under Codex CLI's built-in `:workspace` permission profile, representing its default workspace-editing posture for a trusted repository. The profile makes the workspace roots and system temp directories writable without adding network or Unix socket access. See [Codex permissions](https://learn.chatgpt.com/docs/permissions#define-and-select-a-profile). + +The nested `vt` enables fspy for automatic input inference; changing the file read inside the sandbox checks whether it invalidates the cache. + +## `codex sandbox -P :workspace vt run inner` + +**Exit code:** 1 + +``` +$ vtt print-file input.txt +✗ Failed to set up task communication: Operation not permitted (os error 1) +``` + +## `vtt replace-file-content input.txt tracked modified` + +``` +``` + +## `codex sandbox -P :workspace vt run inner` + +**Exit code:** 1 + +``` +$ vtt print-file input.txt +✗ Failed to set up task communication: Operation not permitted (os error 1) +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/vite-task.json new file mode 100644 index 00000000..5fe67e08 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/sandboxed_fspy/vite-task.json @@ -0,0 +1,14 @@ +{ + "tasks": { + "inner": { + "command": "vtt print-file input.txt", + "cache": true, + "input": [ + { + "auto": true + } + ], + "output": [] + } + } +} diff --git a/packages/tools/package.json b/packages/tools/package.json index 0fb97185..d07450c5 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -3,6 +3,8 @@ "private": true, "type": "module", "dependencies": { + "@anthropic-ai/sandbox-runtime": "catalog:", + "@openai/codex": "catalog:", "@playwright/browser-chromium": "catalog:", "@vitest/browser-playwright": "catalog:", "@voidzero-dev/vite-task-client": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c37ff286..9681ac3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,12 @@ settings: catalogs: default: + '@anthropic-ai/sandbox-runtime': + specifier: 0.0.67 + version: 0.0.67 + '@openai/codex': + specifier: 0.145.0 + version: 0.145.0 '@playwright/browser-chromium': specifier: 1.61.1 version: 1.61.1 @@ -73,6 +79,12 @@ importers: packages/tools: dependencies: + '@anthropic-ai/sandbox-runtime': + specifier: 'catalog:' + version: 0.0.67 + '@openai/codex': + specifier: 'catalog:' + version: 0.145.0 '@playwright/browser-chromium': specifier: 'catalog:' version: 1.61.1 @@ -114,6 +126,11 @@ importers: packages: + '@anthropic-ai/sandbox-runtime@0.0.67': + resolution: {integrity: sha512-4doSyr6KNdc/4zARMXYEawhFu3z6bPQjgKRq3lKp6dbgEYVMv39oaLJ28QsDc7TmLvrLqzHW+VzD2LAXxvnw8A==} + engines: {node: '>=20.11.0'} + hasBin: true + '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -182,6 +199,47 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@openai/codex@0.145.0': + resolution: {integrity: sha512-/PSPSFujjjmiyVFvG2yu/grOFhsWdokTH8t2KGWhXSo/M5n/dIDsnbsnO82/7bLtIoDuzQf7ATBUMWqPWQINlQ==} + engines: {node: '>=16'} + hasBin: true + + '@openai/codex@0.145.0-darwin-arm64': + resolution: {integrity: sha512-h6aQ0UxnaP8mIM/9/qPAH9MNkRliJo88toq1T36IxNM2L5JSU0TFamu+MZn7YkFgDsrp0RfiI+97Tm8AVVxqtA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@openai/codex@0.145.0-darwin-x64': + resolution: {integrity: sha512-FCYzVKCa9VoLtg9gVyzKpqylonfgZrfcWZN6HsXAZPeuo8CukdMqdgTUOhDn2V6h3MbqS0z6VqQVKUllN/yKhA==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@openai/codex@0.145.0-linux-arm64': + resolution: {integrity: sha512-8OLcPXaAol/FOrRoDxWhIiHIFa73KRsM41EKocjRZOwiT4TcelzJWn3dHyiuSb7teWF25rrslvSPyvhULYRRCQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@openai/codex@0.145.0-linux-x64': + resolution: {integrity: sha512-u8w8LLv3DvsfrDCoswLIemZ0SoNEXyi511WsfFsSiYUazk9qMsB/NtU8N9vhAfN7mZAxLFoMex4v66JjHuZWwA==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@openai/codex@0.145.0-win32-arm64': + resolution: {integrity: sha512-sub61rjEFevi1i3Zx7nAd4JM5XxoNFqMqFc5LfTo2xSI8ixHjFvEYDFDXwXOftT04n3Ht1Wh271ioUZpDiEjEg==} + engines: {node: '>=16'} + cpu: [arm64] + os: [win32] + + '@openai/codex@0.145.0-win32-x64': + resolution: {integrity: sha512-u0h9lk094CaXRSqE34SBW2dRaQTPa6fASXqehczWH9QdsU62mBsiAgAdp6tCG4i+YzPmmhjD8FdXNnYGNmwuMg==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + '@oven/bun-darwin-aarch64@1.3.14': resolution: {integrity: sha512-Omj20SuiHBOUjUBIyqtkNjSUIjOtEOJwmbix/ZyFH4BaQ6OZTaaRWIR4TjHVz0yadHgli6lLTiAh1uarnvD49A==} cpu: [arm64] @@ -564,6 +622,9 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@pondwader/socks5-server@1.0.10': + resolution: {integrity: sha512-bQY06wzzR8D2+vVCUoBsr5QS2U6UgPUQRmErNwtsuI6vLcyRKkafjkr3KxbtGFf9aBBIV2mcvlsKD1UYaIV+sg==} + '@rolldown/binding-android-arm64@1.1.5': resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1057,6 +1118,10 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1209,6 +1274,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + node-forge@1.4.0: + resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} + engines: {node: '>= 6.13.0'} + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -1470,8 +1539,18 @@ packages: yuku-parser@0.5.48: resolution: {integrity: sha512-OWBfhrpgK9+/4+IXG9oT8Bao4AhViQA7vdyNNH7EUg8dQYgwa70XtIBWTpCEme1P1ECyoDNYkn0wT63f8XRcVA==} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + snapshots: + '@anthropic-ai/sandbox-runtime@0.0.67': + dependencies: + '@pondwader/socks5-server': 1.0.10 + commander: 12.1.0 + node-forge: 1.4.0 + zod: 3.25.76 + '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -1529,6 +1608,33 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@openai/codex@0.145.0': + optionalDependencies: + '@openai/codex-darwin-arm64': '@openai/codex@0.145.0-darwin-arm64' + '@openai/codex-darwin-x64': '@openai/codex@0.145.0-darwin-x64' + '@openai/codex-linux-arm64': '@openai/codex@0.145.0-linux-arm64' + '@openai/codex-linux-x64': '@openai/codex@0.145.0-linux-x64' + '@openai/codex-win32-arm64': '@openai/codex@0.145.0-win32-arm64' + '@openai/codex-win32-x64': '@openai/codex@0.145.0-win32-x64' + + '@openai/codex@0.145.0-darwin-arm64': + optional: true + + '@openai/codex@0.145.0-darwin-x64': + optional: true + + '@openai/codex@0.145.0-linux-arm64': + optional: true + + '@openai/codex@0.145.0-linux-x64': + optional: true + + '@openai/codex@0.145.0-win32-arm64': + optional: true + + '@openai/codex@0.145.0-win32-x64': + optional: true + '@oven/bun-darwin-aarch64@1.3.14': optional: true @@ -1727,6 +1833,8 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@pondwader/socks5-server@1.0.10': {} + '@rolldown/binding-android-arm64@1.1.5': optional: true @@ -2099,6 +2207,8 @@ snapshots: chai@6.2.2: {} + commander@12.1.0: {} + convert-source-map@2.0.0: {} cross-env@10.1.0: @@ -2208,6 +2318,8 @@ snapshots: nanoid@3.3.12: {} + node-forge@1.4.0: {} + obug@2.1.1: {} oxfmt@0.60.0(vite-plus@0.2.6(@types/node@25.0.3)(@vitest/browser-playwright@4.1.10(@voidzero-dev/vite-plus-core@0.2.4(@types/node@25.0.3)(typescript@6.0.3))(playwright@1.61.1)(vitest@4.1.10))(@voidzero-dev/vite-plus-core@0.2.4(@types/node@25.0.3)(typescript@6.0.3))(typescript@6.0.3)): @@ -2642,3 +2754,5 @@ snapshots: '@yuku-parser/binding-linux-x64-musl': 0.5.48 '@yuku-parser/binding-win32-arm64': 0.5.48 '@yuku-parser/binding-win32-x64': 0.5.48 + + zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 638a4a9f..8f0ec742 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,6 +9,8 @@ allowBuilds: deno: true catalog: + '@anthropic-ai/sandbox-runtime': 0.0.67 + '@openai/codex': 0.145.0 '@tsconfig/strictest': ^2.0.8 '@types/node': 25.0.3 '@playwright/browser-chromium': 1.61.1