Commit 86ceab7
fix(isolation-session): refuse network policy the backend cannot enforce; require the unrestricted-network acknowledgment (#682)
* Refuse dishonest network policy on the IsolationSession backend
The IsolationSession container runs on an unrestricted network (outbound
open; a process inside can listen on a localhost-reachable port) that MXC
cannot filter or deny. Previously the backend accepted the default `Block`
network policy, silently affirming a deny it cannot enforce.
Now provision (and one-shot, which runs the full lifecycle) accept ONLY the
canonical unrestricted-network acknowledgment: network.defaultPolicy=allow +
allowLocalNetwork=true, no allowed/blocked hosts, no proxy, default
enforcement. Everything else (including an absent policy, which defaults to
the unenforceable `Block`) is refused.
Post-provision phases reject any supplied network policy (fixed at provision)
via a new domain `ExecutionRequest.network_specified` flag set from wire
`network` presence in config_parser; an absent policy is inherited. This
closes the domain-model blind spot where an explicit default-valued `Block`
is indistinguishable from absent.
Reworded the network/proxy error messages and added a post-provision
"immutable" message. Updated the happy-path iso test configs to the canonical
form; post-provision and negative-path configs are intentionally unchanged.
Gates: cargo fmt --check; clippy --all-features; cargo test iso ON and OFF
(wxc_common + isolation_session_common green, 84 iso + 456 wxc_common); parser
network_specified tests; wxc_host_prep 16 passed (elevated). Pre-existing env
failures (microvm e2e staging) are identical iso ON/OFF and unrelated.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* SDK: require the unrestricted-network acknowledgment at iso provision
Mirror the Rust-side IsolationSession network fix in the TypeScript SDK.
`IsolationSessionProvisionConfig.network` is now a required field typed as
the exact literal `{ defaultPolicy: 'allow'; allowLocalNetwork: true }`, so
the caller must explicitly acknowledge that the isolation session container
runs on an unrestricted network the backend cannot filter or deny. Any other
value (or a wrong-typed one) is a compile error; the post-provision configs
intentionally expose no `network` field, so the type system enforces the
provision-only rule for SDK callers.
Tests: type-level @ts-expect-error assertions (required network; block and
allowLocalNetwork=false rejected; network rejected on post-provision configs);
provisionSandbox lifts the canonical network to the envelope top level;
updated the conformance oracle's LiftedPhaseKey and the integration test's
provision calls. npm run build + npm test green (207 tests).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* docs: IsolationSession network policy is honesty-gated, not rejected
Update the in-repo docs to match the new behavior: the backend still rejects
all filesystem policy (no host-folder-sharing primitive), but the network
policy is now honesty-gated. Provision (and one-shot) require the canonical
unrestricted-network acknowledgment (network.defaultPolicy=allow +
allowLocalNetwork=true, no host rules, no proxy, default enforcement) and
refuse anything else, including an absent policy; post-provision phases reject
any supplied network policy and inherit an absent one.
Touches: copilot-instructions iso backend row; docs/isolation-session/oneshot
(policy-validation coverage row) + state-aware-rust (prose + policy matrix) +
state-aware-typescript (provision config table gains the required `network`
field); sdk/node/README state-aware example now passes the acknowledgment.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* test: expand IsolationSession network coverage + fix E2E probe
Add end-to-end and integration tests for the new network-acknowledgment
behavior, and fix a latent bug the required-network change introduced in the
SDK E2E probe.
Fix (critical): `probeStateAwareRuntime` (the module-load skip probe in the
SDK integration suite) provisioned iso with no config. With `network` now
required at provision, that returns `policy_validation`, which the probe
rethrows — so on an iso-capable host the whole integration suite would error
at load instead of running. The probe now passes the canonical network
acknowledgment for iso.
New integration tests (sdk/node integration, real wxc-exec): the backend
refuses a provision that (a) omits the network acknowledgment, (b) sends a
non-canonical network (defaultPolicy=block), or (c) omits allowLocalNetwork —
each via an untyped call, proving the runtime guard holds even when a JS
caller bypasses the compile-time type.
New E2E tests (PowerShell VM suites): one-shot refuses block / allow-without-
allowLocalNetwork / allowedHosts; state-aware refuses a non-canonical network
at provision and refuses any network policy on the start and exec
post-provision phases (even the canonical acknowledgment, since it is
immutable post-provision).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* fix: add canonical network ack to iso TTY resize smoke config
The IsolationSession TTY resize smoke (run_isolation_session_resize_smoke.ps1) builds its wxc-exec config inline and was the one manual (-Manual-only) test not covered by the automated suite, so it was missed when the network-acknowledgment requirement landed. Without a network block the backend now rejects it with policy_validation. Add the canonical {defaultPolicy:allow, allowLocalNetwork:true} form (matching isolation_session_powershell_interactive.json) so the manual smoke provisions again.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* docs: align state-aware design + GA networking docs with iso network policy
The cross-backend state-aware design docs and the v2 GA networking scope doc still described IsolationSession as honoring filesystem (not network) at provision, and showed provision examples using network.allowedHosts -- all now rejected by the backend. Align them with shipped behavior and the SDK type: provision honors only the canonical unrestricted-network acknowledgment ({ defaultPolicy: 'allow', allowLocalNetwork: true }); filesystem policy is rejected and ui is ignored.
- networking.md: reword the IsolationSession network-scope line (requires the canonical ack; rejects everything else).
- mxc-state-aware-sandbox-api.md / -overview.md: fix the 10.3 honor matrix (iso filesystem applied->rejected, ui applied->ignored), the SDK-exposure prose, the IsolationSessionProvisionConfig type (required network literal; drop filesystem and ui), and the provision examples (drop filesystem, allowedHosts->allowLocalNetwork).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* docs: address PR review -- stale validator comment, fragile test counts, policy.ui gap
state_aware.rs: the block comment above the validate_<phase> hooks still said network policy was rejected at every phase. That stopped being true when provision started accepting the canonical unrestricted-network acknowledgment. Correct the network clause while keeping the statements that are still true (the backend has no network primitive; proxy policy is rejected at every phase).
oneshot.md: drop the Test Plan Count column and the '~31 backend-specific' / '287 total currently passing' figures. They were already stale (policy.rs has 28 tests, listed as ~24) and the rows never summed to the stated total. No other backend doc or README tracks test counts, so removing them makes this doc consistent and deletes a number that silently rots whenever a test is added. The durable Category / Location / What-it-verifies content stays.
state-aware-rust.md: policy.ui was documented as rejected at every phase, but the backend never validates it, so a supplied UI policy is silently ignored. Correct the matrix to 'ignored' (matching the runtime and the state-aware design doc) and add an explicit known-gap note -- this is the same false-guarantee shape the network honesty gate closes, so rejecting policy.ui is the intended end state, not a deliberate exemption.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
* refactor: move network_specified onto ContainerPolicy
Addresses PR review feedback: the presence signal describes the content
of the policy object, not the invocation, so it belongs beside the other
parse-derived policy member (`#[serde(skip)] network_proxy`) rather than
next to ExecutionRequest's invocation flags (experimental_enabled,
testing_features_enabled, dry_run, audit).
Behavior-preserving: the flag is still captured once in the parser
(`convert_wire_config`), which is also the path `mxc_engine::build_request`
round-trips through, so the Rust SDK / FFI / C# callers are unaffected.
`#[serde(skip)]` keeps it off the wire, so the schema and generated SDK
types are unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb
---------
Co-authored-by: adpa-ms <>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47662115-cf22-4564-8930-370dfbee63fb1 parent 41839e8 commit 86ceab7
39 files changed
Lines changed: 742 additions & 126 deletions
File tree
- .github
- docs
- isolation-session
- sandbox-policy/v2
- state-aware-lifecycle
- sdk/node
- src
- tests
- integration
- unit
- src
- backends/isolation_session/common/src
- core/wxc_common/src
- tests
- configs
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
116 | | - | |
| 116 | + | |
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
119 | 128 | | |
120 | 129 | | |
121 | 130 | | |
122 | 131 | | |
123 | 132 | | |
124 | | - | |
125 | | - | |
126 | | - | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
127 | 136 | | |
128 | 137 | | |
129 | 138 | | |
| |||
146 | 155 | | |
147 | 156 | | |
148 | 157 | | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
154 | 172 | | |
155 | 173 | | |
156 | 174 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
317 | 317 | | |
318 | 318 | | |
319 | 319 | | |
320 | | - | |
| 320 | + | |
321 | 321 | | |
322 | 322 | | |
323 | 323 | | |
| |||
Lines changed: 5 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
293 | | - | |
294 | | - | |
| 293 | + | |
295 | 294 | | |
296 | 295 | | |
297 | 296 | | |
| |||
306 | 305 | | |
307 | 306 | | |
308 | 307 | | |
309 | | - | |
310 | | - | |
| 308 | + | |
311 | 309 | | |
312 | 310 | | |
313 | 311 | | |
| |||
370 | 368 | | |
371 | 369 | | |
372 | 370 | | |
373 | | - | |
374 | | - | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
375 | 374 | | |
376 | 375 | | |
377 | 376 | | |
| |||
Lines changed: 18 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
268 | 268 | | |
269 | 269 | | |
270 | 270 | | |
271 | | - | |
272 | | - | |
273 | | - | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
274 | 275 | | |
275 | 276 | | |
276 | 277 | | |
| |||
500 | 501 | | |
501 | 502 | | |
502 | 503 | | |
503 | | - | |
504 | 504 | | |
505 | 505 | | |
506 | 506 | | |
507 | 507 | | |
508 | | - | |
509 | 508 | | |
510 | | - | |
511 | | - | |
512 | | - | |
513 | | - | |
514 | | - | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
515 | 512 | | |
516 | 513 | | |
517 | 514 | | |
| |||
570 | 567 | | |
571 | 568 | | |
572 | 569 | | |
573 | | - | |
574 | | - | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
575 | 574 | | |
576 | 575 | | |
577 | 576 | | |
| |||
795 | 794 | | |
796 | 795 | | |
797 | 796 | | |
798 | | - | |
799 | | - | |
| 797 | + | |
800 | 798 | | |
801 | 799 | | |
802 | 800 | | |
| |||
811 | 809 | | |
812 | 810 | | |
813 | 811 | | |
814 | | - | |
815 | | - | |
| 812 | + | |
816 | 813 | | |
817 | 814 | | |
818 | 815 | | |
| |||
1560 | 1557 | | |
1561 | 1558 | | |
1562 | 1559 | | |
1563 | | - | |
| 1560 | + | |
1564 | 1561 | | |
1565 | | - | |
| 1562 | + | |
1566 | 1563 | | |
1567 | 1564 | | |
1568 | 1565 | | |
| |||
1586 | 1583 | | |
1587 | 1584 | | |
1588 | 1585 | | |
1589 | | - | |
1590 | | - | |
| 1586 | + | |
| 1587 | + | |
| 1588 | + | |
1591 | 1589 | | |
1592 | 1590 | | |
1593 | 1591 | | |
| |||
0 commit comments