Initial Commit
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# Vm sandbox conformance harness
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`runVmSandboxConformance(label, makeSandbox)` is the public conformance
|
||||
suite every `vm.Context`-based sandbox host must pass. The suite
|
||||
encodes the package's spec ADDED requirements as runnable assertions
|
||||
so any future host implementation (an alternative isolate library, a
|
||||
hardened wrapper, a worker-thread variant) plugs in against the same
|
||||
contract by exporting a single factory function.
|
||||
|
||||
This module is the reusable bridge between the OpenSpec capability
|
||||
spec and the implementation; checking that a sandbox passes the
|
||||
harness is sufficient to verify it satisfies the public requirements.
|
||||
|
||||
## Features
|
||||
|
||||
- Six assertions covering: `process` global absence, frozen
|
||||
`globalThis`, direct dynamic-code rejection, indirect dynamic-code
|
||||
rejection, node-built-in import refusal, dispose idempotency.
|
||||
- Adapter-driven: the harness calls `makeSandbox(source)` to obtain a
|
||||
fresh handle for every assertion so adapters with non-trivial setup
|
||||
cost can amortise it through closure capture.
|
||||
- Permissive eval-code expectation: the indirect-dynamic case accepts
|
||||
either `EVAL_REJECTED` or `INDIRECT_EVAL_REJECTED` so adapters that
|
||||
implement only the broad trap still pass.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { runVmSandboxConformance } from "@suaveplan/api-sandbox-vm/testing";
|
||||
import { createVmSandbox } from "@suaveplan/api-sandbox-vm/sandbox/sandbox";
|
||||
import { createPermissionChecker } from "@suaveplan/api-sandbox-vm/permissions/checker";
|
||||
|
||||
runVmSandboxConformance("self", async (source) =>
|
||||
createVmSandbox({
|
||||
pluginId: "self",
|
||||
logger: console as never,
|
||||
checker: createPermissionChecker({ policy: {} }),
|
||||
pluginModule: { kind: "source", identifier: "x", source },
|
||||
proxies: {
|
||||
fs: { readFile: async () => "", writeFile: async () => undefined },
|
||||
fetch: {
|
||||
request: async () => ({ status: 204, headers: {}, body: "" }),
|
||||
},
|
||||
capabilities: {},
|
||||
},
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Compose with a stricter checker and a pre-baked capability bag so the
|
||||
harness also exercises the host's `__suaveplan` receiver:
|
||||
|
||||
```ts
|
||||
import { runVmSandboxConformance } from "@suaveplan/api-sandbox-vm/testing";
|
||||
import { createVmSandbox } from "@suaveplan/api-sandbox-vm/sandbox/sandbox";
|
||||
|
||||
runVmSandboxConformance("strict", async (source) =>
|
||||
createVmSandbox({
|
||||
pluginId: "strict",
|
||||
logger,
|
||||
checker: strictChecker,
|
||||
pluginModule: { kind: "source", identifier: "strict.mjs", source },
|
||||
proxies: {
|
||||
fs: realFs,
|
||||
fetch: realFetch,
|
||||
capabilities: {
|
||||
db: { query: async (sql) => realQuery(String(sql)) },
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `runVmSandboxConformance(label, makeSandbox)` — register the suite
|
||||
under `runVmSandboxConformance — ${label}`.
|
||||
- `type MakeVmSandbox` — factory accepting plugin source text and
|
||||
returning a `VmSandboxHandle` (synchronously or via Promise).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The harness uses `@suaveplan/testing/runner` so it remains runner-
|
||||
agnostic — Bun-mode and Vitest-mode test runs see identical
|
||||
descriptions and assertion semantics. Sandbox source strings are
|
||||
constructed by concatenation rather than tagged templates so the
|
||||
emitted code never references a host-side binding. The
|
||||
`EVAL_TOK` token-split is a defence against static analysers that
|
||||
would otherwise flag the harness as containing direct `eval` usage —
|
||||
the harness exercises the trap, not the function. Disposal happens
|
||||
inside every assertion so the harness never leaks contexts; the
|
||||
adapter is responsible for tearing the handle down promptly.
|
||||
Reference in New Issue
Block a user