# preopens _(no submodules)_ ## Purpose Maps `policy.fs[]` rules onto a WASI preopen table. The WASI capability model is file-descriptor-based: a guest can only open paths reachable from a preopened directory, and the host controls whether each preopen is read-only or read-write. This module owns that translation. Paths outside the policy allowlist are NOT preopened, so the guest's `path_open` cannot reach them — denial is enforced by the absence of the preopen, not by a runtime check. Write access requires the `rw:` rule prefix; the default is read-only. ## Features - `rw:` prefix promotes a preopen to read-write; absence keeps it read-only. - Globs `/*` and `/**` are stripped because WASI preopens are directory-granular — file-level scoping is enforced by the WASI runtime's resolved-path check. - Deduplication: duplicate rules collapse, with `rw` winning over `ro`. - `matchPreopen` returns the preopen for `path_open` gating, or `undefined` for a miss / write-against-ro. ## Usage: Basic ```ts import { buildWasiPreopens, resolvePermissionPolicy, } from "@suaveplan/api-sandbox-wasm"; const policy = resolvePermissionPolicy({ fs: ["./uploads/*", "rw:./tmp"] }); const preopens = buildWasiPreopens(policy); ``` ## Usage: Advanced ```ts import { matchPreopen } from "@suaveplan/api-sandbox-wasm/preopens"; const matched = matchPreopen(preopens, "/abs/host/path/to/file", "rw"); if (matched === undefined) { metrics.permissionDenied("fs", "preopen_miss_or_ro"); throw new SandWasmError(SAND_WASM_CODES.PREOPEN_DENIED, "denied"); } ``` ## API Reference - `buildWasiPreopens(policy): readonly WasiPreopen[]` - `matchPreopen(preopens, hostPath, "ro" | "rw"): WasiPreopen | undefined` - `WasiPreopen.{guestPath, hostPath, mode}` ## Implementation Notes `hostPath` is computed via `node:path.resolve`, anchoring relative rules against `process.cwd()` AT POLICY-BUILD TIME — operators must build the policy in the directory the plugin expects to see. The resolved path is used as the dedup key; rules that produce the same absolute path collapse, with `rw` winning over `ro` because privilege escalation is more visible than silent downgrade. WASI's preview1 file-rights bitmask is rich (read, write, allocate, truncate, etc.) — the implementation here intentionally uses a two-state mode so policy authoring stays readable. Sites that need finer granularity should layer their own bitmask check on top.