Files
skills/docs/api-stack/api/api-sandbox-wasm/src/testing/run-wasm-conformance.md
2026-05-29 08:20:56 +01:00

2.5 KiB

run-wasm-conformance

(no submodules)

Purpose

Exports runWasmSandboxConformance(label, makeSandbox) — the conformance harness every WASM-tier sandbox host (this package's own, or any future implementation) MUST pass. The harness pins the observable contract: preopens reflect policy.fs[], the outbound allowlist reflects policy.fetch[], the rw: prefix turns a preopen read-write, dispose() is idempotent, and the instrument registry exposes the canonical plugin.permission_denied_total counter.

The harness is exported from the ./testing subpath so adapters consume it as a normal import. The in-package fixture sandbox passes every scenario; the harness is self-tested via run-wasm-conformance.test.ts.

Features

  • Six pinned scenarios covering the spec delta's observable behaviour.
  • Uses the host's describe/it from @suaveplan/testing/runner so adapter test reports show nested suites under the host's tree.
  • WasmSandboxFactory signature lets adapters pass a minimal builder rather than re-implementing the full createWasmSandbox surface.

Usage: Basic

// In an adapter package's test file:
import { runWasmSandboxConformance } from "@suaveplan/api-sandbox-wasm/testing";
import { makeMyAdapterSandbox } from "./my-adapter.js";

runWasmSandboxConformance("my-adapter", makeMyAdapterSandbox);

Usage: Advanced

runWasmSandboxConformance("with-cache", async (input) => {
    const cached = sandboxCache.get(JSON.stringify(input));
    if (cached !== undefined) return cached;
    const handle = await createWasmSandbox({ /* ... */ });
    sandboxCache.set(JSON.stringify(input), handle);
    return handle;
});

API Reference

  • runWasmSandboxConformance(label: string, makeSandbox: WasmSandboxFactory): void
  • WasmSandboxFactory = (input) => Promise<WasmSandboxHandle> where input is { fsRules, fetchRules, denyCapability }.

Implementation Notes

The harness consumes the adapter's WasmSandboxHandle via its public surface only — preopens, outbound, instruments, and dispose(). Adapters that wrap or proxy the handle must preserve those properties identically.

The harness deliberately uses dispose() after every scenario rather than letting GC handle it, because a WASM-runtime under load can pin memory longer than the test budget allows. Adapters that hold open OS resources MUST close them in dispose() for the harness to pass on constrained CI runners.