Files
skills/plugins/library-navigator/skills/sp-sandbox/SKILL.md
2026-05-29 08:20:56 +01:00

5.9 KiB

name, description
name description
sp-sandbox Server-tier sandboxed code execution with vm/worker/spawn/isolate engines, pre-warmed pools, and audit logging.

Sandbox for Suaveplan

Server-tier sandboxed code execution. Ships four SandboxEngine implementations (node:vm default, node:worker_threads, node:child_process, 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.

Architecture

Component Responsibility
createSandbox Public facade — composes engine, resolver, limiter, logger, and transformer into a Sandbox interface.
VmEngine Default engine using node:vm directly — fastest, but NOT a security boundary against adversarial code.
WorkerEngine Spawns a fresh node:worker_threads Worker per execution — true OS-thread isolation.
SpawnEngine Spawns a fresh node:child_process — strongest isolation, highest overhead.
IsolateEngine Structural adapter over isolated-vm (optional peer dep) — strongest in-process isolation.
SandboxPool Pre-warmed engine pool with lazy growth, execution-count recycling, and idle reclamation.
ResourceLimiter Sliding-window rate limit + output-size truncation.
ModuleResolver Allowlist/denylist gatekeeper for modules exposed to sandboxed code.
CodeTransformer Regex-based defence-in-depth layer blocking dangerous patterns (process.exit, require, eval).
AuditLogger SHA-256-hashed structured audit log of every execution.
ResultStreamer Incremental async output delivery instead of end-of-execution dumps.
SandboxError Typed error carrying SANDBOX_CODES.* via defineCodes.

File Structure

devtools/tooling/sandbox/
  src/sandbox/          # createSandbox facade
  src/vm-engine/        # VmEngine — default node:vm engine
  src/worker-engine/    # WorkerEngine — node:worker_threads
  src/spawn-engine/     # SpawnEngine + runner.ts child entry point
  src/isolate-engine/   # IsolateEngine — isolated-vm structural adapter
  src/pool/             # SandboxPool — pre-warmed engine recycling
  src/resource-limiter/ # rate limit + output truncation
  src/module-resolver/  # allowlist/denylist module gatekeeper
  src/code-transformer/ # pattern-based dangerous-code guard
  src/audit-logger/     # structured SHA-256 audit log
  src/result-streamer/  # incremental async output
  src/schemas/          # Zod schemas for every public boundary
  src/error-codes/      # SANDBOX_CODES registry + SandboxError
  src/telemetry/        # OTel instruments for the sandbox itself
  src/types/            # shared SandboxEngine, SandboxResult, etc.

Sibling packages:

  • @suaveplan/linter — unified markdown + biome linting pipeline
  • @suaveplan/profiler — runtime performance profiling toolkit
  • @suaveplan/readline — terminal I/O primitive
  • @suaveplan/test-vite — Vite + Vitest configuration factories

Patterns

Quick Start — execute code in a vm sandbox

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 guide

import { createSandbox } from "@suaveplan/sandbox";

// Trusted accident-isolation, fastest path
const vm = createSandbox({ engine: "vm" });

// Adversarial code, OS-thread isolation
const worker = createSandbox({ engine: "worker" });

// Adversarial code, full process isolation
const spawn = createSandbox({ engine: "spawn" });

// Strongest in-process isolation (requires isolated-vm peer dep + customEngine)
const isolate = createSandbox({ engine: "isolate", customEngine: myIsolateFactory });

Using the pool for high-throughput execution

import { SandboxPool, VmEngine } from "@suaveplan/sandbox";

const pool = new SandboxPool({
    engineConfig: { timeout: 5000, maxOutputSize: 1024 * 1024 },
    factory: (config) => new VmEngine(config),
    minSize: 2,
    maxSize: 10,
});

const result = await pool.execute("1 + 1");
pool.destroy();

Register custom modules

import { createSandbox } from "@suaveplan/sandbox";

const sandbox = createSandbox();
sandbox.registerModule({ name: "math", exports: { add: (a: number, b: number) => a + b } });
const result = await sandbox.execute("math.add(2, 3)");

Constraints

  • Node ≥ 20 — uses node:vm, node:worker_threads, node:child_process, and node:crypto.
  • vm engine is NOT a security boundary — vm.runInContext shares the host realm; prototype-chain escapes are possible. Use worker or spawn for adversarial code.
  • engine: "isolate" requires a customEngine factory — the package does not bundle isolated-vm; supply an IsolateFactory via customEngine.
  • Zod validates every public boundary — createSandbox, execute, registerModule, and pool config all run through strict schemas.
  • CodeTransformer is defence-in-depth only — it catches obvious accidents (process.exit, require, eval) but is not a substitute for an engine-level boundary.
  • Error codes go through defineCodes — SANDBOX_CODES is produced by defineCodes("SANDBOX", [...]); never hand-write the string literal.

Checklist

  1. Choose the engine by threat model: vm for trusted code, worker/spawn for untrusted.
  2. Use SandboxPool when you have many short executions to amortise startup cost.
  3. Register modules before executing code; modules are re-synced to the engine on every execute call.
  4. Call sandbox.destroy() (or pool.destroy()) when done to release OS resources.
  5. Import from subpath exports rather than deep src/ paths for tree-shakeability.