# OpenSpec Change: enterprise-server-sandbox - **Change ID**: enterprise-server-sandbox - **Package**: `@suaveplan/sandbox` - **Category**: server/infra - **Target path**: `server/infra/sandbox` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/sandbox.md` --- ## Summary Deliver `@suaveplan/sandbox` on the genesis branch from scratch at enterprise quality. The package provides an isolated code execution sandbox for running untrusted or user-supplied JavaScript/TypeScript snippets. It supports two backends: a `WorkerSandbox` using Bun's `Worker` API (in-process isolation) and a `ProcessSandbox` using `Bun.spawn` for stronger OS-level isolation. Both expose `run(code, context, options): Promise` with configurable resource limits (CPU timeout, memory limit, I/O restrictions), structured output capture, and abort signal support. Genesis adds Zod-validated options, `@suaveplan/error` codes, OTel spans, and comprehensive security-oriented tests. --- ## Current-state audit (genesis) Does not exist on genesis — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | Typed `SANDBOX.*` error codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/logger` (`workspace:^`) | Structured logs | | `zod` (`catalog:forms`) | Options validation | | `@opentelemetry/api` (`catalog:observability`) | Spans + counters + histograms | | `tslib` (`catalog:build`) | Runtime helpers | --- ## Public API surface ```ts interface Sandbox { run(code: string, context?: SandboxContext, options?: RunOptions): Promise dispose(): Promise } function createWorkerSandbox(options?: SandboxOptions): Sandbox function createProcessSandbox(options?: SandboxOptions): Sandbox interface SandboxOptions { timeoutMs?: number // default: 5000 memoryLimitMb?: number // default: 128 allowNetwork?: boolean // default: false allowFs?: boolean // default: false logger?: LoggerLike } type SandboxContext = Record // serializable globals injected into sandbox interface RunOptions { timeoutMs?: number // override per-run signal?: AbortSignal } interface SandboxResult { ok: boolean value?: unknown // returned value (JSON-serializable) stdout: string stderr: string duration: number exitCode?: number error?: string } type SandboxErrorCode = | 'SANDBOX_TIMEOUT' | 'SANDBOX_MEMORY_EXCEEDED' | 'SANDBOX_EXECUTION_ERROR' | 'SANDBOX_INVALID_CODE' | 'SANDBOX_DISPOSED' function registerSandboxErrorCodes(): void ``` --- ## File layout ```text server/infra/sandbox/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/index.ts types/ sandbox.types.ts sandbox.types.md worker/ worker-sandbox/ worker-sandbox.ts worker-sandbox.md worker-sandbox.types.ts worker-sandbox.test.ts index.ts sandbox-worker-script.ts # Worker inner script process/ process-sandbox/ process-sandbox.ts process-sandbox.md process-sandbox.types.ts process-sandbox.test.ts index.ts tests/ security.test.ts integration.test.ts ``` --- ## Impact Downstream: user-defined rule engines, server-side template execution, AI tool calls. Server-only, Bun runtime required. **Prerequisites on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/logger`.