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

2.5 KiB

outbound

(no submodules)

Purpose

Builds the outbound-socket allowlist from policy.fetch[] and wraps the host's connect adapter so denied destinations are refused BEFORE any OS socket is opened. Denial raises SAND_WASM_OUTBOUND_DENIED and fires the injected onDeny hook so the sandbox host can increment plugin.permission_denied_total{capability="fetch"} without coupling this module to the OTel API.

The matcher supports exact hosts, *.suffix wildcards (RFC 6125 semantics — the apex suaveplan.io does NOT match *.suaveplan.io), and optional port suffixes. Bare-host rules match any port; port-pinned rules match only the named port.

Features

  • Exact-host and *.suffix rule patterns.
  • Port-pinned rules (api.stripe.com:443).
  • Default destination port 443 when none is supplied.
  • O(rules) matching — no regex compilation, suitable for the typical small allowlists.
  • gateOutboundConnect wraps a host connect adapter; denied calls never invoke the inner adapter.

Usage: Basic

import { buildWasiOutboundAllowlist } from "@suaveplan/api-sandbox-wasm";

const allowlist = buildWasiOutboundAllowlist(policy);
if (!allowlist.isAllowed("api.stripe.com")) { /* deny */ }

Usage: Advanced

import { gateOutboundConnect } from "@suaveplan/api-sandbox-wasm/outbound";

const gated = gateOutboundConnect(
    allowlist,
    async (destination) => net.connect(destination),
    (destination) => instruments.recordPermissionDenied("fetch", destination)
);
const socket = await gated("api.stripe.com"); // throws SAND_WASM_OUTBOUND_DENIED for non-listed hosts.

API Reference

  • buildWasiOutboundAllowlist(policy): OutboundAllowlist
  • gateOutboundConnect<TSocket>(allowlist, connect, onDeny)
  • OutboundAllowlist.{isAllowed(destination), rules}

Implementation Notes

Wildcards live inside a single *.suffix form rather than full glob matching because RFC 6125 wildcard semantics are well-defined and predictable. Adding nested wildcards (e.g. **.example.com) would require careful escape handling that this module does not attempt; if operators need deeper granularity they should enumerate sub-domains explicitly.

Out-of-range port suffixes (>65535) on RULES are treated as host-only — the parser falls back to the bare-host path rather than throwing, because a parse failure here would be operator-visible during host boot and add no security value. Out-of-range ports on DESTINATIONS are treated as the default 443 for the same reason.