Initial Commit
This commit is contained in:
86
packages/devtools/tooling/sandbox/src/vm-engine/vm-engine.md
Normal file
86
packages/devtools/tooling/sandbox/src/vm-engine/vm-engine.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# VmEngine
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`VmEngine` is the default sandbox engine. It uses `node:vm` directly: caller code is compiled with `new vm.Script(...)` and executed via `script.runInContext(ctx, { timeout })`. The context is created with `codeGeneration: { strings: false, wasm: false }` so `eval` and the Function constructor are syntactically unavailable inside the sandbox even if the code-transformer's regex filter fails. Context variables and registered modules are injected as own properties of the context object; the host's intrinsics (`Object`, `Array`, etc.) are reachable through the shared realm.
|
||||
|
||||
`VmEngine` is NOT a security boundary against adversarial code. `node:vm`'s
|
||||
context-sharing model means a determined attacker with code-injection can
|
||||
escape via `this.constructor.constructor("...")` or prototype-chain tricks.
|
||||
For adversarial isolation use `worker-engine` (OS-thread isolation) or
|
||||
`spawn-engine` (process isolation).
|
||||
|
||||
## Features
|
||||
|
||||
- Real `node:vm` execution — synchronous, deterministic.
|
||||
- Frozen intrinsics flag (`codeGeneration: { strings: false, wasm: false }`).
|
||||
- Captured console (`log`/`warn`/`error`) with output-size cap.
|
||||
- Module + context-variable injection per execution.
|
||||
- V8 heap statistics via `v8.getHeapStatistics()`.
|
||||
- OTel `recordExecution` + `recordDuration` emission per call.
|
||||
- `executeSync` companion for pool callers that prefer synchronous APIs.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { VmEngine } from "@suaveplan/sandbox/vm-engine";
|
||||
|
||||
const engine = new VmEngine({
|
||||
timeout: 5000,
|
||||
maxOutputSize: 1024,
|
||||
memoryLimit: 50 * 1024 * 1024,
|
||||
});
|
||||
const r = await engine.execute("1 + 1");
|
||||
console.log(r.result); // 2
|
||||
engine.destroy();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Inject a host bridge as a module so user code can interact with the
|
||||
controlled-vocabulary API rather than the host's intrinsics:
|
||||
|
||||
```ts
|
||||
import { VmEngine } from "@suaveplan/sandbox/vm-engine";
|
||||
|
||||
const engine = new VmEngine({
|
||||
timeout: 5000,
|
||||
maxOutputSize: 1024,
|
||||
memoryLimit: 50 * 1024 * 1024,
|
||||
modules: [
|
||||
{
|
||||
name: "host",
|
||||
exports: {
|
||||
fetchProduct: (id: string) => loadProduct(id),
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const r = await engine.execute('host.fetchProduct("sku-42")');
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new VmEngine(config: SandboxEngineConfig)`.
|
||||
- `execute(code, context?, options?): Promise<SandboxResult>`.
|
||||
- `executeSync(code, context?, options?): SandboxResult`.
|
||||
- `registerModule(mod): void`.
|
||||
- `unregisterModule(name): boolean`.
|
||||
- `getHeapStatistics(): { usedHeapSize, heapSizeLimit } | null`.
|
||||
- `reset(): void`.
|
||||
- `destroy(): void`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The compiled script wraps the user code in `(${code})` so a bare expression
|
||||
(e.g. `1 + 1`) returns its value rather than throwing a syntax error from a
|
||||
missing semicolon. An IIFE (`function(){...}()`) compiles to
|
||||
`(function(){...}())` which is also valid. The wrapper is intentionally
|
||||
lightweight; callers who want statement-level execution should use
|
||||
`executeFunction` on the facade or wrap their code in a function themselves.
|
||||
The `breakOnSigint: true` flag is set so a SIGINT delivered to the host
|
||||
terminates the running script rather than killing the entire process.
|
||||
Reference in New Issue
Block a user