Files
2026-05-27 23:29:53 +01:00

93 lines
6.0 KiB
Markdown

# @suaveplan/api-sandbox-vm - vm.Context-based sandbox host for Suaveplan API plugins running in the sandboxed tier. Builds a frozen-globals vm.Context, loads the plugin via vm.SourceTextModule, rejects dynamic-code constructors and node built-in imports, and routes every fs/fetch/capability call through a host-installed permission-gated proxy surface. Server-tier.
`vm.Context`-based sandbox host for Suaveplan API plugins running in
the sandboxed tier. The package owns the `vm.Context`+frozen-globals
half of the design doc §2.2 sandboxed tier; the worker-thread bulkhead
is owned by `@suaveplan/api-worker-host` and the permission policy is
owned by `@suaveplan/api-sandbox-permissions`.
<!-- begin:auto-docs -->
## Documentation tree
- [error-codes](./src/error-codes/error-codes.md) — This module owns the stable `SAND_VM.*` error-code registry used by every public failure path inside the `@suaveplan/ap…
- [error-codes](./src/error-codes/error-codes.md) — This module owns the stable `SAND_VM.*` error-code registry used by every public failure path inside the `@suaveplan/ap…
- [frozen-globals](./src/globals/frozen-globals/frozen-globals.md) — This module assembles the curated global allowlist visible inside the `vm.Context` sandbox. Every binding installed her…
- [frozen-globals](./src/globals/frozen-globals/frozen-globals.md) — This module assembles the curated global allowlist visible inside the `vm.Context` sandbox. Every binding installed her…
- [otel](./src/otel/instruments.md) — This module owns the OpenTelemetry instrument bundle emitted by the `vm.Context` sandbox host. Instruments are bound la…
- [instruments](./src/otel/instruments.md) — This module owns the OpenTelemetry instrument bundle emitted by the `vm.Context` sandbox host. Instruments are bound la…
- [permissions](./src/permissions/checker.md) — `createPermissionChecker` compiles a `PermissionsManifest` (from `@suaveplan/api-types`) into a structural `PermissionC…
- [checker](./src/permissions/checker.md) — `createPermissionChecker` compiles a `PermissionsManifest` (from `@suaveplan/api-types`) into a structural `PermissionC…
- [fetch-proxy](./src/proxies/fetch-proxy/fetch-proxy.md) — `installFetchProxy` returns the outbound-HTTP surface visible inside the sandbox. Every request gates through the suppl…
- [fetch-proxy](./src/proxies/fetch-proxy/fetch-proxy.md) — `installFetchProxy` returns the outbound-HTTP surface visible inside the sandbox. Every request gates through the suppl…
- [fs-proxy](./src/proxies/fs-proxy/fs-proxy.md) — `installFsProxy` returns the sandbox-side filesystem surface that plugins consume. Every method gates the call through…
- [fs-proxy](./src/proxies/fs-proxy/fs-proxy.md) — `installFsProxy` returns the sandbox-side filesystem surface that plugins consume. Every method gates the call through…
- [install-capability-proxies](./src/proxies/install-capability-proxies/install-capability-proxies.md) — `installCapabilityProxies` wires the host-supplied capability bags into the sandbox's `vm.Context`. The sandbox sees on…
- [install-capability-proxies](./src/proxies/install-capability-proxies/install-capability-proxies.md) — `installCapabilityProxies` wires the host-supplied capability bags into the sandbox's `vm.Context`. The sandbox sees on…
- [sandbox](./src/sandbox/sandbox.md) — `createVmSandbox` is the keystone entry point of the package. It materialises a `vm.Context` whose `globalThis` is seal…
- [sandbox](./src/sandbox/sandbox.md) — `createVmSandbox` is the keystone entry point of the package. It materialises a `vm.Context` whose `globalThis` is seal…
- [testing](./src/testing/run-vm-conformance.md) — `runVmSandboxConformance(label, makeSandbox)` is the public conformance suite every `vm.Context`-based sandbox host mus…
- [run-vm-conformance](./src/testing/run-vm-conformance.md) — `runVmSandboxConformance(label, makeSandbox)` is the public conformance suite every `vm.Context`-based sandbox host mus…
<!-- end:auto-docs -->
## Modules
| Subpath | Purpose |
|---|---|
| `./sandbox/sandbox` | `createVmSandbox`, `VmSandboxHandle` — builds the frozen `vm.Context` and drives the plugin lifecycle. |
| `./globals/frozen-globals/frozen-globals` | Curated allowlist of globals visible inside the sandbox. |
| `./proxies/fs-proxy/fs-proxy` | Host-proxied filesystem with permission-gated `readFile`/`writeFile`. |
| `./proxies/fetch-proxy/fetch-proxy` | Host-proxied outbound HTTP with permission gating. |
| `./proxies/install-capability-proxies/install-capability-proxies` | Wires the consolidated `__suaveplan` receiver into the context. |
| `./permissions/checker` | In-package default `PermissionChecker` built from a `PermissionsManifest`. |
| `./error-codes/error-codes` | `SAND_VM.*` registry + `SandboxVmError`. |
| `./otel/instruments` | OTel histogram + three counters (boot duration, eval rejection, module-import rejection, permission denial). |
| `./testing` | `runVmSandboxConformance(label, makeSandbox)` — the conformance harness every vm sandbox host must pass. |
## Quick start
```ts
import {
createVmSandbox,
createPermissionChecker,
} from "@suaveplan/api-sandbox-vm";
const checker = createPermissionChecker({
policy: { fs: ["/srv/data/**"], fetch: ["api.example.com"] },
});
const handle = createVmSandbox({
pluginId: "demo",
logger,
checker,
pluginModule: { kind: "path", path: "/srv/plugins/demo.mjs" },
proxies: {
fs: realFsAdapter,
fetch: realFetchAdapter,
capabilities: {},
},
});
await handle.start();
// ... later
handle.dispose();
```
## Runtime requirement
Node ≥ 20 with `--experimental-vm-modules` enabled at process start.
`vm.SourceTextModule` is gated behind that flag; the sandbox raises
`SAND_VM.SOURCE_TEXT_MODULE_FAILED` with a clear hint when the flag is
missing.
## Conformance
Pass the package's testing harness against any custom `vm`-based
sandbox host:
```ts
import { runVmSandboxConformance } from "@suaveplan/api-sandbox-vm/testing";
runVmSandboxConformance("my-host", makeMyHandle);
```