Skip to content

[WSLC] Promote from experimental to the stable config surface - #1064

Open
Soham Das (SohamDas2021) wants to merge 10 commits into
mainfrom
user/sodas/wslc-promote-to-stable
Open

[WSLC] Promote from experimental to the stable config surface#1064
Soham Das (SohamDas2021) wants to merge 10 commits into
mainfrom
user/sodas/wslc-promote-to-stable

Conversation

@SohamDas2021

@SohamDas2021Soham Das (SohamDas2021) commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

📖 Description

Closes#1049

111 files changed — 58 test, 53 non-test (42 source/config, 11 docs).

WSLc is now configured through the top-level wslc section instead of experimental.wslc, and selecting "containment": "wslc" no longer requires --experimental / { experimental: true } / SandboxRequest::set_experimental(true). This mirrors the Seatbelt promotion precedent.

Wire + schema

  • Move wslc from wire::Experimental to the MxcConfig root, and from experimental.rs to stable.rs in the 0.9.0-alpha closed contract.
  • Keep experimental.wslc as a rejection alias so a pre-promotion config fails with an actionable migration message rather than being silently ignored.
  • Regenerate the two dev schemas and the two TypeScript wire oracles.

Parser + dispatch

  • Generalize the state-aware dispatcher with SectionRoot (Experimental | Stable); StatefulSandboxBackend::SECTION_ROOT defaults to Experimental and only WslcStateAwareRunner overrides it. ParsedStateAwareRequest gains stable_raw for stable-rooted backends.
  • Drop the experimental gate for WSLc on both the one-shot and state-aware surfaces.

TypeScript SDK

  • Move wslc out of ContainerConfig.experimental and off ExperimentalBackends; add BACKEND_SECTION_ROOT, the TS twin of the Rust SectionRoot, so envelopes are built at the right root.
  • Add a wslcAvailable probe fact end to end (Rust probe -> engine -> wxc-exec --probe -> SDK). Without it, removing the experimental gate unmasked the fact that wslc was never in availableMethods, which would have made the backend unreachable through the SDK.

Rust SDK, corpus, harnesses and docs

  • Drop the set_experimental(true) requirement from mxc-sdk.
  • Hoist experimental.wslc to top-level wslc in 31 test configs.
  • Remove --experimental from the WSLc test harnesses.
  • Update the WSLc docs, schema reference, SDK READMEs, setup script and .github/copilot-instructions.md.

🔗 References

🔍 Validation

Unit / static:

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --features wxc/wslc -- -D warnings
  • cargo test -p wxc_common -p wslc_common -p mxc_engine -p wxc -p mxc-sdk --features wxc/wslc,mxc-sdk/wslc — 1,346 tests
  • cargo test -p mxc_config_contract --features schema-gen — 707 tests
  • cd sdk/node && npm test — 283 tests, 0 fail
  • All gates: check-schema-versions, check-schema-codegen, check-sdk-types-codegen, check-contract-codegen, validate-configs (267 configs), check-version-sync, check-rust-toolchain-sync, check-psec-codegen, check-dotnet-errorcode-parity

Live WSLc E2E on a WSL2 host (run_wslc_all_tests.ps1, which chains the per-scenario scripts and delegates to the state-aware suite): 78/79. The 3 reported assertion failures are all network.proxy post-provision error-code mismatches that are pre-existing on the base commit — verified by rebuilding at the merge-base and reproducing byte-identical output — and are fixed independently by #1042.

Also verified end to end against a real wxc-exec.exe build: a promoted top-level wslc config parses and runs a container to completion, the pre-promotion experimental.wslc shape produces the migration error, and --probe reports wslcAvailable: true.

✅ 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

WSLc accepted four policy fields, carried them into the runner, and then
never read them. A caller asking for a UI lockdown, a firewall enforcement
mode, inbound local-network access, or policy preservation got a container
that silently did not have the posture they asked for. Close each hole with
an explicit policy_validation rejection.
Every rejection aborts before anything is created. All three entry surfaces
validate first: ScriptRunner::run ahead of execute, SandboxBackend::spawn
ahead of start_container, and the state-aware dispatcher ahead of each phase
body -- and connect_daemon() lives inside provision(), so a refused provision
never even spawns the daemon.
ui rejected on every phase, both surfaces
network.allowLocalNetwork rejected at state-aware provision (one-shot
already rejected it)
network.enforcementMode firewall/both rejected; capabilities accepted
lifecycle.preservePolicy rejected on one-shot (state-aware already
rejects the whole lifecycle section at parse)
ui is rejected by presence, not value. UiPolicy::default() is full lockdown,
so an explicitly supplied lockdown ui is indistinguishable by value from an
absent one -- a value-based check would let the single most restrictive
request a caller can write through unenforced. This uses the parse-derived
ContainerPolicy::ui_specified flag, mirroring IsolationSession.
enforcementMode and preservePolicy are rejected by value instead, because
their defaults honestly describe WSLc's behavior: an all-or-nothing container
network with nothing per-host to enforce, and auto-remove teardown. Refusing
those for mere presence would be dishonest.
destroyOnExit stays honored -- it selects WSLC_CONTAINER_FLAG_AUTO_REMOVE --
so only preservePolicy is refused. A blanket lifecycle rejection would have
broken the wslc_destroy_on_exit_{true,false} configs; a test pins both values
still passing.
The two allowLocalNetwork messages differ deliberately. One-shot points
callers at experimental.wslc portMappings, but WslcProvisionPhase has no
portMappings field at all, so repeating that advice on the state-aware
surface would be a lie.
Rejection ordering is filesystem -> ui -> network, documented in the policy.rs
module header and pinned by precedence tests.
No wire, schema, or parser-gating changes: this is a domain-model behavior
change only, so it lands while WSLc is still experimental and the nightly
WSLc suite exercises the new rejections before the surface moves.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c23ddc86-3848-452e-8355-e11d2ffa9b7f
Closes#1049
WSLc is now configured through the top-level `wslc` section instead of
`experimental.wslc`, and selecting `"containment": "wslc"` no longer
requires `--experimental` / `{ experimental: true }` /
`SandboxRequest::set_experimental(true)`. This mirrors the Seatbelt
promotion precedent.
Wire + schema
- Move `wslc` from `wire::Experimental` to the `MxcConfig` root, and from
`experimental.rs` to `stable.rs` in the 0.9.0-alpha closed contract.
- Keep `experimental.wslc` as a rejection alias so a pre-promotion config
fails with an actionable migration message rather than being silently
ignored.
- Regenerate the two dev schemas and the two TypeScript wire oracles.
Parser + dispatch
- Generalize the state-aware dispatcher with `SectionRoot`
(`Experimental` | `Stable`); `StatefulSandboxBackend::SECTION_ROOT`
defaults to `Experimental` and only `WslcStateAwareRunner` overrides it.
`ParsedStateAwareRequest` gains `stable_raw` for stable-rooted backends.
- Drop the experimental gate for WSLc on both the one-shot and
state-aware surfaces.
TypeScript SDK
- Move `wslc` out of `ContainerConfig.experimental` and off
`ExperimentalBackends`; add `BACKEND_SECTION_ROOT`, the TS twin of the
Rust `SectionRoot`, so envelopes are built at the right root.
- Add a `wslcAvailable` probe fact end to end (Rust probe -> engine ->
`wxc-exec --probe` -> SDK). Without it, removing the experimental gate
unmasked the fact that `wslc` was never in `availableMethods`, which
would have made the backend unreachable through the SDK.
Rust SDK, corpus, harnesses and docs
- Drop the `set_experimental(true)` requirement from `mxc-sdk`.
- Hoist `experimental.wslc` to top-level `wslc` in 31 test configs.
- Remove `--experimental` from the WSLc test harnesses.
- Update the WSLc docs, schema reference, SDK READMEs, setup script and
`.github/copilot-instructions.md`.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9f02fa89-c89e-4a5d-b80d-5130252d3654
@SohamDas2021
Soham Das (SohamDas2021) requested a review from a team as a code ownerAugust 28, 2026 18:48
@azure-pipelines

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

@microsoft-github-policy-servicemicrosoft-github-policy-serviceBot added the Copilot-Instructions PR modifies Copilot instruction files (.github/copilot-instructions.md or .github/instructions/) label Aug 28, 2026
The promotion updated the WSLc-specific guides and SDK READMEs but left
four documents still describing WSLc as experimental. Two of them are
actively wrong rather than merely stale:
- README.md listed `wslc` among the "Experimental backends" that require
`{ experimental: true }` or `--experimental`. This is the repo's front
page, and the claim is now false.
- docs/linux-wsl-roadmap-june-2026.md carried a copy-pasteable JSON
example nesting `wslc` under `experimental` -- the exact shape the
parser now rejects with the migration error. Its "Notes" section also
still listed WSLC alongside Bubblewrap as awaiting promotion.
The remaining two were internally contradictory after the promotion:
- docs/wsl/wsl-container-support-plan.md had its preamble rewritten to
say WSLc is stable while three JSON examples, the dispatch snippet,
the architecture diagram, and a runnable CLI command all still showed
the experimental gate. (The mixed top-level/nested examples predate
this branch; this commit makes the whole document consistent.)
- sdk/dotnet/README.md described `WslcContainment` as selecting "the
experimental WSLC backend" and stated `Experimental` is required. The
sample also set `Experimental = true`, which is now dead weight --
`resolve_runner` gates only MicroVm, WindowsSandbox, IsolationSession,
and Hyperlight, and `require_experimental_optin` gates only
WindowsSandbox and IsolationSession.
Docs only; no behavior change. All 14 edited JSON blocks re-verified as
parseable.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9f02fa89-c89e-4a5d-b80d-5130252d3654

CopilotAI 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

Promotes WSLc to the top-level stable configuration surface and removes its experimental opt-in. The current 173-file diff also contains substantial unrelated C#, Bubblewrap, and LXC changes.

Changes:

  • Moves WSLc configuration, dispatch, schemas, SDKs, tests, and documentation to the stable surface.
  • Adds WSLc availability probing and native sidecar packaging.
  • Includes unrelated runtime and SDK changes outside #1049’s stated scope.

Reviewed changes

Copilot reviewed 105 out of 107 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
.github/copilot-instructions.mdUpdates WSLc architecture guidance.
.github/workflows/Build.Linux.Job.ymlAdds Bubblewrap SDK tests.
.github/workflows/SDK.Dotnet.Test.Job.ymlAdds optional-backend lanes.
.github/workflows/Versioning.Checks.Job.ymlAdds C# API parity check.
README.mdLists WSLc as stable.
build.batStages WSLc runtime sidecars.
docs/linux-wsl-roadmap-june-2026.mdUpdates WSLc promotion status.
docs/schema.mdDocuments top-level WSLc.
docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.mdUpdates lifecycle wire documentation.
docs/wsl/wsl-container-getting-started.mdUpdates WSLc usage.
docs/wsl/wsl-container-support-plan.mdUpdates WSLc design status.
docs/wsl/wslc-state-aware.mdRemoves experimental requirement.
schemas/dev/mxc-config.schema.0.9.0-alpha.jsonRegenerates exact schema.
schemas/dev/mxc-config.schema.0.9.0-dev.jsonRegenerates rolling schema.
schemas/schema-version.jsonAdds WSLc lifecycle version.
scripts/check-dotnet-api-parity.jsAdds C# parity validation.
scripts/check-dotnet-bindings-codegen.jsExpands binding checks.
scripts/setup-wslc.ps1Updates configuration paths.
scripts/versioning/check-schema-versions.jsChecks WSLc/C# versions.
sdk/dotnet/CHANGELOG.mdDocuments broad C# changes.
sdk/dotnet/Microsoft.Mxc.Sdk.Sample/Program.csUses explicit request containment.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/JsonAssert.csAdds JSON golden comparison.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/Microsoft.Mxc.Sdk.Tests.csprojEmbeds shared fixtures.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/MxcLifecycleE2ETests.csExpands lifecycle coverage.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/MxcLifecycleTests.csTests lifecycle envelopes/features.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/MxcSandboxProcessTests.csExpands streaming tests.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/MxcSandboxTests.csTests requests and discovery.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/SandboxAdapterTests.csTests SDK adapters.
sdk/dotnet/Microsoft.Mxc.Sdk.Tests/SandboxPolicyDiscoveryTests.csTests policy discovery.
sdk/dotnet/Microsoft.Mxc.Sdk/Microsoft.Mxc.Sdk.csprojBuilds/packages optional backends.
sdk/dotnet/Microsoft.Mxc.Sdk/MxcLifecycle.csAdds multi-backend lifecycle support.
sdk/dotnet/Microsoft.Mxc.Sdk/MxcSandbox.csExpands managed SDK surface.
sdk/dotnet/Microsoft.Mxc.Sdk/MxcSandboxProcess.csChanges streaming lifecycle behavior.
sdk/dotnet/Microsoft.Mxc.Sdk/Native/SafeHandles.csAdds stream-closer handle.
sdk/dotnet/Microsoft.Mxc.Sdk/NetworkProxyPolicyJsonConverter.csAdds proxy-union conversion.
sdk/dotnet/Microsoft.Mxc.Sdk/PlatformDiscovery.csAdds typed platform discovery.
sdk/dotnet/Microsoft.Mxc.Sdk/SandboxAdapters.csAdds injectable adapters.
sdk/dotnet/Microsoft.Mxc.Sdk/SandboxId.csDocuments WSLc identifiers.
sdk/dotnet/Microsoft.Mxc.Sdk/SandboxPolicy.csExpands managed policy model.
sdk/dotnet/Microsoft.Mxc.Sdk/SandboxPolicyDiscovery.csAdds policy discovery helpers.
sdk/dotnet/Microsoft.Mxc.Sdk/SandboxRequest.csAdds explicit containment requests.
sdk/dotnet/Microsoft.Mxc.Sdk/SchemaVersions.csExposes schema constants.
sdk/dotnet/Microsoft.Mxc.Sdk/StateAwareTypes.csAdds backend-specific lifecycle types.
sdk/dotnet/README.mdDocuments expanded C# API.
sdk/node/README.mdUpdates WSLc SDK documentation.
sdk/node/src/generated/v0_9_0_alpha/wire.tsRegenerates exact wire types.
sdk/node/src/generated/wire.tsRegenerates rolling wire types.
sdk/node/src/platform.tsReports WSLc availability.
sdk/node/src/sandbox.tsEmits top-level WSLc config.
sdk/node/src/state-aware-helper.tsSupports stable section roots.
sdk/node/src/state-aware-types.tsUpdates WSLc paths.
sdk/node/src/types.tsRemoves WSLc from experimental types.
sdk/node/tests/integration/wslc-e2e.test.tsUpdates WSLc E2E configuration.
sdk/node/tests/unit/conformance-helpers.tsUpdates conformance documentation.
sdk/node/tests/unit/sandbox.test.tsTests stable WSLc behavior.
sdk/node/tests/unit/state-aware.test.tsTests stable lifecycle envelopes.
sdk/node/tests/unit/wire-conformance-state-aware.test.tsUpdates lifecycle conformance.
src/Cargo.lockRecords dependency changes.
src/backends/appcontainer/common/src/probe.rsAdds WSLc probe fact.
src/backends/bubblewrap/common/src/bwrap_command.rsAdds process-tree teardown flag.
src/backends/bubblewrap/common/src/bwrap_runner.rsUpdates Bubblewrap teardown handling.
src/backends/bubblewrap/common/src/bwrap_version.rsDocuments required flag version.
src/backends/lxc/common/src/lxc_runner.rsAdds network-readiness enforcement.
src/backends/wslc/common/src/daemon_client.rsResolves daemon beside native module.
src/backends/wslc/common/src/daemon_protocol.rsUpdates public-path documentation.
src/backends/wslc/common/src/policy.rsUpdates WSLc policy paths.
src/backends/wslc/common/src/state_aware.rsSelects stable section root.
src/backends/wslc/common/src/wsl_container_runner.rsUpdates stable WSLc paths.
src/backends/wslc/common/src/wslc_bindings.rsResolves SDK DLL beside module.
src/core/mxc-sdk/Cargo.tomlUpdates feature/test dependencies.
src/core/mxc-sdk/README.mdRemoves WSLc opt-in requirement.
src/core/mxc-sdk/src/lib.rsUpdates WSLc API documentation.
src/core/mxc-sdk/tests/streaming_bubblewrap.rsAdds Bubblewrap streaming coverage.
src/core/mxc_config_contract/src/dev/experimental.rsRemoves experimental WSLc contract.
src/core/mxc_config_contract/src/dev/mod.rsRe-exports stable WSLc types.
src/core/mxc_config_contract/src/dev/one_shot.rsAdds top-level WSLc field.
src/core/mxc_config_contract/src/dev/stable.rsDefines stable WSLc contract.
src/core/mxc_config_contract/src/dev/state_aware/provision/wslc.rsMoves provision configuration.
src/core/mxc_config_contract/tests/v0_9_0_alpha.rsRegisters WSLc tests.
src/core/mxc_config_contract/tests/v0_9_0_alpha/experimental.rsRemoves old test module.
src/core/mxc_config_contract/tests/v0_9_0_alpha/experimental/root.rsTests alias rejection.
src/core/mxc_config_contract/tests/v0_9_0_alpha/fixtures/one_shot/invalid/port_out_of_range.jsonUpdates invalid WSLc fixture.
src/core/mxc_config_contract/tests/v0_9_0_alpha/optional_fields.rsUpdates WSLc optional paths.
src/core/mxc_config_contract/tests/v0_9_0_alpha/state_aware/provision/wslc.rsTests WSLc provision contract.
src/core/mxc_config_contract/tests/v0_9_0_alpha/wslc.rsTests stable WSLc contract.
src/core/mxc_config_contract/tests/version_boundaries.rsRegisters boundary tests.
src/core/mxc_config_contract/tests/version_boundaries/experimental.rsRemoves experimental boundary case.
src/core/mxc_config_contract/tests/version_boundaries/state_aware.rsUpdates lifecycle boundary fixture.
src/core/mxc_config_contract/tests/version_boundaries/wslc.rsAdds WSLc version boundaries.
src/core/mxc_engine/src/dispatch.rsRemoves streaming opt-in gate.
src/core/mxc_engine/src/guarded_capture.rsReuses module-path resolver.
src/core/mxc_engine/src/lib.rsExports WSLc availability.
src/core/mxc_engine/src/platform.rsAdds serializable WSLc support.
src/core/mxc_engine/src/policy.rsBuilds top-level WSLc config.
src/core/mxc_engine/src/run.rsRemoves one-shot opt-in gate.
src/core/mxc_engine/src/state_aware.rsRemoves lifecycle opt-in gate.
src/core/wxc/src/main.rsPublishes WSLc probe fact.
src/core/wxc_common/src/config_contract_adapters/dev/one_shot.rsAdapts stable WSLc config.
src/core/wxc_common/src/config_contract_adapters/dev/one_shot_tests/experimental.rsUpdates adapter tests.
src/core/wxc_common/src/config_contract_adapters/dev/state_aware.rsAdapts stable lifecycle config.
src/core/wxc_common/src/config_contract_adapters/dev/state_aware_tests/provision.rsUpdates provision adapter tests.
src/core/wxc_common/src/config_contract_adapters/v0_6.rsInitializes new wire field.
src/core/wxc_common/src/config_contract_adapters/v0_7.rsInitializes new wire field.
src/core/wxc_common/src/config_contract_adapters/v0_8.rsInitializes new wire field.
src/core/wxc_common/src/config_parser.rsParses/rejects promoted WSLc shapes.
src/core/wxc_common/src/models.rsMoves WSLc into request model.
src/core/wxc_common/src/process_util.rsAdds native module-path resolver.
src/core/wxc_common/src/state_aware_backend.rsAdds backend section-root metadata.
src/core/wxc_common/src/state_aware_dispatch.rsDispatches by section root.
src/core/wxc_common/src/state_aware_request.rsRetains stable-rooted raw config.
src/core/wxc_common/src/wire.rsPromotes WSLc wire section.
src/ffi/mxc_ffi/Cargo.tomlAdds WSLc feature/dependency.
src/ffi/mxc_ffi/src/lib.rsExpands FFI SDK surface.
src/ffi/mxc_ffi/src/request.rsAdds request-contract handling.
src/ffi/mxc_ffi/src/state_aware.rsTests shared lifecycle fixtures.
src/ffi/mxc_ffi/src/streaming.rsExpands streaming FFI.
src/ffi/mxc_ffi/tests/ffi.rsExpands FFI integration coverage.
src/testing/wxc_e2e_tests/tests/e2e_bubblewrap_characterization.rsStrengthens timeout teardown test.
tests/configs/bubblewrap_network_egress_budget_rejected.jsonAdds network-budget fixture.
tests/configs/bubblewrap_readonly_denial.jsonAdds read-only denial fixture.
tests/configs/bubblewrap_teardown_timeout.jsonAdds teardown fixture.
tests/configs/bubblewrap_teardown_timeout_netns.jsonAdds network teardown fixture.
tests/configs/bubblewrap_version_gate.jsonAdds version-gate fixture.
tests/configs/wslc_custom_registry.jsonHoists WSLc section.
tests/configs/wslc_custom_registry_ghcr.jsonHoists WSLc section.
tests/configs/wslc_custom_registry_quay.jsonHoists WSLc section.
tests/configs/wslc_denied_dotdot_alias.jsonHoists WSLc section.
tests/configs/wslc_denied_masking.jsonHoists WSLc section.
tests/configs/wslc_destroy_on_exit_false_rejected.jsonHoists WSLc section.
tests/configs/wslc_destroy_on_exit_true.jsonHoists WSLc section.
tests/configs/wslc_env_vars.jsonHoists WSLc section.
tests/configs/wslc_exit_code.jsonHoists WSLc section.
tests/configs/wslc_filesystem.jsonHoists WSLc section.
tests/configs/wslc_filesystem_object.jsonHoists WSLc section.
tests/configs/wslc_large_output.jsonHoists WSLc section.
tests/configs/wslc_most_specific_denied_parent.jsonHoists WSLc section.
tests/configs/wslc_network_isolated.jsonHoists WSLc section.
tests/configs/wslc_network_proxy.jsonHoists WSLc section.
tests/configs/wslc_port_mapping_multiple.jsonHoists WSLc section.
tests/configs/wslc_port_mapping_tcp.jsonHoists WSLc section.
tests/configs/wslc_python_hello.jsonHoists WSLc section.
tests/configs/wslc_python_stdlib.jsonHoists WSLc section.
tests/configs/wslc_readonly_mount.jsonHoists WSLc section.
tests/configs/wslc_state_aware_provision.jsonHoists lifecycle WSLc section.
tests/configs/wslc_state_aware_provision_bridged.jsonHoists lifecycle WSLc section.
tests/configs/wslc_state_aware_provision_rejected_denied.jsonHoists lifecycle WSLc section.
tests/configs/wslc_state_aware_provision_rejected_hosts.jsonHoists lifecycle WSLc section.
tests/configs/wslc_state_aware_provision_rejected_proxy.jsonHoists lifecycle WSLc section.
tests/configs/wslc_state_aware_provision_with_filesystem.jsonHoists lifecycle WSLc section.
tests/configs/wslc_stderr.jsonHoists WSLc section.
tests/configs/wslc_tar_import_docker_save.jsonHoists WSLc section.
tests/configs/wslc_tar_import_rootfs.jsonHoists WSLc section.
tests/configs/wslc_timeout.jsonHoists WSLc section.
tests/examples/wslc_hello_world.jsonUpdates WSLc example.
tests/policy/README.mdDocuments shared fixtures.
tests/policy/request-directional-network.jsonAdds request golden.
tests/policy/request-process-container.jsonAdds request golden.
tests/policy/request-wslc.jsonAdds WSLc request golden.
tests/policy/state-aware-wslc-exec.jsonAdds WSLc exec golden.
tests/policy/state-aware-wslc-provision.jsonAdds WSLc provision golden.
tests/scripts/run_bwrap_all_tests.shRegisters new Bubblewrap tests.
tests/scripts/run_bwrap_directional_test.shTests network budget rejection.
tests/scripts/run_bwrap_readonly_denial_test.shTests read-only enforcement.
tests/scripts/run_bwrap_teardown_test.shTests process-tree teardown.
tests/scripts/run_bwrap_version_gate_test.shTests bwrap version gating.
tests/scripts/run_lxc_all_tests.shUpdates LXC suite.
tests/scripts/run_wslc_all_tests.ps1Removes WSLc experimental flag.
tests/scripts/run_wslc_denied_masking_test.ps1Removes experimental flag.
tests/scripts/run_wslc_dotdot_alias_test.ps1Removes experimental flag.
tests/scripts/run_wslc_most_specific_test.ps1Removes experimental flag.
tests/scripts/run_wslc_object_test.ps1Removes experimental flag.
tests/scripts/run_wslc_proxy_test.ps1Removes experimental flag.
tests/scripts/run_wslc_state_aware_tests.ps1Removes lifecycle opt-in.
Suppressed comments (1)

sdk/dotnet/README.md:540

  • This newly added overview contradicts the promotion: WSLc is no longer experimental, while IsolationSession and Windows Sandbox remain experimental. Distinguish WSLc from those two so managed SDK users do not retain an unnecessary opt-in.
state-aware lifecycle supports IsolationSession, Windows Sandbox, and WSLC on
Windows; all three are experimental).

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

Comment threaddocs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md Outdated
CopilotAI review requested due to automatic review settings August 28, 2026 20:00

CopilotAI 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

Copilot reviewed 105 out of 107 changed files in this pull request and generated 3 comments.

Comment threadsrc/core/wxc_common/src/wire.rs Outdated
Comment threadsdk/node/src/platform.ts
The promotion left three consumers still speaking the pre-promotion wire
shape, which surfaced as four CI failures across two root causes.
`MxcLifecycle.SetBackendConfig` nested every backend's per-phase config
under `experimental.<backend>.<phase>` unconditionally. Now that the
parser rejects `experimental.wslc` outright, that produced a
`malformed_request` before backend resolution could report anything
useful. Give the C# SDK the same section-root switch the TypeScript SDK
already carries in `BACKEND_SECTION_ROOT`, so a promoted backend writes a
closed top-level `wslc.<phase>` section while the still-experimental
backends keep their `experimental` nesting. The switch is exhaustive over
the known backends and throws on an undeclared one, so adding a backend
without choosing a root fails loudly instead of silently defaulting.
That single emitter fix clears three of the four failures: the .NET
`WslcBuildSwitch_MatchesNativeAvailabilityAndStagesRuntimeUnit` test on
all three platforms, and the Rust
`managed_state_aware_goldens_are_accepted_by_native_contract` test in
`mxc_ffi`, which feeds the C# golden fixtures back through the native
contract. The golden `state-aware-wslc-provision.json` and the
`BuildProvisionEnvelope_WslcUsesV08AndNestsImageOptions` assertion move
with it; the latter now also asserts that no `experimental` section is
emitted at all, so a regression cannot pass by nesting the section twice.
Separately, `check-dotnet-api-parity.js` compared the managed
`StateAwareContainment` enum against the `require_experimental_optin`
list in `state_aware.rs`. That list is the *experimental subset*, not the
set of state-aware backends; the two were only coincidentally equal
before this promotion and diverge the moment a backend is promoted.
Compare against `backend_from_prefix` in `state_aware_dispatch.rs`, which
is the actual registry of reachable state-aware backends. This also
strengthens the check, since it now tracks the dispatcher rather than a
gate that shrinks over time, and it drops a now-redundant second read of
`state_aware_dispatch.rs`.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9f02fa89-c89e-4a5d-b80d-5130252d3654
CopilotAI review requested due to automatic review settings August 28, 2026 20:12

CopilotAI 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

Copilot reviewed 109 out of 111 changed files in this pull request and generated 6 comments.

Suppressed comments (3)

Previously missed (1) — in code that hasn't changed since the last review.

sdk/node/src/platform.ts:171

  • This availability fact is obtained by probing the auto-discovered wxc-exec, but resolveExecutableAndArgs may later run options.executablePath. A caller supplying a WSLc-enabled custom binary is therefore rejected when the separately discovered binary lacks WSLc (and the inverse can be incorrectly accepted). Probe the selected executable, or defer this per-binary feature check to an explicitly supplied executable.
 if (facts.wslcAvailable === true) {
support.availableMethods.push('wslc');

sdk/node/tests/unit/sandbox.test.ts:1292

  • This assertion passes only when the current host reports WSLc unavailable. On a WSLc-capable host the helper correctly returns arguments, so the test fails. Bypass the unrelated availability check and directly verify that promotion removed the CLI flag.
 assert.throws(
() => resolveExecutableAndArgs(makeConfig('wslc'), { executablePath: fakeExe }),
(e: Error) => !/experimental mode/.test(e.message),
);

sdk/node/README.md:145

  • WSLc does not work out of the box: default Windows builds omit the wslc feature and the README elsewhere requires build.bat --with-wslc. Describe it as non-experimental but build-time opt-in.
The default `processcontainer`, `bubblewrap`, `lxc`, `seatbelt`, and `wslc` backends work out of the box. **Experimental backends** (`windows_sandbox`, `microvm`, `isolation_session`, `hyperlight`) require `{ experimental: true }` in `SandboxSpawnOptions` when you spawn — see [Choosing a Backend](#choosing-a-backend).

Comment threadsrc/core/wxc_common/src/config_parser.rs
Comment threadsrc/core/wxc_common/src/wire.rs
Comment threadsrc/core/wxc_common/src/models.rs
Comment threadsdk/node/tests/unit/sandbox.test.ts Outdated
Comment threadsdk/node/README.md Outdated
Comment threadsdk/node/README.md Outdated
Comment threaddocs/wsl/wsl-container-support-plan.md
@SohamDas2021Soham Das (SohamDas2021) changed the title [WSLC] Promote WSLc from experimental to the stable config surface[WSLC] Promote from experimental to the stable config surfaceSep 1, 2026
Comment threadschemas/dev/mxc-config.schema.0.9.0-alpha.json
}
],
"description": "WSL container backend config."
"description": "WSL container backend config (pre-promotion alias). Promoted to the top-level `wslc` section; still parsed here so the parser can reject it with a migration message instead of silently ignoring it."

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: I'm now realizing that we have an alpha and a dev and now I'm wondering if the promotion process is now that you do the same thing you did in the alpha, in the dev?

Comment threadscripts/check-dotnet-api-parity.js
Comment threadsdk/dotnet/Microsoft.Mxc.Sdk.Tests/MxcLifecycleTests.cs Outdated
Comment threadsdk/dotnet/Microsoft.Mxc.Sdk/MxcLifecycle.cs
Comment threadsrc/core/mxc_engine/src/run.rs
Comment threadsrc/core/wxc/src/main.rs Outdated
Comment threadsrc/core/wxc_common/src/state_aware_backend.rs
Comment threadsrc/core/wxc_common/src/wire.rs Outdated
Comment threadsrc/core/wxc_common/src/config_parser.rs Outdated
@microsoft-github-policy-servicemicrosoft-github-policy-serviceBot added Needs-Author-Feedback Issue needs attention from issue or PR author Needs-Attention Issue needs attention from Microsoft and removed Needs-Author-Feedback Issue needs attention from issue or PR author labels Sep 3, 2026
Comment threadsdk/node/src/sandbox.ts
@adpa-ms

Copy link
Copy Markdown
Contributor

[AgentAssisted] Two documentation spots a comment sweep may not reach — both outside the current diff, so not attachable to a line.

wire.rs's Containment::Wslc is still documented /// WSL container (experimental)., and that string is emitted as the description for the wslc containment value in the regenerated 0.9.0-dev schema, so config authors see "experimental" in editor validation. The codegen gate will catch the regeneration once the doc comment is updated.

docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md still contains the literal experimental.<backend> 16 times, with no mention of SectionRoot / SECTION_ROOT / stable_raw / BACKEND_SECTION_ROOT. As the cross-backend contract doc it's now wrong for one of its three backends, and it's the doc the next promotion would follow.

Base automatically changed from user/sodas/wslc-rejection-hardening to mainSeptember 4, 2026 00:07
CopilotAI review requested due to automatic review settings September 4, 2026 17:53

CopilotAI 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.

🟡 Changes recommended

Several public API and generated-schema descriptions still incorrectly document WSLc as experimental or report the previous schema default.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 131/133 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment threaddocs/wsl/wsl-container-support-plan.md
Comment threadsdk/node/src/state-aware-types.ts
Comment threadsrc/core/mxc_engine/src/policy.rs
CopilotAI review requested due to automatic review settings September 4, 2026 18:14
@SohamDas2021
Soham Das (SohamDas2021)force-pushed the user/sodas/wslc-promote-to-stable branch from 83ea3b7 to 57a0fdcCompareSeptember 4, 2026 18:14

CopilotAI 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.

🟡 Changes recommended

The SDK builders can emit the 0.9-only WSLc shape with older schema versions, and several updated documents remain inaccurate.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 131/133 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment on lines +120 to 122
config.wslc = {
image: 'alpine:latest',
};
Comment on lines 974 to +977
fn apply_wslc_backend(config: &mut serde_json::Value, wslc: &WslcSection) {
use serde_json::json;
config["containment"] = json!("wslc");
config["experimental"] = json!({ "wslc": wslc.wire() });
config["wslc"] = wslc.wire();
Comment threaddocs/schema.md
"release": "3.19"
},

"wslc": { // WSL Container settings (Windows only)
Comment on lines +89 to 92
All backends implement the `ScriptRunner` trait. `main.rs` uses `Box<dyn ScriptRunner>` with a `match` on `request.containment`. WSLC is a stable backend and needs no `--experimental` gate; the remaining experimental backends (Sandbox, MicroVM, IsolationSession, Hyperlight) still do:

```rust
// main.rs — current dispatch
```

Run with: `wxc-exec.exe --experimental --debug app-policy.json`
Run with: `wxc-exec.exe --debug app-policy.json`
var root = doc.RootElement;

Assert.Equal("0.8.0-alpha", root.GetProperty("version").GetString());
Assert.Equal("0.9.0-alpha", root.GetProperty("version").GetString());
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c28d1c5e-fe3e-4634-9dd7-246528cc9edd
CopilotAI review requested due to automatic review settings September 4, 2026 18:21
@SohamDas2021
Soham Das (SohamDas2021)force-pushed the user/sodas/wslc-promote-to-stable branch from 57a0fdc to d784cc4CompareSeptember 4, 2026 18:21

CopilotAI 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.

🟡 Changes recommended

Stable WSLc builders still emit schema-invalid pre-0.9 configurations, and post-provision validation can silently discard a foreign backend block.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

sdk/node/src/sandbox.ts:122

  • This now emits a top-level wslc field for every supported policy version, including 0.6–0.8. The 0.9 contract and version-boundary tests introduce this field only in 0.9, and the SDK README explicitly says WSLc configs must declare 0.9, so createConfigFromPolicy({ version: '0.6.0-alpha' }, 'wslc') returns schema-invalid JSON. Reject pre-0.9 policy versions here (and update the existing 0.6 WSLc tests) rather than constructing a config that does not match its declared contract.
 config.wslc = {
image: 'alpine:latest',
};

src/core/mxc_engine/src/policy.rs:977

  • The Rust builder has the same contract hole as the TypeScript SDK: it writes the newly introduced top-level wslc section while preserving any caller-supplied 0.6–0.8 version (the current WSLc tests use minimal_policy() at 0.7). Such output is invalid against the closed contracts and conflicts with the new v0.9 boundary test. Validate that WSLc is paired with schema 0.9+ before building the wire object; this also protects the C# one-shot API, which delegates through this builder.
    docs/wsl/wsl-container-support-plan.md:89
  • This updated “current dispatch” description is still architecturally incorrect: wxc is a thin CLI and backend selection lives in mxc_engine::run::resolve_runner_inner_windows (src/core/mxc_engine/src/run.rs:124-182), using request.wslc, not main.rs/request.container_config. Update or remove the paragraph and sample so the promotion docs point contributors to the actual dispatch layer.
All backends implement the `ScriptRunner` trait. `main.rs` uses `Box<dyn ScriptRunner>` with a `match` on `request.containment`. WSLC is a stable backend and needs no `--experimental` gate; the remaining experimental backends (Sandbox, MicroVM, IsolationSession, Hyperlight) still do:
  • Files reviewed: 131/133 changed files
  • Comments generated: 1
  • Review effort level: Balanced

@@ -1490,6 +1512,53 @@ fn convert_wire_state_aware(

validate_experimental_backend_keys(containment.as_ref(), experimental_raw.as_ref())?;
Resolves the conflicts caused by #1058 (WSLc rejection hardening) being
squash-merged to main as ab8930d while this branch already carried its
original commits, plus four other changes that landed alongside it.
Twelve files conflicted. Most were "both sides added a sibling", so the
resolution keeps both additions rather than either side alone:
- probe.rs / main.rs / platform.ts (+ tests): keep both the wslc_available
gate from this branch and the hyperlight_available gate from #1059.
- platform.test.ts: split the merged block into separate "wslc availability
gate" and "hyperlight availability gate" describes.
- sandbox.test.ts: keep main's new Linux backend-failure-reason test
alongside the renamed windows_sandbox test.
- docs/schema.md: combine two independent promotions -- top-level wslc from
this branch and top-level seatbelt (with extraMachLookups) from #1033 --
leaving experimental holding only telemetry.
- sdk/node/README.md: keep both the Windows wslc-gating sentence and main's
Linux unavailableReasons sentence.
The remaining five (policy.rs, wsl_container_runner.rs, the two WSLc test
configs, copilot-instructions.md) are pure promotion conflicts where this
branch's form -- wslc.portMappings, schema 0.9.0-alpha, the top-level wslc
block -- is the correct one.
Verified: cargo check/clippy/fmt/test --workspace --features wslc, the six
versioning and codegen gates, npm run build + npm test (331 tests), and
dotnet build of the C# SDK all pass.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c28d1c5e-fe3e-4634-9dd7-246528cc9edd
CopilotAI review requested due to automatic review settings September 4, 2026 19:24

CopilotAI 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.

🟡 Changes recommended

Stable WSLc lifecycle requests can still silently discard a foreign experimental backend section on non-provision phases.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

src/core/wxc_common/src/config_parser.rs:1454

  • This migration check still allows a foreign experimental backend block on WSLc's non-provision phases. For example, an exec with a wslc: sandbox ID and experimental.windows_sandbox reaches validate_experimental_backend_keys with containment == None; its single key is accepted, then WSLc dispatch reads only the stable root and silently drops that block. Resolve the validation backend from sandboxId before validating so stable WSLc rejects every experimental backend section.
    docs/wsl/wsl-container-support-plan.md:89
  • This updated text still describes an architecture that no longer exists: wxc delegates backend selection to mxc_engine, and main.rs has no match request.containment. Point the example at src/core/mxc_engine/src/run.rs::resolve_runner (and update the snippet) so the promotion documentation does not direct maintainers to the wrong dispatch layer.
All backends implement the `ScriptRunner` trait. `main.rs` uses `Box<dyn ScriptRunner>` with a `match` on `request.containment`. WSLC is a stable backend and needs no `--experimental` gate; the remaining experimental backends (Sandbox, MicroVM, IsolationSession, Hyperlight) still do:

sdk/dotnet/Microsoft.Mxc.Sdk.Tests/MxcLifecycleTests.cs:422

  • The assertion now expects 0.9, but the test is still named BuildProvisionEnvelope_WslcUsesV08AndNestsImageOptions. Rename it to V09 so failures and test filters identify the contract being exercised.
 Assert.Equal("0.9.0-alpha", root.GetProperty("version").GetString());
  • Files reviewed: 129/131 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +23 to 24
//! separate from the public `wslc.*` wire schema. The state-aware
//! backend (a later PR) is the translator between the public wire model and
Comment on lines +385 to +387
/// Target operating system inside the container.
#[serde(default)]
pub target_os: OptionalField<String>,

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.

[AgentAssisted] targetOs has no consumer — no read of WslcConfig::target_os anywhere in src/backends/wslc/, and the parser passes any string through, so "windows" or "" silently runs Linux. Pre-existing and unchanged from main, so not a regression.

Flagging it here only because this block is the closed stable surface: removing the field is free today and a breaking change later. If it's reserved for planned multi-OS support, that's a good reason to keep it and no action is needed — otherwise dropping it, or validating "linux", would close the gap.

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

Labels

Copilot-InstructionsPR modifies Copilot instruction files (.github/copilot-instructions.md or .github/instructions/)Needs-AttentionIssue needs attention from Microsoft

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[WSLC] Promote WSLC, move it out of experimental

5 participants

@SohamDas2021@adpa-ms@dhoehna@bbonaby