[Bubblewrap/LXC] Address network policy gaps - schema#634
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends MXC’s network configuration surface with a GA schema for LXC/Bubblewrap, adding structured egress/ingress policy and an HTTP proxy field, then wiring that schema through the Rust wire model → parser → internal policy model and the SDK policy layer (including regenerated schema + TS wire types).
Changes:
- Added GA
network.egress(allow/deny rules),network.ingress.hostLoopback, andnetwork.proxy.httpto the Rust wire model and dev JSON schema. - Mapped GA network fields in
config_parserinto new internalEgressRule/Protocol/RuleActionmodel fields with validation (CIDR-only destinations). - Updated SDK policy mapping + tests and regenerated
sdk/src/generated/wire.ts.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/core/wxc_common/src/wire.rs | Adds GA network wire schema structs/enums (egress/ingress/proxy.http). |
| src/core/wxc_common/src/models.rs | Introduces internal egress rule model types and stores them on ContainerPolicy. |
| src/core/wxc_common/src/config_parser.rs | Parses/validates GA network fields and maps them into the internal model with legacy precedence rules. |
| src/core/mxc-sdk/tests/sdk_helpers.rs | Adjusts test helper construction for the expanded network policy struct. |
| src/core/mxc-sdk/src/policy.rs | Adds SDK GA network policy types and emits GA schema in wire config when present. |
| sdk/src/generated/wire.ts | Regenerated TS wire types to include the new GA network schema. |
| schemas/dev/mxc-config.schema.0.8.0-dev.json | Regenerated dev JSON schema with GA network types and fields. |
…nly (AB#62830582) - Add GA network schema (egress.allow/deny with cidr+ports+protocol, ingress.hostLoopback, proxy.http) to wire + parser + internal EgressRule model + SDK types. - Reject DNS names (CIDR-only); keep legacy allowedHosts/blockedHosts/defaultPolicy working. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3b78bec0-e139-4cfd-9c10-092ef986d4f4
6108846 to
f86ebb1
Compare
…col (AB#62830582) convert_wire_egress_rules pushed each GA port selector's port and protocol into two independent Vecs on one EgressRule. Since the internal EgressRule treats protocols x ports as a cartesian grid, a rule mixing selectors (e.g. tcp/80 + udp/53) widened to also permit tcp/53 and udp/80. Group selectors by protocol (first-seen order, deduped ports) and emit one EgressRule per protocol group so each rule's cartesian expansion equals exactly the requested selectors. Adds a regression test. Addresses copilot-pull-request-reviewer feedback on PR microsoft#634. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| /// Proxy URL (parsed into host:port). | ||
| pub url: Option<String>, | ||
| /// GA HTTP proxy URL (parsed into host:port). | ||
| pub http: Option<String>, |
There was a problem hiding this comment.
The GA spec puts the proxy in runtimeConfig.networkProxy (a URL, outside the network policy block), not network.proxy.http, right?
There was a problem hiding this comment.
Thanks — I'd like to defer the runtimeConfig.networkProxy relocation to a follow-up rather than fold it into this PR. Two reasons:
- Scope / risk. There is no
runtimeConfigsection anywhere in the wire model today, so this introduces a brand-new top-level config surface that is cross-cutting — schema, SDK public types, generated wire types, and every backend's proxy handling. That is meaningfully broader than this PR's "network policy schema" scope. - Spec fidelity. Doing it correctly needs the canonical GA
runtimeConfig.networkProxyspec (exact shape, precedence vs. the existingnetwork.proxy, and which backends honor it). I don't want to guess the shape and bake in something we then have to break.
This PR intentionally leaves the existing network.proxy.http surface unchanged. I'll open a tracking issue for the runtimeConfig.networkProxy migration and link it here. If you have a link to the GA spec you'd like followed, I'm happy to do the relocation in a dedicated follow-up PR.
There was a problem hiding this comment.
Tracking issue filed: #655 — I'll do the runtimeConfig.networkProxy relocation there in a dedicated follow-up (it needs the canonical GA spec for the exact shape and precedence vs. the existing network.proxy, plus it touches a new top-level runtimeConfig surface across schema, SDK types, generated wire types, and every backend). This PR intentionally leaves network.proxy.http unchanged. Leaving this thread open as the pointer to #655.
There was a problem hiding this comment.
I would block on this. Let's get the schema finalized at once and not check in temporary incorrect shapes.
Implements the actionable reviewer feedback on the GA egress/proxy schema: - ICMP has no ports: make EgressPort.port optional and reject a port paired with protocol 'icmp' (wire.rs, config_parser.rs). - Add egress.default (allow|deny): lets the 'allow-all-except-deny-list' model be expressed and prevents a legacy defaultPolicy:'allow' from being silently downgraded when GA egress is present. Maps to the internal default_network_policy; omitted/deny fail closed (wire.rs, config_parser.rs). - Optional rule ports: an omitted/empty ports list now means match-all (all ports and all protocols) to the listed destinations, so 'allow all ports to X' is expressible. A portless tcp/udp selector matches all ports for that protocol (config_parser.rs). - Make the external-proxy + egress rejection backend-agnostic instead of Bubblewrap-only, since MXC never forwards egress rules to a proxy (config_parser.rs). Regenerates the dev JSON schema and SDK wire types from the wire model, updates the hand-written SDK public types (types.ts) and the mxc-sdk policy port, and adds/updates unit tests. The proxy-placement thread (runtimeConfig.networkProxy) is deferred and answered on the PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s.json) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e5d2aa5b-7f04-4e4d-83d3-a02efe7020ab
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e5d2aa5b-7f04-4e4d-83d3-a02efe7020ab
🧪 Local test re-verification — 2026-07-17Re-ran the test suites locally at branch tip Windows host (
Linux (WSL2 Ubuntu-24.04,
Note: the
|
|
@SohamDas2021 — every item from your review has been addressed and pushed; requesting a re-review. Resolved (in
Deferred (tracked in #655):
Validation @ |
…et-schema-migration
Linked work item: AB#62830582 — [Bubblewrap/LXC] Address network policy gaps - schema
Summary
Adds the GA network policy schema and migration for LXC/Bubblewrap.
network:egress.{allow,deny}[](eachto: [{ cidr }],ports: [{ protocol, port }]),ingress.hostLoopback, andproxy.http.ingress.hostLoopback→allow_local_network,proxy.http→network_proxy,egress.*→ internalEgressRules.std::net; DNS hostnames are rejected with a clear parse error.allowedHosts/blockedHosts/defaultPolicycontinue to work. Precedence: GAnetwork.egresssupersedes the legacy list fields;ingress.hostLoopbackoverridesallowLocalNetwork.Model
EgressRule,Protocol,RuleActiontowxc_common::models.Validation
cargo fmt --all -- --check;cargo clippy -p wxc_common -D warnings— cleancargo test -p wxc_common— 403 passed;cargo test -p mxc-sdk— 23 passedcargo check --target x86_64-unknown-linux-gnu -p wxc_common— passCoupling
The internal
EgressRule/Protocol/RuleActiontypes are also added independently by the enforcement PRs (AB#62830559, AB#62830341). This PR owns the JSON parser; the enforcement PRs consume the model field. Merge-time reconciliation is expected.Microsoft Reviewers: Open in CodeFlow