Skip to content

feat(sandbox): Windows/WSL backend (sandbox Phase 3) - #201

Merged
quickbeard merged 3 commits into
mainfrom
sandbox-wsl-provider
Aug 12, 2026
Merged

quickbeard merged 3 commits into
mainfrom
sandbox-wsl-provider

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

Phase 3 (Windows/WSL) groundwork and provider. In progress — the WSL provider lands on this branch, so this PR will grow.

Landed so far

--backend bwrap|vz filter for build-image.ts. WSL and bubblewrap consume the rootfs tarball and bring their own kernel; only vz needs the compiled one. Building both together meant a cross-arch x64 rootfs — exactly what wsl --import needs for an x64 Windows fleet — dragged in a QEMU-emulated Linux compile that takes hours on an Apple Silicon host. --backend bwrap now stops after the tarball, skipping the ext4 and kernel stages.

Default is unchanged (both backends), so existing invocations behave as before. Invalid values are rejected before Docker is touched.

Still to come on this branch

  • src/wsl/ provider: wsl --import of bwrap-x64.tar.gz, guest server launch over the same boot.json contract fix(sandbox): boot the guest server via a launcher, not a CLI #200 established
  • Windows version policy: warn-never-block, with Win10 22H2 (19045) warned and Win11 clean
  • Populate the wslInstaller manifest block (null today, already scaffolded in manifest.ts)

Context

Target fleet is x64-only, half Windows 11 and half Windows 10 22H2 (19045) — so both paths matter and there are no sub-22H2 machines to support.

Verified before starting: the vz sandbox now boots and serves end to end on this base (e2e-vz.ts → health: OK, create 1.82s, start 1.61s, authenticated /global/health over the vsock bridge).

🤖 Generated with Claude Code

quickbeard and others added 3 commits August 12, 2026 17:48
WSL and bubblewrap consume the rootfs tarball and bring their own kernel;
only vz needs the compiled one. Building the two together meant a cross-arch
x64 rootfs — what `wsl --import` needs on an x64 Windows fleet — dragged in a
QEMU-emulated Linux compile that takes hours on an Apple Silicon host.

--backend bwrap now stops after the tarball, skipping the ext4 and kernel
stages. Default stays both backends, so existing invocations are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Creates a codev-managed WSL2 distribution from the rootfs tarball with
`wsl --import` and boots the same guest launcher the vz and bwrap backends
use, so one server bundle and one boot.json contract cover every platform.

Three Windows-specific details drive the shape:

- wsl.exe emits UTF-16LE for --version/--list/--import and UTF-8 for output
  piped out of a distro. decodeWslOutput sniffs NUL bytes to tell them apart;
  reading the list as UTF-8 yields NUL-interleaved garbage that silently never
  matches a distro name.
- WSL2 republishes a guest loopback port under the same number on the Windows
  loopback, so host and guest must agree on one port. The provider reserves it
  on the host first, which also keeps concurrent sandboxes from colliding.
- Credentials go through WSLENV rather than the command line, where any host
  process could read them out of the process table.

Windows version policy comes from the existing windowsSandboxAvailability, so
Win11 is clean, Win10 22H2 warns, and nothing is ever hard-blocked.

Tests drive the real code through a fake wsl.exe: distro registration, path
translation, the boot script, and a create -> start -> authenticated health
check -> destroy round trip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mirrors e2e-vz.ts for Windows: serves a locally built rootfs tarball over
loopback HTTP, imports the distribution, boots the guest server, and waits for
the authenticated health check over WSL2 localhost forwarding. This is what
makes the WSL provider runnable on a real machine before any desktop wiring
exists.

Two differences from e2e-vz.ts, both deliberate:

- The sha256 is digested once up front rather than inside resolveImage. A hash
  object cannot be digested twice, so computing it in the callback breaks as
  soon as the provider resolves the image more than once.
- --image and --bundle are resolved to absolute paths, because wslpath resolves
  relative paths against the guest's cwd rather than the host's.

--hold keeps the distribution up for inspection; --keep skips the unregister.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@quickbeard
quickbeard force-pushed the sandbox-wsl-provider branch from 779db6f to 92cf880 Compare August 12, 2026 10:49
@quickbeard
quickbeard merged commit fdc10f6 into main Aug 12, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the sandbox-wsl-provider branch August 13, 2026 01:15
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.

1 participant