Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,6 @@ Privacy information can be found at https://privacy.microsoft.com and in the Mic
| [tests/scripts/README.md](tests/scripts/README.md) | Local and CI backend test suites |
| [docs/host-prep.md](docs/host-prep.md) | Windows host preparation (`wxc-host-prep.exe`) |
| [docs/diagnostics.md](docs/diagnostics.md) | Diagnostic logging and ETW |
| [docs/sandbox-policy/0.7.0/policy.md](docs/sandbox-policy/0.7.0/policy.md) | Sandbox policy 0.7.0 specification |
| [docs/process-container/guide.md](docs/process-container/guide.md) | Windows AppContainer / BaseContainer guide |
| [docs/lxc-support/lxc-backend.md](docs/lxc-support/lxc-backend.md) | LXC backend (Linux) |
| [docs/bwrap-support/bubblewrap-backend.md](docs/bwrap-support/bubblewrap-backend.md) | Bubblewrap backend (Linux) |
Expand Down
7 changes: 3 additions & 4 deletions docs/authoring-a-new-feature.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

Read these in order:

1. [Sandbox Policy spec](sandbox-policy/0.7.0/policy.md): what
Policy and ContainerConfig are, design principles.
1. [Configuration schema](schema.md): supported policy fields and their
default behavior.
2. [Versioning Design](versioning.md): how policy/schema/SDK
versions relate and when to bump.

Expand Down Expand Up @@ -101,8 +101,7 @@ If your feature touches SandboxPolicy, update
If your feature adds policy or config fields, you will need
to plumb them through `createConfigFromPolicy()` in
`sdk/node/src/sandbox.ts`. See the
[worked example in the Sandbox Policy spec](sandbox-policy/0.7.0/policy.md#10-worked-example-ui-policy)
for a walkthrough.
[UI policy section](schema.md#ui-policy) for the supported request shape.

---

Expand Down
10 changes: 5 additions & 5 deletions docs/bwrap-support/bubblewrap-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ requiring root privileges or a container runtime.
> old config does not migrate its policy. Legacy `defaultPolicy`,
> `enforcementMode`, host lists, `allowLocalNetwork`, and `network.proxy`
> are not accepted. See [schema migration](../schema.md).
> Directly constructed runtime requests with non-default retired fields are
> also rejected before sandbox provisioning. Bubblewrap also rejects
> directional requests it cannot enforce, such as `ingress.default: "allow"`
> or direct egress rules combined with a runtime proxy. An omitted `network`
> section takes the directional deny defaults.

## Prerequisites

Expand Down Expand Up @@ -220,11 +225,6 @@ block's value, while bash (RHEL) fabricates a shorter `/usr/local/bin:/usr/bin`
plus `TERM=dumb`. So neither reads back as empty from inside the workload,
whatever MXC passed.

> **Historical (retired pre-v0.9 contracts):** the child received only
> `process.env`, with no default `PATH`. Those contracts are no longer
> registered: a request declaring one fails as an unsupported version before
> `inheritDefaultEnv` or any other process field is evaluated.

### Filesystem Policy

| Field | bwrap Mapping | Description |
Expand Down
4 changes: 2 additions & 2 deletions docs/ci-validation-infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ get fixed or wired.

| Backend | Status | Notes |
|---------|--------|-------|
| Process T1 | βœ… Good | Windows 24H2+ only. Runs the primitives suite, tier-gated to `base-container`. Includes the schema 0.8 directional networking phases (capability matrix, model-3 equivalence, explicit egress rules, host loopback, runtime proxy, reject surface) and the legacy 0.7 network lane. Remaining failures are genuine MXC bugs or harness limitations. |
| Process T3 | βœ… Good | Windows 23H2 only. Runs the primitives suite tier-gated to `appcontainer-dacl`, plus `T3-Workloads.ps1` (real programs β€” pwsh, git, node, python, cmd β€” on top of the T3 primitives). The 0.8 networking phases assert the documented *rejection* behavior here, since AppContainer cannot carry egress rules, proxy peer identity, or host-loopback configuration. |
| Process T1 | βœ… Good | Windows 24H2+ only. Runs the primitives suite, tier-gated to `base-container`. Includes supported directional networking phases (capability matrix, model-3 equivalence, explicit egress rules, host loopback, runtime proxy, reject surface). Remaining failures are genuine MXC bugs or harness limitations. |
| Process T3 | βœ… Good | Windows 23H2 only. Runs the primitives suite tier-gated to `appcontainer-dacl`, plus `T3-Workloads.ps1` (real programs β€” pwsh, git, node, python, cmd) on top of the T3 primitives. The directional networking phases assert the documented *rejection* behavior here, since AppContainer cannot carry egress rules, proxy peer identity, or host-loopback configuration. |
| Bubblewrap | βœ… Good | |
| LXC | βœ… Good | Some networking tests fail on distros other than Ubuntu 24.04; seems to be an issue with MXC. The in-process streaming handle is covered at PR time by `lxc-e2e.yml` instead, because this matrix runs prebuilt binaries. |
| WSLC | βœ… Good | Might have to retry hung jobs - this is an issue with overzealous agent reclaiming. |
Expand Down
16 changes: 6 additions & 10 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,9 @@ separate ingress defaults:

See
[`tests/examples/30_network_0_8_directional.json`](../tests/examples/30_network_0_8_directional.json)
for the complete config and
[`sandbox-policy/0.8.0/networking/networking.md`](sandbox-policy/0.8.0/networking/networking.md)
for the historical GA design; use the
[supported schema guide](schema.md) for current backend authoring.
for the complete config and the
[supported schema guide](schema.md#directional-networking-supported-contracts)
for current backend authoring.

### Network Proxy

Expand Down Expand Up @@ -146,10 +145,8 @@ their supported ingress policies differ. See their backend guides.

Every supported contract (`0.9.0-alpha` or later) accepts the directional
shape and rejects the retired `defaultPolicy`, host-list, and `network.proxy`
fields. This is the cross-backend schema (see
[`docs/sandbox-policy/0.8.0/networking/networking.md`](sandbox-policy/0.8.0/networking/networking.md)
for the full design and per-backend enforcement matrix), not a
backend-specific format: it's parsed the same way regardless of
fields. This is the [cross-backend schema](schema.md#directional-networking-supported-contracts),
not a backend-specific format: it's parsed the same way regardless of
`containment`. Each backend independently declares which parts of it β€” if
any β€” it actually enforces; a backend that hasn't declared support for a
given field rejects a config that sets it.
Expand All @@ -158,8 +155,7 @@ Note that `EGRESS_RULES` is what carries per-CIDR/port rules; a backend
without it accepts only `egress.default`. On Seatbelt,
`runtimeConfig.networkProxy` covers only loopback endpoints; there is no
supported equivalent for a remote proxy URL or `builtinTestServer`. See
[`docs/sandbox-policy/0.8.0/networking/schema-updates.md`](sandbox-policy/0.8.0/networking/schema-updates.md)
for the full field mapping and [`tests/examples/31_mac_network_0_8.json`](../tests/examples/31_mac_network_0_8.json)
[`tests/examples/31_mac_network_0_8.json`](../tests/examples/31_mac_network_0_8.json)
for a complete example:

```json
Expand Down
2 changes: 1 addition & 1 deletion docs/linux-wsl-roadmap-june-2026.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ These items depend on the WSLC SDK team and are not unilaterally schedulable.

> **Why network enforcement must be container-scoped (host vs. VM vs. container).** Network policy can be enforced at three layers: the Windows **host** (Windows Firewall), the WSL2 **VM**, or the **container** network namespace inside the VM. GA decision **D6 (per-sandbox scoping)** requires every sandbox's policy to be independent β€” concurrent WSLC containers must not affect each other's access β€” and names the container network namespace as WSLC's scoping identity. A machine-wide **host** firewall can't attribute traffic to one container vs. another, so it violates D6 (and per **D8**, host firewalls apply *on top of* enforcement, never *as* it). A **VM-wide** rule fails the same way when one utility VM hosts multiple containers β€” sandbox A's rules would bleed into sandbox B. Only the **container namespace** is inherently per-sandbox, which is why it's the required enforcement point. The catch: MXC can't install rules into that namespace today (`Privileged` doesn't grant `CAP_NET_ADMIN`, and the VM may lack iptables tooling). Hence SDK dep #1 β€” a VM-level API that applies rules **scoped to a specific container's namespace**: physically enforced at the VM boundary, logically attributed to one container.
>
> **Contrast with Hyperlight/Nanvix, and the state-aware wrinkle.** Hyperlight (host-proxied sockets, per-instance) and Nanvix (per-guest egress filter) get D6 scoping for free because each sandbox *is* its own VM instance/process β€” no shared surface to bleed across. WSLC today is also effectively 1 sandbox : 1 VM (the one-shot flow creates a session, one container, then tears it down), but the highest-value WSLC optimization β€” **state-aware session reuse** (Misc #29), keeping a warm VM to amortize startup cost β€” makes one VM host **multiple** containers, at which point a host- or VM-wide rule genuinely bleeds across co-resident sandboxes. That is exactly when namespace-scoped enforcement (SDK dep #1) stops being merely cleaner and becomes mandatory.
> **Contrast with Hyperlight/Nanvix, and the state-aware wrinkle.** Hyperlight (network disabled for supported requests, per-instance) and Nanvix (all-deny or unrestricted networking, per-guest) keep their network posture scoped to each VM instance/process β€” no shared surface to bleed across. WSLC today is also effectively 1 sandbox : 1 VM (the one-shot flow creates a session, one container, then tears it down), but the highest-value WSLC optimization β€” **state-aware session reuse** (Misc #29), keeping a warm VM to amortize startup cost β€” makes one VM host **multiple** containers, at which point a host- or VM-wide rule genuinely bleeds across co-resident sandboxes. That is exactly when namespace-scoped enforcement (SDK dep #1) stops being merely cleaner and becomes mandatory.

---

Expand Down
28 changes: 18 additions & 10 deletions docs/lxc-support/lxc-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

The LXC backend provides Linux container isolation using [LXC (Linux Containers)](https://linuxcontainers.org/lxc/).

For exact `0.9.0-alpha`, networking is directional-only: use `network.egress`
and `network.ingress`. LXC rejects `runtimeConfig.networkProxy`, so a v0.9 LXC
request has no proxy surface at all β€” see [Proxy](#proxy) below.
For every registered contract from `0.9.0-alpha` onward, networking is
directional-only: use `network.egress` and `network.ingress`. LXC rejects
`runtimeConfig.networkProxy`, so a supported LXC request has no proxy surface
at all β€” see [Proxy](#proxy) below.
Legacy host lists and enforcement-mode fields in older examples are not
accepted. Do not relabel an old request as v0.9 without migrating its policy.
See [the schema migration reference](../schema.md).
Expand Down Expand Up @@ -143,9 +144,6 @@ in `process.env` replaces it.
> configuration, not just project input. Pass `"HOME=…"` to point elsewhere
> when the workspace is untrusted.

Below 0.9 only `process.env` is passed through and `inheritDefaultEnv` is
rejected.

Shells like bash also have a fallback `PATH`, so a truly empty environment is
not reachable through `process.env`.

Expand Down Expand Up @@ -173,9 +171,15 @@ The legacy `network.proxy` fields also have no supported exact contract.
Choose a backend that supports a loopback proxy if the workload needs one;
relabeling a retired LXC proxy request as v0.9 cannot make its policy enforceable.

The retired host-list, enforcement-mode, local-network, and `network.proxy`
fields are no longer representable in typed Rust requests. LXC still rejects
the supported `runtimeConfig.networkProxy` field before creating a container.
Omitting `network.egress` or `network.ingress` means default deny for that
direction; retired fields never supply a fallback.

### No network at all

A request that permits nothing and names no proxy keeps its own loopback and reaches nothing else.
A request that permits nothing keeps its own loopback and reaches nothing else.

## Usage

Expand Down Expand Up @@ -247,7 +251,11 @@ LXC reads a run's network section only when the container starts. Omit
`containerId` for a generated name. The claim is released when the handle drops.

**Teardown is owed on every terminal path,** including a drop without `wait`:
the proxy pin and the network chains come down, and the container is released.
the network chains come down, and the container is released. A reused container
also has any stale proxy hosts-file pin from an earlier run cleared before its
new workload launches. MXC checks for marked lines inside the running
container using `lxc-attach` and removes them if present. A failed check
refuses to run the workload.
A teardown failure is reported through `Sandbox::warnings`, which a bare drop
leaves no handle to read.

Expand Down Expand Up @@ -336,8 +344,8 @@ The zone query should answer the zone you assigned.
and anything it starts run unfiltered in both directions for that interval. The
requested command is attached afterwards. A connection opened during that window
keeps working once the rules land, because the chains accept established flows.
- **A filtered container cannot renew a DHCP lease.** The chains permit loopback,
established flows, and DNS, with no carve-out for DHCP. A container that
- **A filtered container cannot renew a DHCP lease.** The chains permit loopback
and established flows, with no implicit carve-out for DHCP or DNS. A container that
outlives its lease loses its address; one that finishes within the lease period
is unaffected.
- **A container that needs a network waits for an IPv4 address.** A dual-stack
Expand Down
71 changes: 8 additions & 63 deletions docs/nanvix-microvm/nanvix.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,70 +181,15 @@ including egress allow with omitted ingress defaults.
Disabled networking prevents guest socket creation (`OSError: [Errno 134]`).
Unrestricted networking includes host-backed bind/listen capabilities;
NanVix cannot independently enforce ingress or host-loopback restrictions.
Directional egress rules are explicitly rejected because the legacy IPv4
filter does not implement their full semantics, including default-deny DNS.
Directional egress rules are explicitly rejected rather than translated to
the guest's IPv4 host filter, which cannot implement their full semantics,
including default-deny DNS.
Runtime proxy configuration is also unsupported.

### Legacy per-host filter implementation (compatibility/reference only)

The following describes the retained legacy runtime filter, not accepted v1.1
JSON vocabulary. The exact cutover does not silently translate directional
rules into this weaker contract.

Legacy `defaultPolicy` and host-list interactions follow the
[backend-agnostic network policy semantics](../schema.md#legacy-network-host-list-semantics).
Invalid legacy combinations are rejected by shared policy validation:
`blockedHosts` requires an `allowedHosts` exception set under a block default,
and `allowedHosts` cannot be used under an allow default.

NanVix forwards the validated host list to the guest's host-side socket proxy,
which enforces egress at `connect()`. The guest filter is **allow-XOR-block**,
so NanVix rejects requests that supply both lists instead of dropping either
one.

Entries may be IPv4 literals (`93.184.216.34`), IPv4 CIDR blocks
(`10.0.0.0/8`), or hostnames. Hostnames are resolved to their IPv4 (A-record)
addresses at preflight; IPv6 (AAAA) results are dropped because the guest filter
is IPv4-only. Resolution failures are handled per direction so neither list ever
fails open:

- **allowlist** (deny-by-default): each dropped entry is logged as a warning and
the run continues, since dropping an entry only *narrows* access. If the list
resolves to **no** IPv4 address at all, the run is rejected at preflight rather
than silently allowing all traffic.
- **blocklist** (allow-by-default): **any** entry that resolves to no IPv4
address rejects the run at preflight. Silently dropping a blocked host would
let traffic the policy explicitly blocks flow freely, and the static preflight
filter cannot enforce a name that does not resolve β€” so the blocklist
fails closed.

**DNS:** in allowlist mode the guest daemon automatically exempts the DNS port
(53), so name resolution works without adding the resolver to `allowedHosts`.

Network proxies (`network.proxy`) are not supported and are rejected at
preflight.

```jsonc
{
"containment": "microvm",
"process": { "commandLine": "import urllib.request; ..." },
// Historical legacy shape, not accepted by the exact v1.1 contract:
"network": { "defaultPolicy": "allow" }
}
```

```jsonc
{
"containment": "microvm",
"process": { "commandLine": "import urllib.request; ..." },
// Historical legacy shape, not accepted by the exact v1.1 contract:
"network": { "allowedHosts": ["example.com", "10.0.0.0/8"] }
}
```

## Not Supported

| Workload | Error |
| ------------------------------- | ----------------------------------- |
| Both `allowedHosts` + `blockedHosts` | Rejected at preflight (mutually exclusive) |
| File writing outside `/mnt/rw/` | `OSError: Read-only file system` |
| Workload | Error |
| -------------------------------------------- | -------------------------------- |
| Mixed directional networking or egress rules | Rejected before VM creation |
| Runtime proxy | Rejected before VM creation |
| File writing outside `/mnt/rw/` | `OSError: Read-only file system` |
8 changes: 4 additions & 4 deletions docs/process-container/examples/0.8.0-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

> **Audience:** MXC consumers and developers

> Historical design reference: schema 0.8 is retired. For supported requests,
> Schema 0.8 is retired. For supported requests,
> use [current ProcessContainer networking guidance](../networking.md).

See the shared [0.7-to-0.8 network schema comparison](../../sandbox-policy/0.8.0/networking/schema-updates.md)
for egress, ingress, and proxy endpoint changes. This page covers the
ProcessContainer-specific proxy peer.
For the supported egress, ingress, and proxy endpoint fields, see
[directional networking](../../schema.md#directional-networking-supported-contracts).
The example below covers the ProcessContainer-specific proxy peer.

## Contained proxy

Expand Down
10 changes: 5 additions & 5 deletions docs/process-container/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
This guide covers adding new OS-level features that flow through MXC's Windows
process container pipeline.

Exact v0.9 networking uses directional egress/ingress,
`runtimeConfig.networkProxy`, and ProcessContainer proxy-peer identity. Legacy
networking fields remain available under their published contracts. Backend
Supported networking uses directional egress/ingress,
`runtimeConfig.networkProxy`, and ProcessContainer proxy-peer identity. Retired
networking fields are rejected by every registered contract. Backend
selection depends on host capability and requested policy, not schema version.

For which policy aspects this backend can enforce on each Windows 11 release,
see [Windows OS-version policy support](./os-version-support.md).

## Prerequisites

1. Read the [Sandbox Policy spec](../sandbox-policy/0.7.0/policy.md) to
understand how `SandboxPolicy` maps to `ContainerConfig`.
1. Read the [supported configuration schema](../schema.md) for policy and
request fields.
2. Read [authoring-a-new-feature.md](../authoring-a-new-feature.md), especially
Step 1 (feature spec) and Step 2 (OS changes).
3. Submit a feature spec so reviewers understand the end-to-end flow.
Expand Down
Loading