Skip to content

Update network policy docs with clarifications and examples - #811

Open
Branden Bonaby (bbonaby) wants to merge 9 commits into
mainfrom
user/bbonaby/update-network-policy-docs
Open

Update network policy docs with clarifications and examples#811
Branden Bonaby (bbonaby) wants to merge 9 commits into
mainfrom
user/bbonaby/update-network-policy-docs

Conversation

@bbonaby

@bbonaby Branden Bonaby (bbonaby) commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

📖 Description

Soon we'll update the 0.8.0 dev schema to use a directional network policy. The legacy allowLocalNetwork field combines private-network access behind one switch. Schema 0.8 separates that intent: egress controls outbound private-network access, while ingress.default controls inbound private-network access. On ProcessContainer, MXC derives the required AppContainer capabilities from both directions. Because Windows exposes privateNetworkClientServer as bidirectional, private-network directionality remains coupled at the capability layer until inbound WFP narrowing is implemented. The remaining changes document the planned schema, explain the 0.7-to-0.8 differences, and show how existing configurations map to the new shape.

🔗 References

🔍 Validation

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task

GitHub Actions runs the PR validation build automatically. The ADO pipeline
(MXC-PR-Build) is the Azure version of the PR pipeline, kept in parity with the GitHub
Actions build; it runs on merge to main, and Microsoft reviewers with write access can trigger it
on a PR with /azp run. See docs/pull-requests.md.

If the dependency-feed-check check fails on a new dependency, the crate must be added to
the feed before the PR can pass. See docs/pull-requests.md
for the steps.

Microsoft Reviewers: Open in CodeFlow

@bbonaby
Branden Bonaby (bbonaby) requested a review from a team as a code owner August 11, 2026 20:31
Copilot AI balanced review requested due to automatic review settings August 11, 2026 20:31
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Documents the proposed schema 0.8 network policy and migration from schema 0.7.

Changes:

  • Defines egress, ingress, and proxy semantics.
  • Adds schema migration guidance.
  • Updates ProcessContainer examples and enforcement details.
Show a summary per file
File Description
docs/sandbox-policy/v2/networking.md Expands schema 0.8 networking guidance.
docs/sandbox-policy/v2/networking-0.7.0-vs-0.8.0.md Adds migration mappings and examples.
docs/process-container/networking.md Updates ProcessContainer networking behavior.
docs/process-container/examples/0.8.0-schema.md Adds a proxy configuration example.
docs/examples.md Replaces legacy networking examples.

Review details

Tip

Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 5/5 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment thread docs/sandbox-policy/0.8.0/networking/networking.md
Comment thread docs/sandbox-policy/v2/networking-0.7.0-vs-0.8.0.md Outdated
Comment thread docs/sandbox-policy/v2/networking.md Outdated
Comment thread docs/process-container/examples/0.8.0-schema.md Outdated
Comment thread docs/examples.md Outdated
Comment thread docs/process-container/networking.md Outdated
Copilot AI review requested due to automatic review settings August 11, 2026 20:48
@bbonaby
Branden Bonaby (bbonaby) force-pushed the user/bbonaby/update-network-policy-docs branch from 44d6ef8 to 3b9a080 Compare August 11, 2026 20:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (4)

docs/sandbox-policy/0.8.0/networking/networking.md:76

  • This gives ingress.hostLoopback bidirectional semantics, including sandbox-to-host proxy access, while schema-updates.md:17 and D2 below define it as host-loopback inbound control. That ambiguity determines whether an egress-deny sandbox may initiate connections to host services. Please define one direction for this field and make the migration table, D2, and proxy guidance consistent with it.
    docs/sandbox-policy/0.8.0/networking/networking.md:339
  • The documented Seatbelt mechanism cannot enforce the promised host-loopback-only boundary. Seatbelt shares the host network stack, and the current (allow network-inbound (local ip)) rule permits listening on any local interface; a sandbox binding 0.0.0.0 can therefore be reachable from LAN/WAN, contrary to lines 65-67 and D2. The 0.8 contract should either reject this ingress posture on Seatbelt or specify a source/interface-scoped enforcement mechanism before claiming support.
    docs/sandbox-policy/0.8.0/networking/schema-updates.md:19
  • This mapping is too broad: a 0.7 proxy.url that points to loopback does have a 0.8 equivalent in runtimeConfig.networkProxy; only remote proxy URLs are removed. As written, users migrating an existing loopback URL are told there is no replacement.
| `proxy.url` | No GA equivalent | Schema 0.8 accepts only HTTP/S loopback proxy URLs |

docs/linux-wsl-roadmap-june-2026.md:164

  • These line citations no longer identify the ingress requirements: line 148 is the proxy URL, line 289 is the proxy enforcement row, and line 295 is only the implementation-doc link. Replace the fragile line-number list with links to the “Host Loopback and Inbound Policy” and D2 headings so this roadmap still points implementers to the stated contract.
| 14 | **(N2) Inbound control (`hostLoopback`)** | 🟡 Actionable | Already in place: `--unshare-net` inherently blocks inbound (no route). New work (proxy mode): GA requires ingress enforced via an iptables **INPUT** chain in the sandbox's **own network namespace** (`docs/sandbox-policy/0.8.0/networking/networking.md` L148/L212/L289/L295), scoped per-sandbox (D6). This **depends on N1** moving proxy mode off the shared host netns onto `--unshare-net` + a routed proxy (slirp4netns/veth, elevation required). Once Bwrap has a private netns, ingress runs there via the shared `NetworkIptablesManager` with a default **DROP** (same chain as LXC): `-i lo` ACCEPT (intra-container only), `ESTABLISHED,RELATED` ACCEPT. As on LXC, a bare `NEW -j ACCEPT` is **wrong** (it exposes the container IP over the veth); `hostLoopback: "allow"` requires a **host-loopback-bound DNAT/forward** with INPUT allowing `NEW` **only** for that path. A host-side INPUT chain on the shared netns is **not** the GA target: it can't be attributed to a single sandbox. **Dual-stack:** as on LXC, the `iptables` INPUT chain covers IPv4 only; a parallel `ip6tables`/`nftables` INPUT path is required for `::1`, otherwise IPv6 inbound escapes the default DROP. Shares the IPv6 tooling gap in Bwrap **item #19** and depends on it. | M |
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings August 11, 2026 20:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (5)

docs/sandbox-policy/0.8.0/networking/networking.md:67

  • “All backends” is not true for the backends covered later in this document: the Isolation Session section states that it cannot filter or deny network access and that a contained process can listen on a localhost-reachable port. Scope this default stance to backends that enforce the GA network policy so consumers do not assume default-deny on unsupported containment backends.
    sdk/node/README.md:436
  • This relative link works in the repository, but this README is also the npm package README and package.json publishes only README.md, dist/, bin/, and the license. The referenced ../../docs tree is therefore absent from the package, leaving npm consumers with a broken link. Keep this as an absolute GitHub URL, as the other documentation links above are.
- [Sandbox policy 0.7.0](../../docs/sandbox-policy/0.7.0/policy.md) — policy specification

docs/sandbox-policy/0.8.0/networking/schema-updates.md:19

  • This mapping is too broad: a 0.7 proxy.url that is already an HTTP/S loopback URL does have a GA equivalent in runtimeConfig.networkProxy; only remote/non-loopback URLs lose support. As written, the table contradicts the note in the same row and can lead users to discard a directly migratable configuration.
| `proxy.url` | No GA equivalent | Schema 0.8 accepts only HTTP/S loopback proxy URLs |

docs/process-container/networking.md:149

  • This 0.8 tier description conflicts with docs/process-container/os-version-support.md:54-60: schema 0.8 prefers the PSEC CreateProcessSecurityEnvironment contract, temporarily falls back to legacy SBOX CreateProcessInSandbox, and then continues to AppContainer when neither is usable. Describing SBOX as the sole preferred Tier 1 path makes this planned 0.8 guide direct implementers toward the legacy contract; align the table with the documented PSEC/SBOX/AppContainer fallback order.
| On builds that expose the OS sandbox-creation API (`CreateProcessInSandbox`), the OS itself, in its own elevated context, applies the per-sandbox WFP filters and wires the WinHTTP proxy before the target process runs.<br><br>No MXC-side privileged component, no UAC. The filter lifetime is owned by the OS and bound to AppContainer. This is the preferred path and where new capabilities land first. | On builds without that API (Windows 23H2), model 1 uses per-sandbox WFP filters that MXC writes by elevating on each launch.<br><br>Downlevel supports cooperative proxy routing through environment variables, but it does not satisfy the model 2 enforcement guarantee. It does not provide per-container WinHTTP or scoped proxy-peer enforcement. |

docs/linux-wsl-roadmap-june-2026.md:164

  • The retained line-number citations no longer support this inbound-policy claim after the networking document was expanded: current lines 148, 212, 289, and 295 point to the proxy example, IP-literal rationale, proxy enforcement, and an implementation link. Replace these brittle L... references with the relevant heading anchor (for example, D2 / the backend ingress section) so the roadmap points readers to the actual requirement.
| 14 | **(N2) Inbound control (`hostLoopback`)** | 🟡 Actionable | Already in place: `--unshare-net` inherently blocks inbound (no route). New work (proxy mode): GA requires ingress enforced via an iptables **INPUT** chain in the sandbox's **own network namespace** (`docs/sandbox-policy/0.8.0/networking/networking.md` L148/L212/L289/L295), scoped per-sandbox (D6). This **depends on N1** moving proxy mode off the shared host netns onto `--unshare-net` + a routed proxy (slirp4netns/veth, elevation required). Once Bwrap has a private netns, ingress runs there via the shared `NetworkIptablesManager` with a default **DROP** (same chain as LXC): `-i lo` ACCEPT (intra-container only), `ESTABLISHED,RELATED` ACCEPT. As on LXC, a bare `NEW -j ACCEPT` is **wrong** (it exposes the container IP over the veth); `hostLoopback: "allow"` requires a **host-loopback-bound DNAT/forward** with INPUT allowing `NEW` **only** for that path. A host-side INPUT chain on the shared netns is **not** the GA target: it can't be attributed to a single sandbox. **Dual-stack:** as on LXC, the `iptables` INPUT chain covers IPv4 only; a parallel `ip6tables`/`nftables` INPUT path is required for `::1`, otherwise IPv6 inbound escapes the default DROP. Shares the IPv6 tooling gap in Bwrap **item #19** and depends on it. | M |
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings August 11, 2026 21:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (2)

docs/process-container/networking.md:54

  • Omitting allowedProxyPeer is insufficient for a non-AppContainer host proxy: the omitted network policy defaults ingress.hostLoopback to deny (as documented below), so that proxy remains unreachable. Include the required host-loopback opt-in here so users do not produce a broken proxy configuration.
| Peer | Packaged app family or unpackaged AppContainer profile; omit for an unpackaged non-AppContainer proxy |

docs/process-container/networking.md:150

  • This still labels the downlevel cooperative environment-variable path as Model 2, although Model 2 above guarantees that all direct egress is blocked. Because clients can ignore proxy variables, this also contradicts the fail-loud rule immediately below that fallback must preserve requested semantics. Model 2 must be unavailable/rejected on this path unless a proxy-only enforcement primitive exists.
| Prefer PSEC (`CreateProcessSecurityEnvironment`) when its complete export set and runtime support probe succeed. Fall back temporarily to SBOX (`CreateProcessInSandbox`) when PSEC is unavailable, then to AppContainer when neither BaseContainer contract is usable. | Neither PSEC nor SBOX (`CreateProcessInSandbox`) is available, so MXC uses the AppContainer fallback.<br><br>Until downlevel WFP support is implemented, model 1 provides coarse egress and ingress allow/deny postures only. Model 2 provides cooperative proxy routing through environment variables without proxy-only enforcement. |
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings August 11, 2026 22:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings August 11, 2026 23:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (3)

docs/sandbox-policy/0.8.0/networking/schema-updates.md:61

  • This purported 0.7-to-0.8 translation silently narrows the legacy rule. allowedHosts permits every port/protocol for this CIDR, while the 0.8 example permits only TCP/443. Omit ports to preserve behavior, or explicitly state that the example intentionally adds a new restriction.
          "to": [ { "cidr": "140.82.112.0/20" } ],
          "ports": [ { "protocol": "tcp", "port": 443 } ]

docs/sandbox-policy/0.8.0/networking/schema-updates.md:95

  • The migration shown here is incomplete for the legacy proxy.localhost host-process case. With the omitted network block, schema 0.8 denies host loopback, while the ProcessContainer guidance requires either ingress.hostLoopback: "allow" for a host proxy or an identity-scoped allowedProxyPeer. Document that required choice so readers do not migrate to an unreachable proxy.
The omitted 0.8 `network` block uses deny defaults.

docs/process-container/networking.md:79

  • This condition also includes the unpackaged non-AppContainer mode below, where runtimeConfig.networkProxy is set but MXC explicitly does not add privateNetworkClientServer. Tie the capability to allowedProxyPeer so the two documented proxy modes do not contradict each other.
When `runtimeConfig.networkProxy` is set, MXC adds `privateNetworkClientServer`
for this path.
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings August 11, 2026 23:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (2)

docs/process-container/networking.md:130

  • This contradicts the identity-scoped proxy contract above: lines 78–80 say that setting both networkProxy and allowedProxyPeer adds privateNetworkClientServer, while this sentence says that capability is omitted whenever hostLoopback is allowed. A configuration containing all three fields therefore has two documented outcomes. Define the precedence and state it consistently.
The proxy endpoint is runtime metadata, not shared network policy. MXC resolves `allowedProxyPeer` when provided, adds
`privateNetworkClientServer` unless `ingress.hostLoopback` is `"allow"`, and configures the per-container WinHTTP proxy.

docs/process-container/networking.md:123

  • This proxy-bypass guarantee is not true for every ProcessContainer path described by this document. The downlevel table at line 185 explicitly says proxy requests fall back to cooperative environment-variable routing and are not model 2 enforcement; in identity-scoped mode the added bidirectional private-network capability can permit direct private egress. Scope this statement to BaseContainer paths with OS enforcement and call out that the downlevel AppContainer fallback is cooperative only.
As a cooperative fallback, MXC also sets the standard proxy environment variables for libraries that use them. The OS
permits outbound traffic only to the configured loopback proxy address and port; direct or proxy-bypassing traffic is
blocked.
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
@bbonaby
Branden Bonaby (bbonaby) force-pushed the user/bbonaby/update-network-policy-docs branch from 6b5b53b to b1bcfd7 Compare August 12, 2026 00:10
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Copilot AI review requested due to automatic review settings August 12, 2026 00:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (4)

docs/sandbox-policy/0.8.0/networking/networking.md:196

  • This absolute guarantee conflicts with the Seatbelt caveat at line 208, which says the default hostLoopback: deny prevents binding loopback listeners and therefore breaks intra-sandbox loopback servers. Explicitly qualify the guarantee for that backend.
    docs/process-container/networking.md:77
  • This unconditional claim conflicts with the AppContainer fallback documented below at lines 122–126: adding privateNetworkClientServer can permit direct private-network egress when WFP is unavailable. Qualify the enforcement guarantee so callers do not mistake the fallback for proxy-only containment.
| Enforcement | Per-container WinHTTP proxy plus scoped loopback; all direct egress remains blocked |

docs/process-container/networking.md:204

  • These rules contradict the compatibility behavior immediately above: line 190 says asymmetric private-network intent is accepted without independent enforcement, and lines 196–199 explicitly permit cooperative proxy and capability-coupling exceptions. State those exceptions here; otherwise this section simultaneously promises rejection and acceptance for the same request.
- Follow the PSEC, SBOX, and AppContainer fallback order only when the next path
  can preserve the requested semantics.
- Reject the launch with a typed error when no available path can enforce the
  request.

docs/process-container/examples/0.8.0-schema.md:15

  • This is presented as a schema 0.8 configuration, but it omits the required process.commandLine, so it will remain invalid even after the planned network fields are implemented. Include a process block or clearly label the JSON as a partial fragment.
  "version": "0.8.0-alpha",
  "containment": "processcontainer",
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Copilot AI review requested due to automatic review settings August 12, 2026 02:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (1)

docs/sandbox-policy/0.8.0/networking/schema-updates.md:28

  • This describes the 0.7 wire field as a bidirectional private-network switch, but the immutable 0.7 schema defines allowLocalNetwork as inbound bind/listen permission and says only Seatbelt honors it; ProcessContainer private-network access is separately represented by processContainer.capabilities (the SDK may populate both). Consequently, raw 0.7 configs cannot be migrated using this mapping as stated. Please distinguish the SDK SandboxPolicy translation from the 0.7 wire-schema field, or revise the mapping to the actual wire semantics.
`allowLocalNetwork` does not have a one-to-one schema 0.8 replacement. In
schema 0.7 it combines private-network access behind one switch. In schema 0.8,
`egress` expresses outbound private-network access and `ingress.default`
expresses inbound private-network access. Backends derive their required
network capabilities from both directions.
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Copilot AI review requested due to automatic review settings August 12, 2026 03:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (1)

docs/sandbox-policy/0.8.0/networking/networking.md:163

  • The latter two alternatives omit the required HTTP/S scheme, so copying them does not produce a valid networkProxy URL. Show a complete URL for every host form.
  • Files reviewed: 11/12 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants