Files
suaveplan/openspec/changes/enterprise-server-sandbox/tasks.md
2026-05-27 23:29:53 +01:00

4.7 KiB

Tasks: enterprise-server-sandbox

Change ID: enterprise-server-sandbox Package: @suaveplan/sandbox Target path: server/infra/sandbox Prerequisites on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/logger


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree per proposal.md.
  • package.json at 0.1.0, "sideEffects": false, exports "." + worker + process subpaths.
  • Deps: @suaveplan/error workspace:^, @suaveplan/types workspace:^, @suaveplan/logger workspace:^, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build.
  • DevDeps: vitest catalog:testing, @vitest/coverage-istanbul catalog:testing, @suaveplan/testing workspace:^.
  • tsconfig.json extending library-node.json; vitest.config.ts with pool: 'forks', setupFiles: ['@suaveplan/testing/polyfills'].
  • Scripts: lint, typecheck, test, test:coverage, build, docs:check.

2. Types and errors

  • Define all interfaces and Zod schemas (SandboxOptionsSchema, RunOptionsSchema) in src/types/sandbox.types.ts.
  • Write sandbox.types.md (≥200 words, both examples, API reference).
  • src/error-codes.ts: five codes; registerSandboxErrorCodes(); eager call.

3. Worker sandbox

  • Write src/worker/sandbox-worker-script.ts: minimal worker entry that receives { code, context } via self.onmessage, evaluates code in a Function('context', code)(context) with captured stdout/stderr, posts result back, handles errors.
  • Implement WorkerSandbox in src/worker/worker-sandbox/worker-sandbox.ts:
    • Creates a new Worker(sandboxWorkerScript) per run() call (for isolation reset).
    • Posts { code, context } to worker; sets a timeout via AbortController; on timeout terminate worker and throw SANDBOX_TIMEOUT.
    • Captures postMessage response as SandboxResult.
    • dispose(): no-op (workers are per-run).
    • OTel: span sandbox.run, counter sandbox.runs_total, histogram sandbox.duration_ms.
  • Write worker-sandbox.test.ts (≤500 lines): simple return value; console.log captured; context injection; timeout; syntax error (ok: false, error set); abort signal; { timeout: 15000 }.
  • Write worker-sandbox.md (≥200 words).

4. Process sandbox

  • Implement ProcessSandbox in src/process/process-sandbox/process-sandbox.ts:
    • run(code, context, options): write a temp JS file; spawn bun run <tempFile> with stdin: JSON.stringify(context); capture stdout/stderr; enforce timeout by killing process; return SandboxResult.
    • Propagate exit code; on non-zero, set ok: false.
    • dispose(): clean up temp files.
    • OTel: same instrumentation as worker sandbox.
  • Write process-sandbox.test.ts (≤500 lines): same scenarios as worker sandbox, plus process exit code handling.
  • Write process-sandbox.md (≥200 words).

5. Security tests

  • Write tests/security.test.ts (≤500 lines, { timeout: 15000 }):
    • Code attempting process.exit() is caught and sandbox returns error.
    • Code attempting require('fs').readFileSync('/etc/passwd') is blocked (process sandbox with allowFs: false).
    • Infinite loop hits timeout correctly.
    • Code throwing large strings does not OOM the test runner.
    • Context values are not accessible outside the sandbox (no prototype pollution).

6. Integration tests

  • tests/integration.test.ts: worker + process sandbox run same set of test snippets; verify identical results; { timeout: 30000 }.

7. Docs + verify + publish

  • Root README.md: security model explanation, worker vs process trade-offs, quick-start examples, API table.
  • bunx turbo lint --filter=@suaveplan/sandbox — zero errors.
  • bunx turbo typecheck --filter=@suaveplan/sandbox — zero errors.
  • bunx turbo test --filter=@suaveplan/sandbox — all pass.
  • bunx turbo test:coverage --filter=@suaveplan/sandbox — 100%.
  • bun scripts/publish.ts --package @suaveplan/sandbox.
  • Update CLAUDE.md; archive to openspec/archive/2026-04-24-enterprise-server-sandbox/.