first commit
This commit is contained in:
72
docs/api-stack/api/api-sandbox-wasm/src/outbound/outbound.md
Normal file
72
docs/api-stack/api/api-sandbox-wasm/src/outbound/outbound.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# outbound
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## 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
|
||||
|
||||
```ts
|
||||
import { buildWasiOutboundAllowlist } from "@suaveplan/api-sandbox-wasm";
|
||||
|
||||
const allowlist = buildWasiOutboundAllowlist(policy);
|
||||
if (!allowlist.isAllowed("api.stripe.com")) { /* deny */ }
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
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.
|
||||
Reference in New Issue
Block a user