feat: add Hyper-V provider for local Windows VMs - #212
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 11, 2026, 8:49 AM ET / 12:49 UTC. Summary Reproducibility: not applicable. as a bug reproduction; this is a new provider feature, and the PR body plus maintainer comment provide live after-fix Hyper-V behavior proof instead. Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Merge this only if maintainers are ready to support Do we have a high-confidence way to reproduce the issue? Not applicable as a bug reproduction; this is a new provider feature, and the PR body plus maintainer comment provide live after-fix Hyper-V behavior proof instead. Is this the best way to solve the issue? Yes, if maintainers want Hyper-V in core: the implementation keeps Hyper-V lifecycle code in a provider adapter, keeps the guest password off argv, pins and verifies MinGit, and includes mocked lifecycle plus live host validation. The remaining question is product/support ownership, not a narrower code repair. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f6ad6f84ca33. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
581a5b8 to
010aef7
Compare
|
@clawsweeper re-review The provider now makes a plain Windows VHDX (just a known admin password) work end-to-end — it supplies the rest:
Live proof in the body: doctor → warmup→state=ready (ssh=Administrator@…, workroot=C:\crabbox) → run (sync+command over SSH) → list → stop → cleanup (0 VMs), on a plain dev VHDX with C: full (storage redirected to D:). |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review Addressed the P2: registered the documented |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
# Conflicts: # docs/source-map.md
|
Maintainer live validation on June 11, 2026:
Local verification at
|
* fix(hyperv): provisioning hangs forever waiting for PowerShell Direct A new Hyper-V lease could hang indefinitely during provisioning. After Start-VM, the first guest call (PowerShell Direct via stageSSHKey) fires while the guest is still booting, where `Invoke-Command -VMName` blocks instead of fast-failing, and no per-attempt timeout let the fixed retry loop advance. The whole `crabbox run` then stalls with no progress. This has been latent since the provider was introduced in #212. Add a bounded PowerShell Direct readiness gate (`waitGuestReady`) before the first guest call: it retries a trivial authenticated probe within an overall budget, with each attempt bounded so a blocked probe is killed and retried (verified not to corrupt the guest session). Every real guest call (`invokeInGuest`) also gets a generous per-attempt timeout so a wedged mid-session call can never hang the provision. Also fix guest OpenSSH install: `Add-WindowsCapability` (Features-on-Demand) fails 0x800f0950 on templates without Windows Update access, so a plain template could never finish provisioning. Install the pinned, SHA-256-verified Win32-OpenSSH MSI (the Microsoft.OpenSSH.Preview payload) from GitHub instead, mirroring how git is bootstrapped, and resolve sshd/ssh-keygen from the sshd service path since the MSI installs to C:\Program Files\OpenSSH rather than System32\OpenSSH. * docs(hyperv): document bootstrap requirements Align the repo-local Crabbox skill and Hyper-V provider reference with the bounded PowerShell Direct readiness gate and pinned Win32-OpenSSH MSI bootstrap. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9f442e2b-8ad2-401d-b570-5490c436e9c4 * docs: tighten Hyper-V guidance and comments * docs: restore Hyper-V maintenance context * docs: sync published Crabbox skill * fix(hyperv): select native OpenSSH package Co-authored-by: Paul Campbell (AgOS) <paulcam@microsoft.com> * docs: shorten Hyper-V skill guidance --------- Co-authored-by: Dallin Romney <dallinromney@gmail.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary
A
hypervprovider for running Crabbox leases on local Windows VMs via Microsoft Hyper-V and PowerShell Direct — the Windows-native counterpart totart(macOS), with no external CLI or cloud account. The design goal is "bring a plain Windows VHDX with a known administrator password, and it just works": the provider supplies everything else. With--hyperv-init-passwordeven that requirement drops away for auto-logon images: a stock, password-less Microsoft dev-environment VHDX works completely unmodified.How it works
crabbox warmup --provider hyperv --hyperv-image <vhdx>:New-VHD -Differencing -ParentPath) — near-instant and space-thin (a few MB up front), so the template stays read-only and shared instead of copying tens of GB per lease.--hyperv-init-passwordthe provider mounts the lease's own differencing disk offline, loads its registry hive, and writes aRunOncecommand that sets the guest password toCRABBOX_HYPERV_GUEST_PASSWORDat the template's auto-logon. The template VHDX is never modified. Guard rails: requires an explicitCRABBOX_HYPERV_GUEST_PASSWORD(refuses to stamp the default password onto a guest), rejects"/%in the password and the user name (both pass through cmd.exe), and the password reaches the host-side script via env, never argv.New-VM -Generation 2 -Path <vmDir>puts the VM config and the multi-GB.VMRSruntime files on the same (data) drive as the VHD rather than defaulting toC:\ProgramData, and automatic checkpoints are disabled (Set-VM -AutomaticCheckpointsEnabled $false) so a lease never spawns a.avhdxthat would strand a disk on release.Add-WindowsCapability,Start-Service sshd, firewall) and installs git if absent (portable MinGit, pinned to an immutable release asset and SHA-256-verified before extraction) — mirroring how the Linux cloud-init path provisions a guest. Both are no-ops when already present, so a template that pre-bakes them just skips the download. MinGit is extracted toC:\Program Files\MinGit, notC:\Program Files\Git: MinGit'setc\gitconfigdeliberately includesC:/Program Files/Git/etc/gitconfig, so extracting it there makes the include self-referential and every guest git command dies with "exceeded maximum include depth" (caught live by the second proof below; fixed in this PR).authorized_keysand, for admin accounts,administrators_authorized_keyswith the SYSTEM+Administrators-only ACL that Windows OpenSSH requires (otherwise sshd silently ignores it).crabbox-name prefix.Net template requirement: a Generation-2 Windows VHDX — either with an administrator password known to Crabbox (
--hyperv-user/CRABBOX_HYPERV_GUEST_PASSWORD), or, for auto-logon images, none at all with--hyperv-init-password. Non-Windows targets are rejected (from CLI, YAML, or env), and ISO images are rejected.Live proof 1 — passworded template (existing path), Windows 11 Pro host, Go 1.26.4
Captured on the latest head. Plain Windows 11 VHDX with only an admin password set; C: deliberately full so storage is redirected to D: (which also exercises the off-system-drive placement):
Live proof 2 — broader template coverage: STOCK password-less Microsoft image +
--hyperv-init-passwordThe template here is Microsoft's downloadable
WinDev2407Eval.vhdxexactly as downloaded (file mtime 2024-07-25 before and after the run — never written): auto-logonUser, no password, no OpenSSH, no git. One flag makes it a working lease:Reaching
state=readyhere exercises the full chain on a guest that started with nothing — first-boot password injection, OpenSSH install, pinned + checksum-verified MinGit install (to the corrected path;git --versionexiting 0 in-guest is the regression proof for the MinGit fix), ACL-correct key injection, and the Windows readiness check over SSH.Configuration
CLI:
--hyperv-image(required),--hyperv-cpu,--hyperv-memory,--hyperv-switch,--hyperv-user,--hyperv-work-root,--hyperv-init-password. YAMLhyperv:andCRABBOX_HYPERV_*env equivalents, incl.CRABBOX_HYPERV_GUEST_PASSWORDandCRABBOX_HYPERV_INIT_PASSWORD.Not included (follow-up)
%USERPROFILE%).