Files
suaveplan/packages/devtools/tooling/sandbox/README.md
2026-05-27 23:29:53 +01:00

109 lines
8.6 KiB
Markdown

# @suaveplan/sandbox - Server-tier sandboxed code execution: node:vm, node:worker_threads, and node:child_process engines, pre-warmed pool, audit logger, sliding-window rate limiter, pattern-based code transformer, async result streamer.
Server-tier sandboxed code execution for `@suaveplan` plugin hosts and agent runtimes. Ships four `SandboxEngine` implementations (a `node:vm` default, real `node:worker_threads` for OS-thread isolation, real `node:child_process` for process isolation, and a structural `isolated-vm` adapter), a pre-warmed `SandboxPool`, an async `ResultStreamer`, a pattern-based `CodeTransformer`, an allowlist-based `ModuleResolver`, a sliding-window `ResourceLimiter`, and a SHA-256 `AuditLogger` — all behind a `createSandbox()` facade with Zod-validated config and full OpenTelemetry instrumentation.
<!-- begin:auto-docs -->
## Documentation tree
- [audit-logger](./src/audit-logger/audit-logger.md) — `AuditLogger` records every sandbox execution with a structured `AuditLogEntry`. Each entry carries an ISO-8601 timesta…
- [audit-logger](./src/audit-logger/audit-logger.md) — `AuditLogger` records every sandbox execution with a structured `AuditLogEntry`. Each entry carries an ISO-8601 timesta…
- [code-transformer](./src/code-transformer/code-transformer.md) — `CodeTransformer` is a defence-in-depth layer that pattern-matches dangerous code constructs before they reach the engi…
- [code-transformer](./src/code-transformer/code-transformer.md) — `CodeTransformer` is a defence-in-depth layer that pattern-matches dangerous code constructs before they reach the engi…
- [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/sandbox` raises typed `SandboxError` instances rather than plain `Error` so consumers can discriminate fail…
- [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/sandbox` raises typed `SandboxError` instances rather than plain `Error` so consumers can discriminate fail…
- [isolate-engine](./src/isolate-engine/isolate-engine.md) — `IsolateEngine` implements the `SandboxEngine` contract over a structural `IsolateFactory` interface that mirrors the `…
- [isolate-engine](./src/isolate-engine/isolate-engine.md) — `IsolateEngine` implements the `SandboxEngine` contract over a structural `IsolateFactory` interface that mirrors the `…
- [module-resolver](./src/module-resolver/module-resolver.md) — `ModuleResolver` is the gatekeeper between user code and the host's module surface. It maintains an allowlist of module…
- [module-resolver](./src/module-resolver/module-resolver.md) — `ModuleResolver` is the gatekeeper between user code and the host's module surface. It maintains an allowlist of module…
- [pool](./src/pool/pool.md) — `SandboxPool` amortises engine startup cost across many short executions by maintaining a warm pool of `SandboxEngine`…
- [pool](./src/pool/pool.md) — `SandboxPool` amortises engine startup cost across many short executions by maintaining a warm pool of `SandboxEngine`…
- [resource-limiter](./src/resource-limiter/resource-limiter.md) — `ResourceLimiter` enforces two complementary controls on the sandbox boundary: a sliding-window rate limit (so a single…
- [resource-limiter](./src/resource-limiter/resource-limiter.md) — `ResourceLimiter` enforces two complementary controls on the sandbox boundary: a sliding-window rate limit (so a single…
- [result-streamer](./src/result-streamer/result-streamer.md) — `ResultStreamer` delivers sandbox output incrementally rather than as a single end-of-execution dump. The most common u…
- [result-streamer](./src/result-streamer/result-streamer.md) — `ResultStreamer` delivers sandbox output incrementally rather than as a single end-of-execution dump. The most common u…
- [sandbox](./src/sandbox/sandbox.md) — `createSandbox` is the public entry point of the package. It composes the engine, `ModuleResolver`, `ResourceLimiter`,…
- [sandbox](./src/sandbox/sandbox.md) — `createSandbox` is the public entry point of the package. It composes the engine, `ModuleResolver`, `ResourceLimiter`,…
- [schemas](./src/schemas/schemas.md) — Zod schemas guard every public boundary of `@suaveplan/sandbox`. The package never trusts its caller; instead, every ar…
- [schemas](./src/schemas/schemas.md) — Zod schemas guard every public boundary of `@suaveplan/sandbox`. The package never trusts its caller; instead, every ar…
- [spawn-engine](./src/spawn-engine/spawn-engine.md) — `SpawnEngine` uses `node:child_process.spawn` for the strongest isolation the package offers: a fresh OS process spawne…
- [runner](./src/spawn-engine/runner.md) — `runner.ts` is the child-process entry point invoked by `SpawnEngine`. The parent process spawns it via `node:child_pro…
- [spawn-engine](./src/spawn-engine/spawn-engine.md) — `SpawnEngine` uses `node:child_process.spawn` for the strongest isolation the package offers: a fresh OS process spawne…
- [telemetry](./src/telemetry/telemetry.md) — `@suaveplan/sandbox` ships first-class OpenTelemetry instrumentation so consumers running the sandbox at any scale can…
- [telemetry](./src/telemetry/telemetry.md) — `@suaveplan/sandbox` ships first-class OpenTelemetry instrumentation so consumers running the sandbox at any scale can…
- [vm-engine](./src/vm-engine/vm-engine.md) — `VmEngine` is the default sandbox engine. It uses `node:vm` directly: caller code is compiled with `new vm.Script(...)`…
- [vm-engine](./src/vm-engine/vm-engine.md) — `VmEngine` is the default sandbox engine. It uses `node:vm` directly: caller code is compiled with `new vm.Script(...)`…
- [worker-engine](./src/worker-engine/worker-engine.md) — `WorkerEngine` uses real `node:worker_threads` for true OS-thread isolation. Each `execute` call spawns a fresh `Worker…
- [worker-engine](./src/worker-engine/worker-engine.md) — `WorkerEngine` uses real `node:worker_threads` for true OS-thread isolation. Each `execute` call spawns a fresh `Worker…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/sandbox
```
## Quick start
```ts
import { createSandbox } from "@suaveplan/sandbox";
const sandbox = createSandbox({ timeout: 5000, engine: "vm" });
const result = await sandbox.execute("2 + 3");
console.log(result.result); // 5
sandbox.destroy();
```
## Engine selection
| Engine | Boundary | Use when |
|---|---|---|
| `vm` (default) | `node:vm` context | Trusted accident-isolation, fastest path. |
| `worker` | `node:worker_threads` | Adversarial code, OS-thread isolation. |
| `spawn` | `node:child_process` | Adversarial code, full process isolation. |
| `isolate` | `isolated-vm` (optional dep) | Strongest in-process isolation. |
Wire `engine: "isolate"` with a `customEngine` factory that constructs a real
`IsolateEngine` over your installed `isolated-vm` peer dependency.
## Modules
Co-located docs for every public surface:
- [error-codes](./src/error-codes/error-codes.md) — `SANDBOX_CODES`,
`SandboxError`.
- [schemas](./src/schemas/schemas.md) — Zod boundaries.
- [telemetry](./src/telemetry/telemetry.md) — OTel instruments + recorders.
- [audit-logger](./src/audit-logger/audit-logger.md) — execution audit log.
- [resource-limiter](./src/resource-limiter/resource-limiter.md) —
rate-limit + output truncation.
- [module-resolver](./src/module-resolver/module-resolver.md) —
denylist/allowlist + builtins.
- [code-transformer](./src/code-transformer/code-transformer.md) —
regex-based dangerous-pattern guard.
- [vm-engine](./src/vm-engine/vm-engine.md) — default engine.
- [worker-engine](./src/worker-engine/worker-engine.md) — OS-thread engine.
- [spawn-engine](./src/spawn-engine/spawn-engine.md) — process engine.
- [runner](./src/spawn-engine/runner.md) — spawn-engine child entry point.
- [isolate-engine](./src/isolate-engine/isolate-engine.md) — `isolated-vm`
structural adapter.
- [pool](./src/pool/pool.md) — pre-warmed engine pool.
- [result-streamer](./src/result-streamer/result-streamer.md) — async
streaming output.
- [sandbox](./src/sandbox/sandbox.md) — `createSandbox` facade.
## Security model
`vm-engine` shares the host realm and is NOT a security boundary against
adversarial code — `vm.runInContext` can be escaped via prototype-chain
tricks. For adversarial isolation, use `worker-engine` or `spawn-engine`,
both of which sit behind real OS-level boundaries. The `code-transformer`
is a defence-in-depth layer that catches the obvious accidents
(`process.exit`, `require`, `eval`, etc.); it is not a substitute for an
engine-level boundary.
## Tier
Server (`node:vm` / `node:worker_threads` / `node:child_process` / `node:crypto`).
Targets Node ≥ 20 (and Bun, which provides the same APIs).