5.9 KiB
5.9 KiB
@suaveplan/api-sandbox-wasm - WASM-based sandbox host for Suaveplan sandboxed-tier API plugins. Instantiates a WebAssembly module against a WASI snapshot preview1 implementation built from the plugin manifest's PermissionPolicy: read-only fs preopens by default (rw: prefix opt-in), outbound socket allowlist from permissions.fetch[], and capability host imports gated by PermissionChecker. Denials raise SAND_WASM_* errors and increment plugin.permission_denied_total. Ships ./testing conformance harness so every sandbox host satisfies the same WASI-specific invariants.
Stage-8 WebAssembly sandbox host. Instantiates a sandboxed-tier plugin
WASM module against a WASI snapshot preview1 implementation derived from
the plugin's PermissionPolicy:
permissions.fs[]maps to read-only WASI preopen directories. Write access requires therw:rule prefix.permissions.fetch[]maps to an outbound socket allowlist; thesock_connecthost import refuses non-matching destinations BEFORE opening an OS socket.- Capability imports (under
suaveplan_caps) are permission-gated per call; denials return a WASI errno to the guest AND incrementplugin.permission_denied_total{plugin, capability, reason}.
Documentation tree
- error-codes — Defines the stable
SAND_WASM.*error-code registry and theSandWasmErrorsubclass thrown by every production path i…- error-codes — Defines the stable
SAND_WASM.*error-code registry and theSandWasmErrorsubclass thrown by every production path i…
- error-codes — Defines the stable
- install-capability-imports — Wraps every host-supplied capability proxy in a permission check so the guest's call goes through `PermissionCheckerLik…
- install-capability-imports — Wraps every host-supplied capability proxy in a permission check so the guest's call goes through `PermissionCheckerLik…
- otel — Owns the WASM sandbox host's OpenTelemetry instrument registry. Every counter the host emits on a production path lives…
- otel — Owns the WASM sandbox host's OpenTelemetry instrument registry. Every counter the host emits on a production path lives…
- outbound — Builds the outbound-socket allowlist from
policy.fetch[]and wraps the host'sconnectadapter so denied destination…- outbound — Builds the outbound-socket allowlist from
policy.fetch[]and wraps the host'sconnectadapter so denied destination…
- outbound — Builds the outbound-socket allowlist from
- policy — Defines the
PermissionPolicyvalue object and theresolvePermissionPolicybuilder that lifts a `PermissionsManifest…- policy — Defines the
PermissionPolicyvalue object and theresolvePermissionPolicybuilder that lifts a `PermissionsManifest…
- policy — Defines the
- preopens — Maps
policy.fs[]rules onto a WASI preopen table. The WASI capability model is file-descriptor-based: a guest can onl…- preopens — Maps
policy.fs[]rules onto a WASI preopen table. The WASI capability model is file-descriptor-based: a guest can onl…
- preopens — Maps
- sandbox — Top-level entry point for the WASM sandbox host.
createWasmSandboxcompiles (or accepts a pre-compiled) WASM module,…- sandbox — Top-level entry point for the WASM sandbox host.
createWasmSandboxcompiles (or accepts a pre-compiled) WASM module,…
- sandbox — Top-level entry point for the WASM sandbox host.
- testing — Exports
runWasmSandboxConformance(label, makeSandbox)— the conformance harness every WASM-tier sandbox host (this pa…- run-wasm-conformance — Exports
runWasmSandboxConformance(label, makeSandbox)— the conformance harness every WASM-tier sandbox host (this pa…
- run-wasm-conformance — Exports
- wasi — Minimal
wasi_snapshot_preview1snapshot tied to the sandbox host's permission policy. Every host-visible side effect…- wasi — Minimal
wasi_snapshot_preview1snapshot tied to the sandbox host's permission policy. Every host-visible side effect…
- wasi — Minimal
Install
bun add @suaveplan/api-sandbox-wasm
Usage
import {
createWasmSandbox,
resolvePermissionPolicy,
} from "@suaveplan/api-sandbox-wasm";
const policy = resolvePermissionPolicy({
fs: ["./uploads/*", "rw:./tmp"],
fetch: ["api.stripe.com", "*.suaveplan.io"],
});
const handle = await createWasmSandbox({
pluginName: "stripe-checkout",
policy,
capabilities: [
{
capabilityId: "secrets",
importName: "secrets_get",
invoke: (...args) => secretsAdapter.get(args[0] as string),
},
],
checker,
wasmBytes: await readFile("./plugin.wasm"),
});
try {
const start = handle.instance.exports._start as () => void;
start();
} finally {
handle.dispose();
}
Modules
- error-codes —
SAND_WASM_*registry +SandWasmError. - policy —
PermissionPolicyvalue object +resolvePermissionPolicy. - preopens —
buildWasiPreopens+matchPreopen. - outbound —
buildWasiOutboundAllowlist+gateOutboundConnect. - wasi — minimal
wasi_snapshot_preview1snapshot with policy gating. - imports/install-capability-imports — permission-gated host imports.
- sandbox —
createWasmSandbox+WasmSandboxHandle. - otel —
createSandWasmInstruments(plugin.permission_denied_total). - testing —
runWasmSandboxConformanceharness.
Verification
bunx turbo lint typecheck test:coverage --filter=@suaveplan/api-sandbox-wasm
License
MIT