Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d587d9f
feat: US-023 - V8 sidecar: native dynamic import() via HostImportModu…
NathanFlurry Mar 21, 2026
5d5f90f
feat: US-024 - V8 sidecar: use native ESM mode for ESM files (stop co…
NathanFlurry Mar 22, 2026
e0b0fa6
chore: update PRD and progress for US-024
NathanFlurry Mar 22, 2026
d823cd5
feat: US-025 - Remove JS-side ESM hacks after V8 native ESM support
NathanFlurry Mar 22, 2026
4ccab1b
chore: update PRD and progress for US-025
NathanFlurry Mar 22, 2026
9a3599c
feat: US-026 - Fix streaming stdin delivery from PTY to sandbox process
NathanFlurry Mar 22, 2026
7a3e8e8
chore: update PRD and progress for US-026
NathanFlurry Mar 22, 2026
c05ed84
chore: US-027 bridge improvements for Pi in-VM execution
NathanFlurry Mar 22, 2026
a09193d
chore: US-027 bridge improvements for Pi in-VM execution
NathanFlurry Mar 22, 2026
ea8947c
chore: update PRD and progress for US-027
NathanFlurry Mar 22, 2026
649d6c9
feat: US-027 - Pi headless tests running in-VM (native ESM)
NathanFlurry Mar 22, 2026
f31ef1e
chore: update PRD and progress for US-027
NathanFlurry Mar 22, 2026
7e9d773
chore: US-028 bridge fixes for Pi interactive TUI
NathanFlurry Mar 22, 2026
e079fcd
chore: update PRD and progress for US-028
NathanFlurry Mar 22, 2026
3a428a7
chore: US-028 add keepalive timer to Pi interactive sandbox code
NathanFlurry Mar 22, 2026
ca4e88d
chore: US-028 V8 event loop infrastructure for Pi interactive TUI
NathanFlurry Mar 22, 2026
0b7c297
chore: US-028 route nextTick/queueMicrotask/timers through bridge
NathanFlurry Mar 22, 2026
d95b3b6
chore: update PRD and progress for US-028
NathanFlurry Mar 22, 2026
ad6ab04
chore: US-028 fix V8 SIGSEGV with Intl.Segmenter polyfill + module ca…
NathanFlurry Mar 22, 2026
3aab776
chore: update PRD and progress for US-028
NathanFlurry Mar 22, 2026
8f0d437
feat: US-028 Pi interactive tests pass — PTY icrnl fix + process exit…
NathanFlurry Mar 22, 2026
a11d1eb
chore: update PRD and progress for US-028
NathanFlurry Mar 22, 2026
aa5e8b3
docs: enforce in-VM execution for all CLI tool tests, ban child_proce…
NathanFlurry Mar 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,30 @@

- NEVER mock external services in tests — use real implementations (Docker containers for databases/services, real HTTP servers for network tests, real binaries for CLI tool tests)
- tests that validate sandbox behavior MUST run code through the secure-exec sandbox (NodeRuntime/proc.exec()), never directly on the host
- CLI tool tests (Pi, Claude Code, OpenCode) must execute inside the sandbox: Pi runs as JS in the VM, Claude Code and OpenCode spawn their binaries via the sandbox's child_process.spawn bridge
- NOTHING runs on the host except Docker containers for e2e-docker tests — all CLI tool code executes inside the sandbox VM
- Pi, Claude Code, and OpenCode are ALL pure JavaScript/TypeScript — they ALL run in-VM via `import()` through `kernel.openShell()` or `kernel.spawn()`
- Claude Code is a bundled ESM Node.js script (`@anthropic-ai/claude-code/cli.js`), not a native binary — its `.node` addons (tree-sitter, audio-capture) are optional and gracefully degrade
- OpenCode is TypeScript (https://github.com/anomalyco/opencode) — the distributed `opencode` command is a Bun-compiled binary but the source is vanilla TS/JS; build the JS bundle from source and run it in-VM
- if the sandbox can't run something, that is a secure-exec bug to fix, not a reason to spawn on the host
- NEVER work around sandbox limitations with host-side execution — this is the #1 rule for CLI tool tests:
- do NOT use `child_process.spawn` or `child_process.spawnSync` from INSIDE sandbox code to run a tool binary on the host (e.g. `spawnSync('claude', [...args])` routing through the child_process bridge) — this is still host execution, the tool's JS runs on the host not in the V8 isolate
- do NOT use `node:child_process.spawn` from TEST code to run tools on the host
- do NOT create `HostBinaryDriver` classes that spawn binaries on the host
- do NOT use `script -qefc` or `python3 pty.spawn` to give host processes a PTY
- do NOT add `sandboxSkip` / probe-based skip logic that silently skips when the sandbox can't do something
- do NOT mark a story as passing if the tool runs on the host instead of in the V8 isolate
- the ONLY correct pattern is: `kernel.spawn('node', ['-e', 'import("tool-entry.js")'])` or equivalent — the tool's JavaScript executes inside the V8 sandbox isolate
- if `import()` hangs, if ESM loading fails, if the TUI crashes — those are secure-exec bugs to fix in packages/nodejs/src/, packages/core/src/, or native/v8-runtime/src/
- e2e-docker fixtures connect to real Docker containers (Postgres, MySQL, Redis, SSH/SFTP) — skip gracefully via `skipUnlessDocker()` when Docker is unavailable
- interactive/PTY tests must use `kernel.openShell()` with `@xterm/headless`, not host PTY via `script -qefc`
- CLI tool tests (Pi, Claude Code, OpenCode) must support both mock and real LLM API tokens:
- check `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` env vars at test startup
- if a real token is present, use it instead of the mock LLM server — this validates true e2e behavior
- Pi supports both Anthropic and OpenAI tokens; OpenCode uses OpenAI; Claude Code uses Anthropic
- log which mode each test suite is using at startup: `"Using real ANTHROPIC_API_KEY"`, `"Using real OPENAI_API_KEY"`, or `"Using mock LLM server"`
- tests must pass with both mock and real tokens — mock is the fallback, real is preferred
- to run with real tokens locally: `source ~/misc/env.txt` before running tests
- real-token tests may use longer timeouts (up to 60s) since they hit external APIs

## Tooling

Expand Down
4 changes: 2 additions & 2 deletions native/v8-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion native/v8-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name = "secure-exec-v8"
path = "src/main.rs"

[dependencies]
v8 = "130"
v8 = "134"
crossbeam-channel = "0.5"
signal-hook = "0.3"
libc = "0.2"
3 changes: 1 addition & 2 deletions native/v8-runtime/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,7 @@ pub fn resolve_pending_promise(
resolver.resolve(scope, undef.into());
}

// Flush microtasks after resolution
scope.perform_microtask_checkpoint();
// Microtask checkpoint is the caller's responsibility (explicit policy).

Ok(())
}
Loading
Loading