{"_id":"@brainst0rm/sandbox","name":"@brainst0rm/sandbox","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@brainst0rm/sandbox","version":"0.1.0","repository":{"type":"git","url":"git+https://github.com/justinjilg/brainstorm.git","directory":"packages/sandbox"},"type":"module","description":"MicroVM sandbox abstraction for the Brainstorm endpoint agent. Defines the Sandbox interface (boot/executeTool/reset/shutdown) consumed by the endpoint dispatcher (P3.3) and provides a Cloud Hypervisor backend (P3.1a, Linux track). Apple Virtualization.fr","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/src/index.js"},"./scripts/first-light":{"import":"./dist/scripts/first-light.js"},"./scripts/snapshot-create":{"import":"./dist/scripts/snapshot-create.js"}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"vitest run --passWithNoTests"},"dependencies":{"@brainst0rm/relay":"0.1.0"},"devDependencies":{"@types/node":"^22.0.0","tsup":"^8.3.0","typescript":"^5.6.0","vitest":"^2.1.0"},"_id":"@brainst0rm/sandbox@0.1.0","gitHead":"10e9a5392bcf59b26446ef84a942d5b89cecc491","bugs":{"url":"https://github.com/justinjilg/brainstorm/issues"},"homepage":"https://github.com/justinjilg/brainstorm#readme","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-GHDrMSG+x7C75Nxbjo+phWZ2Ea6hMms6AyQZIgUwTSYSB/1cme6Pj0ftAUF1eR4nempUlEs7u31OSieVqcrfOA==","shasum":"461a7fc0ce2bebdbc8b89943876212b057b0dd81","tarball":"https://registry.npmjs.org/@brainst0rm/sandbox/-/sandbox-0.1.0.tgz","fileCount":23,"unpackedSize":212409,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@brainst0rm%2fsandbox@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIC+7JpixXMoxXURYNvLWy/IHUq0Y/5j+sHY6p/P1AoeYAiEAk7iunjFWhRMFGy2C1MkWru+ZwSBwqFAlP95PVfSpSxU="}]},"_npmUser":{"name":"justinjilg","email":"justin.jilg@gmail.com"},"directories":{},"maintainers":[{"name":"justinjilg","email":"justin.jilg@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sandbox_0.1.0_1778932012502_0.532209938851075"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-16T11:46:52.390Z","0.1.0":"2026-05-16T11:46:52.642Z","modified":"2026-05-16T11:46:53.115Z"},"maintainers":[{"name":"justinjilg","email":"justin.jilg@gmail.com"}],"description":"MicroVM sandbox abstraction for the Brainstorm endpoint agent. Defines the Sandbox interface (boot/executeTool/reset/shutdown) consumed by the endpoint dispatcher (P3.3) and provides a Cloud Hypervisor backend (P3.1a, Linux track). Apple Virtualization.fr","homepage":"https://github.com/justinjilg/brainstorm#readme","repository":{"type":"git","url":"git+https://github.com/justinjilg/brainstorm.git","directory":"packages/sandbox"},"bugs":{"url":"https://github.com/justinjilg/brainstorm/issues"},"readme":"# @brainst0rm/sandbox\n\nMicroVM sandbox abstraction for the Brainstorm endpoint agent.\n\nThis is **P3.1a scaffolding**, not a runnable VM. It was authored on Darwin\nand **has not been booted against a real `cloud-hypervisor` binary**. The\ngoal of this package today is to nail down the cross-backend interface,\nfreeze the protocol-shape contracts (`ResetState`, `VerificationDetails`),\nand leave a Linux runner a small, well-documented set of pieces to fill in\nfor first light.\n\n## What's in here\n\n| File                          | Status      | Notes                                                                                                                                                                                         |\n| ----------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `src/sandbox.ts`              | implemented | Abstract `Sandbox` interface, `ToolInvocation`, `ToolExecution`, `ResetState` re-export, `makeVerificationDetails` helper                                                                     |\n| `src/errors.ts`               | implemented | `SandboxNotAvailableError`, `SandboxBootError`, `SandboxToolTimeoutError`, `SandboxToolError`, `SandboxResetError`, `SandboxResetDivergenceError` — codes match the protocol error vocabulary |\n| `src/chv/chv-config.ts`       | implemented | `ChvSandboxConfig`, `KernelConfig`, `RootfsConfig`, `VsockConfig`, defaults                                                                                                                   |\n| `src/chv/chv-process.ts`      | partial     | Builds CHV argv, spawns the binary, refuses cleanly on non-Linux. **Validated on node-2 first-light (PR #277).**                                                                              |\n| `src/chv/vsock-client.ts`     | implemented | CHV `CONNECT <port>` handshake + length-prefixed JSON RPC loop. Validated end-to-end on node-2 (echo round-trip, 600ms boot / 2ms exec).                                                      |\n| `src/chv/chv-sandbox.ts`      | partial     | Boot / exec / shutdown validated on node-2. **Reset machinery (P3.2a) is host-side code only — full validation requires a real install-time golden-snapshot flow.**                           |\n| `src/chv/chv-remote.ts`       | implemented | `ch-remote` argv wrapper (`snapshot fs://`, `resume`, `info`) with injectable `ExecFileFn` for tests. Argv shape pinned by unit tests; semantics await node-2 integration.                    |\n| `src/chv/chv-overlay-hash.ts` | implemented | Streaming SHA-256 hasher over the rootfs CoW overlay file; injectable `HashFileFn` for tests. **No real overlay file has been hashed in this checkout.**                                      |\n\n## P3.2a — Linux reset machinery (host-side code, host-side validation)\n\n`ChvSandbox.reset()` now drives the full reset cycle:\n\n1. **Snapshot revert** via `ch-remote --api-socket <path> snapshot\nfs://<snapshotPath>` followed by `ch-remote --api-socket <path>\nresume`. Both calls go through `ChRemote` (`src/chv/chv-remote.ts`)\n   which centralises argv shape and accepts an injectable `ExecFileFn`\n   for tests.\n2. **3-source verification** (per threat-model §5.1):\n   - **fs_hash** — SHA-256 streamed over `rootfs.path` (the CoW overlay).\n     Compared against `baselines.fs_hash`.\n   - **open_fd_count** — `VsockClient.guestQuery(\"OpenFdCount\")` over the\n     established vsock RPC channel. Compared against\n     `baselines.open_fd_count`.\n   - **vmm_api_state** — `ch-remote info` parsed for `state`, normalised\n     onto the protocol's canonical vocabulary\n     (`running` | `paused` | `stopped` | `error`). Compared against\n     `baselines.expected_vmm_api_state`.\n3. **Divergence handling.** If any single source disagrees with its\n   baseline, `reset()` throws `SandboxResetDivergenceError`, the sandbox\n   transitions to `state() === \"failed\"`, and the returned\n   `verification_details.divergence_action` is `\"halt\"`. This is\n   unconditional — we deliberately do NOT require a quorum, because the\n   substrate-lying threat model assumes an attacker can compromise up to\n   2 of 3 sources (threat-model §A6).\n4. **Baselines unset = scaffold mode.** If `config.baselines` is\n   undefined, each source emits an explicit \"not-configured\" marker\n   (`sha256:not-configured` for `fs_hash`, `0` for `open_fd_count`, the\n   live VMM state for `vmm_api_state`). The reset soft-passes; the\n   markers tell consumers (and the audit log) that real verification is\n   not yet wired. Production endpoints MUST configure baselines.\n\n### What still requires real-CHV validation on node-2\n\nThis is **host-side code**. The unit tests pin the `ch-remote` argv\nshape and the divergence semantics against an injected `ExecFileFn` /\n`HashFileFn` / fake vsock. They DO NOT exercise:\n\n- Actual `ch-remote snapshot fs://...` semantics. CHV's documented verb\n  for revert is sometimes documented as `restore`; this implementation\n  uses `snapshot` per the P3.2a wire-protocol spec. If real CHV expects\n  a different verb, the integration runner will surface a non-zero exit\n  and we patch the verb in `chv-remote.ts` (one-line edit, obvious test\n  diff).\n- Actual rootfs CoW overlay file location and stability. We hash\n  whatever `rootfs.path` points to; whether that file settles to a\n  deterministic state after revert is for the runner to confirm.\n- The install-time **golden-snapshot creation flow**. P3.2a's reset path\n  consumes a snapshot that someone else creates. The matching install\n  flow (separate work item) needs to:\n  1. Boot the sandbox to a known-clean state.\n  2. Pause the VMM (`ch-remote pause`).\n  3. Create the snapshot (`ch-remote snapshot\ndestination_url=file://<dir>`).\n  4. Compute the post-pause baselines: SHA-256 of the rootfs file,\n     `OpenFdCount` over vsock, `vmm_api_state` from `ch-remote info`.\n  5. Persist baselines to the endpoint config so reset can compare.\n\n### Honest gaps that block \"real production reset\"\n\n1. **Install-time golden-snapshot flow.** Not in this package; needs to\n   be wired before reset's `snapshotPath` mode is meaningful. Until\n   then, `snapshotPath` unset = no-op revert (verification still runs).\n2. **Rootfs-overlay path semantics.** `RootfsConfig.path` is treated as\n   the file to hash. For CHV's CoW mode, the path that's mutated is the\n   overlay file, which may differ from the read-only base disk. The\n   integration runner must point `rootfs.path` at the overlay file, not\n   the base.\n3. **`OpenFdCount` GuestQuery handler.** Implemented in `VsockClient`;\n   the in-guest dispatcher (P3.4 image-builder) must respond. First-light\n   confirmed echo dispatch but did not yet exercise GuestQuery.\n4. **Baseline-recording flow.** `ChvSandboxConfig.baselines` is a config\n   shape; how those values get computed and persisted at install time\n   is a separate work item.\n5. **Bootstrap kernel + rootfs**\n   This package consumes `KernelConfig.path` and `RootfsConfig.path` as\n   opaque strings. P3.4 produces both.\n\n## What's needed from `brainstormVM`\n\nP3.1a's hard sequencing gate is \"brainstormVM `vm.boot` proven E2E on bare\nmetal\" (plan §5, R17). Beyond that gate, this package needs the following\nfrom the brainstormVM workstream:\n\n- **Kernel image baseline.** Whether to bundle our own `vmlinux` or consume\n  a brainstormVM-blessed one. Either way, we need its path on the runner\n  and ideally its expected hash (so the install-time baseline machinery\n  has something to record). _Open._\n- **Disk format / layout convention.** brainstormVM uses per-VM disks\n  (per the v3.2 plan note, D35); we need to know whether those disks are\n  raw or qcow2 so `--disk path=...` flags use the right form. _Open._\n- **Snapshot directory layout.** Cloud Hypervisor's `restore` flag takes\n  a `source_url=file://<dir>` pointing at a directory containing a\n  `state.json` + `mem.bin` + per-disk snapshot files. brainstormVM may\n  already have an opinion here; if not, we set it in P3.2a. _Open._\n- **VMM API state vocabulary.** This package maps `ch-remote info`'s\n  `state` field to the protocol's `VmmApiState` (`running` / `stopped` /\n  `paused` / `error`). brainstormVM's existing `vm.info` likely uses\n  similar names — we should align. _Open._\n\n## What's needed from P3.4 (image-build pipeline)\n\n- A reproducible Linux microVM rootfs containing the MVP tool set\n  (`echo`, `whoami`, `uname`, `cat-file`, plus 2–3 MSP-relevant tools).\n- The in-guest dispatcher: a tiny program listening on the vsock port\n  that accepts JSON-line requests, forks the requested tool, returns\n  `{ exit_code, stdout, stderr, evidence_hash }`. The wire format\n  proposed in `vsock-client.ts` is the contract — needs P3.3 alignment\n  with crd4sdom's Go agent before it's frozen.\n- The install-time baseline-recording flow that produces\n  `ChvSandboxConfig.baselines` (`fs_hash`, `open_fd_count`,\n  `expected_vmm_api_state`).\n\n## Linux runner first-light checklist\n\nWhen this scaffolding lands on a real Linux box (Hetzner runner per\n0bz7aztr's pattern), the following sequence brings first light:\n\n1. **Verify substrate.** Confirm `cloud-hypervisor --version` and\n   `ch-remote --version` are present on `$PATH`. KVM available\n   (`ls /dev/kvm`).\n2. **Confirm `isChvSupportedHost()` returns true.** It should — sanity\n   check.\n3. **Stand up kernel + rootfs paths.** Either consume brainstormVM\n   artifacts or use a plain Debian cloud kernel + minimal rootfs to\n   prove boot, before P3.4 lands the real image.\n4. **Implement the vsock RPC.**\n   - Replace the throw at the bottom of `VsockClient.open()` with a real\n     `CONNECT <guestPort>\\n` write + `OK <port>\\n` read.\n   - Replace `VsockClient.sendCommand()` body with a real JSON-line\n     write + read loop, deadline-bounded by `setTimeout`.\n   - Build the in-guest dispatcher matching the wire format.\n5. **Boot the VM.**\n   - Construct a `ChvSandbox` with kernel/rootfs/vsock config.\n   - Call `boot()`. It should resolve without throwing.\n   - Confirm `state()` returns `\"ready\"`.\n6. **Run a no-op tool.**\n   - Call `executeTool({ tool: \"echo\", params: { message: \"hello\" }, command_id: \"...\", deadline_ms: 5000 })`.\n   - Verify `exit_code === 0`, `stdout` contains \"hello\".\n7. **Wire FS-hash + open-fd sources for `verifyPostReset`.**\n   - Replace the \"return baseline\" stubs with a real overlay hash and a\n     real in-guest fd-count query.\n8. **Snapshot + revert smoke.**\n   - Take a snapshot via `ch-remote snapshot destination_url=file://...`.\n   - Run a tool that mutates state.\n   - Call `reset()`. Confirm:\n     - `verification_passed: true`\n     - `verification_details.fs_hash_match: true`\n     - `verification_details.divergence_action: \"none\"`\n   - Re-run the no-op tool to confirm sandbox is still functional.\n9. **Negative reset test.**\n   - After reset, mutate the host-visible overlay file directly.\n   - Call `reset()` again — verification should now FAIL with\n     `SandboxResetDivergenceError`. This proves the integrity monitor\n     catches at least one of the substrate-lying patterns from threat\n     model §A6.\n10. **Hand off to P3.2a (Linux reset machinery).** Reset latency\n    measurement (1000 iterations, p50 < 500 ms target) and\n    failure-mode catalog.\n\n## Build / typecheck\n\n```bash\nnpx turbo run build --filter='@brainst0rm/sandbox'\nnpx turbo run typecheck --filter='@brainst0rm/sandbox'\n```\n\nThe build was confirmed green on Darwin during scaffolding. There are no\ntests in this package yet — meaningful tests require a Linux runner. The\ntype contract is the binding artifact today; tests follow first light.\n\n## Relationship to the rest of Phase 3\n\n- **P3.1b (macOS / Apple Virtualization.framework)** — separate package.\n  Implements the same `Sandbox` interface from `src/sandbox.ts` so the\n  dispatcher remains backend-agnostic. Currently TBD on naming\n  (`@brainst0rm/sandbox-vf`?). The `SandboxBackend` union here already\n  reserves `\"vf\"`.\n- **P3.3 (Go integration)** — crd4sdom's work mirrors this interface in\n  Go. The TypeScript `ChvSandbox` is the reference for behaviour, not\n  the production runtime — the Go agent will own the in-process path on\n  Linux endpoints. This package may also be wired into\n  `@brainst0rm/endpoint-stub` as an optional executor for end-to-end\n  TypeScript-only loops during dev.\n- **P3.4 (image build)** — produces the kernel + rootfs + in-guest\n  dispatcher this package consumes opaquely.\n- **P3.5a (Linux validation)** — runs the 1000-dispatch red-team\n  against a fully wired-up `ChvSandbox`.\n","readmeFilename":"README.md","_rev":"1-19701a8ce794a29966523720bbcd1aa1"}