Files
suaveplan/packages/api-stack/api/api-sandbox-permissions/src/checker/checker.md
2026-05-27 23:29:53 +01:00

4.4 KiB

checker/checker — PermissionChecker

(no submodules)

Purpose

This module is the composite entry point that the two sandbox hosts (api-sandbox-vm, api-sandbox-wasm) wire into their worker capability proxy. It binds a PermissionPolicy to a PermissionInstruments handle and exposes the three production check methods plus three assert* helpers that throw SandboxPermissionError in the default "enforce" deny mode.

Construction is per plugin-worker pair — never global — because the policy and instruments both pin the plugin label and the worker boundary is the natural granularity for the check + telemetry pair.

Features

  • PermissionChecker.checkFs / checkFetch / checkCapability — invoke the underlying pure function AND record the deny counter on a deny outcome.
  • PermissionChecker.assertFs / assertFetch / assertCapability — same as above, but in "enforce" mode raise SandboxPermissionError on deny; in "warn" mode return the deny result silently after recording the counter.
  • DenyMode — "enforce" (default) or "warn".
  • Deny telemetry — every deny path records exactly one plugin.permission_denied_total increment with the documented { plugin, capability, reason } label set.

Usage: Basic

import { PermissionChecker } from "@suaveplan/api-sandbox-permissions/checker";
import { createPermissionInstruments } from "@suaveplan/api-sandbox-permissions/instruments";
import { PermissionPolicy } from "@suaveplan/api-sandbox-permissions/policy";

const checker = new PermissionChecker({
    policy: new PermissionPolicy({
        permissions: { fs: ["./uploads/*"], fetch: ["api.stripe.com"] },
    }),
    instruments: createPermissionInstruments({ plugin: "billing" }),
});

const fs = checker.checkFs("./uploads/avatar.png", "read");
console.assert(fs.outcome === "allow");

Usage: Advanced

import { PermissionChecker } from "@suaveplan/api-sandbox-permissions/checker";
import { createPermissionInstruments } from "@suaveplan/api-sandbox-permissions/instruments";
import { PermissionPolicy } from "@suaveplan/api-sandbox-permissions/policy";
import { SAND_PERM_CODES, SandboxPermissionError } from "@suaveplan/api-sandbox-permissions/error-codes";

// Canary mode — record denies on metrics, do not block the call.
const canary = new PermissionChecker({
    policy: new PermissionPolicy({
        permissions: { fs: ["./uploads/*"] },
    }),
    instruments: createPermissionInstruments({ plugin: "billing" }),
    mode: "warn",
});

const warnResult = canary.assertFs("./etc/passwd", "read");
console.assert(warnResult.outcome === "deny");
// `plugin.permission_denied_total{plugin: "billing", capability: "fs",
//  reason: "path-not-in-allowlist"}` incremented; no throw.

// Enforcing mode — throws on deny.
const strict = new PermissionChecker({
    policy: canary.policy,
    instruments: canary.instruments,
    // mode: "enforce" — default
});
try {
    strict.assertFs("./etc/passwd", "read");
} catch (err) {
    if (err instanceof SandboxPermissionError) {
        console.assert(err.code === SAND_PERM_CODES.DENIED);
    }
}

API Reference

  • class PermissionChecker
    • constructor({ policy, instruments, mode? })
    • readonly policy: PermissionPolicy
    • readonly instruments: PermissionInstruments
    • readonly mode: DenyMode
    • checkFs(path, mode): CheckResult
    • checkFetch(url): CheckResult
    • checkCapability(payload): CheckResult
    • assertFs(path, mode): CheckResult (throws in enforce mode)
    • assertFetch(url): CheckResult
    • assertCapability(payload): CheckResult
  • type DenyMode = "enforce" | "warn"
  • type CheckerCapabilitySource = "fs" | "fetch" | "db" | "secrets" | "events"

Implementation Notes

The class is deliberately stateless apart from its three readonly fields — deny telemetry is delegated to the PermissionInstruments handle, which is itself stateless behind the OTel counters. This means the checker is safe to instantiate once per plugin-worker pair and share across every in-flight capability call.

The assert* helpers wrap check* rather than the pure functions so the counter increments exactly once per deny: the underlying pure functions do not call recordDenial, only the checker methods do. A deny-mode-warn call therefore records the same counter the enforce mode would, which is what dashboards rely on to detect canary-phase regressions.