Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Contents:
- `scripts/build-qemu.sh` — reproducible local QEMU build, with one rolling screenshot file and a bounded first-boot settle loop
- `scripts/verify.ps1` + `scripts/remediate.ps1` — in-guest verification / remediation loop
- `scripts/firstboot-state.ps1` — lightweight first-boot probe used to wait for concrete SAC runtime components before verification
- `scripts/cocoon-nic-autoheal.ps1` — body of the `CocoonNicAutoHeal` scheduled task; cycles every Net PnP device once a minute to recover chained-clone guests where vm.restore leaves the NIC bound but unable to transmit
- `scripts/verify-ch.sh` + `scripts/sac_probe.py` — Cloud Hypervisor runtime validation for DHCP, RDP, real SAC, and clean shutdown
- `.github/workflows/build.yml` — headless QEMU/KVM build on `ubuntu-latest`, publishes to GHCR via ORAS

Expand Down Expand Up @@ -399,7 +400,7 @@ The included [`autounattend.xml`](autounattend.xml) drives the install across th
- **International-Core**: `InputLocale=0409:00000409` only. The component must be present here for Windows 11 25H2 OOBE to skip the country / keyboard selection screens.
- **OOBE**: hides EULA, online account, wireless setup.
- **User account**: local admin `cocoon` with auto-logon (password base64-encoded in XML).
- **FirstLogonCommands**: 53 commands.
- **FirstLogonCommands**: 55 commands.

| Order | Action | Notes |
|--------|------------------------------|-------|
Expand Down Expand Up @@ -429,8 +430,10 @@ The included [`autounattend.xml`](autounattend.xml) drives the install across th
| 47 | **Zero startup delay** | `Explorer\Serialize\StartupDelayInMSec=0` |
| 48-50 | **DWM tuning** | No minimize animation, no drag full windows, ClearType font smoothing |
| 51 | **Disable scheduled tasks** | Compatibility Appraiser, ScheduledDefrag, DiskDiagnostic |
| 52 | **QuickEdit restore** | Restore QuickEdit after install |
| 53 | **Install marker** | `cmd /c "echo %date% %time% > C:\install.success"` |
| 52 | **viosock driver** | `pnputil /add-driver D:\viosock\w11\amd64\viosock.inf /install` (D: + E: + standard + attestation paths). Required for cocoon-agent's `AF_VSOCK` listener — registers the `Virtio Vsock STREAM` Winsock provider (Address Family 40, `viosocklib.dll`). `virtio-win-guest-tools.exe /S` (Order 21) does not install this driver. |
| 53 | **NIC auto-heal task** | Write `C:\CocoonNicAutoHeal.ps1` and register `CocoonNicAutoHeal` schtasks (every minute, SYSTEM, HIGHEST). Cycles all Net PnP devices to recover chained-clone NDIS state. |
| 54 | **QuickEdit restore** | Restore QuickEdit after install |
| 55 | **Install marker** | `cmd /c "echo %date% %time% > C:\install.success"` |

> **Note on WinRM persistence**: `Enable-PSRemoting` + the `AllowUnencrypted`/`Basic` WSMan settings set by orders 14-16 do not always survive the very first post-install reboot on Win11 25H2. `remediate.ps1` re-applies them from the same deterministic settings, and the CI loop reboots → verifies → remediates → re-verifies to make the final image idempotent.

Expand Down
20 changes: 18 additions & 2 deletions autounattend.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,25 @@
<!-- VM performance: disable scheduled tasks that waste CPU -->
<SynchronousCommand wcm:action="add"><Order>51</Order><CommandLine>powershell -Command "Disable-ScheduledTask -TaskName '\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser' -EA SilentlyContinue; Disable-ScheduledTask -TaskName '\Microsoft\Windows\Defrag\ScheduledDefrag' -EA SilentlyContinue; Disable-ScheduledTask -TaskName '\Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticDataCollector' -EA SilentlyContinue"</CommandLine></SynchronousCommand>

<!-- viosock driver (virtio-vsock) install. virtio-win-guest-tools.exe /S
does not register the viosock WSP, so cocoon-agent's AF_VSOCK
listener can't bind. Install directly from the virtio-win ISO.
Both attestation (D:\viosock\w11\amd64) and standard layout, on
D: and E:, mirroring the windowsPE DriverPaths. Verified post-
install: "Virtio Vsock STREAM" Provider Path %SystemRoot%\System32
\viosocklib.dll, Address Family 40 in `netsh winsock show catalog`. -->
<SynchronousCommand wcm:action="add"><Order>52</Order><CommandLine>cmd /c "if exist D:\viosock\w11\amd64\viosock.inf (pnputil /add-driver D:\viosock\w11\amd64\viosock.inf /install) else if exist E:\viosock\w11\amd64\viosock.inf (pnputil /add-driver E:\viosock\w11\amd64\viosock.inf /install) else if exist D:\Win11\amd64\viosock\viosock.inf (pnputil /add-driver D:\Win11\amd64\viosock\viosock.inf /install) else if exist E:\Win11\amd64\viosock\viosock.inf (pnputil /add-driver E:\Win11\amd64\viosock\viosock.inf /install)"</CommandLine></SynchronousCommand>

<!-- NIC auto-heal: scheduled task that cycles every Net PnP device once a minute.
Recovers chained-clone Win11 guests where vm.restore leaves the NIC bound at
the OS layer but unable to transmit (Status reports 'OK' so a Status='Error'
filter would miss it). Base64-encoded UTF-16LE PowerShell that writes
C:\CocoonNicAutoHeal.ps1 and registers CocoonNicAutoHeal via schtasks. -->
<SynchronousCommand wcm:action="add"><Order>53</Order><CommandLine>powershell.exe -NoProfile -EncodedCommand JABjAG8AbgB0AGUAbgB0ACAAPQAgAEAAJwAKACQARQByAHIAbwByAEEAYwB0AGkAbwBuAFAAcgBlAGYAZQByAGUAbgBjAGUAIAA9ACAAIgBTAGkAbABlAG4AdABsAHkAQwBvAG4AdABpAG4AdQBlACIACgBmAG8AcgBlAGEAYwBoACAAKAAkAGQAIABpAG4AIAAoAEcAZQB0AC0AUABuAHAARABlAHYAaQBjAGUAIAAtAEMAbABhAHMAcwAgAE4AZQB0ACkAKQAgAHsACgAgACAAIAAgAEQAaQBzAGEAYgBsAGUALQBQAG4AcABEAGUAdgBpAGMAZQAgAC0ASQBuAHMAdABhAG4AYwBlAEkAZAAgACQAZAAuAEkAbgBzAHQAYQBuAGMAZQBJAGQAIAAtAEMAbwBuAGYAaQByAG0AOgAkAGYAYQBsAHMAZQAKACAAIAAgACAAUwB0AGEAcgB0AC0AUwBsAGUAZQBwACAALQBTAGUAYwBvAG4AZABzACAAMgAKACAAIAAgACAARQBuAGEAYgBsAGUALQBQAG4AcABEAGUAdgBpAGMAZQAgAC0ASQBuAHMAdABhAG4AYwBlAEkAZAAgACQAZAAuAEkAbgBzAHQAYQBuAGMAZQBJAGQAIAAtAEMAbwBuAGYAaQByAG0AOgAkAGYAYQBsAHMAZQAKAH0ACgAnAEAACgBTAGUAdAAtAEMAbwBuAHQAZQBuAHQAIAAtAFAAYQB0AGgAIABDADoAXABDAG8AYwBvAG8AbgBOAGkAYwBBAHUAdABvAEgAZQBhAGwALgBwAHMAMQAgAC0AVgBhAGwAdQBlACAAJABjAG8AbgB0AGUAbgB0ACAALQBFAG4AYwBvAGQAaQBuAGcAIABBAFMAQwBJAEkAIAAtAEYAbwByAGMAZQAKAHMAYwBoAHQAYQBzAGsAcwAgAC8AYwByAGUAYQB0AGUAIAAvAHQAbgAgAEMAbwBjAG8AbwBuAE4AaQBjAEEAdQB0AG8ASABlAGEAbAAgAC8AdAByACAAIgBwAG8AdwBlAHIAcwBoAGUAbABsAC4AZQB4AGUAIAAtAE4AbwBQAHIAbwBmAGkAbABlACAALQBFAHgAZQBjAHUAdABpAG8AbgBQAG8AbABpAGMAeQAgAEIAeQBwAGEAcwBzACAALQBGAGkAbABlACAAQwA6AFwAQwBvAGMAbwBvAG4ATgBpAGMAQQB1AHQAbwBIAGUAYQBsAC4AcABzADEAIgAgAC8AcwBjACAAbQBpAG4AdQB0AGUAIAAvAG0AbwAgADEAIAAvAHIAdQAgAFMAWQBTAFQARQBNACAALwByAGwAIABIAEkARwBIAEUAUwBUACAALwBmAAoA</CommandLine></SynchronousCommand>

<!-- Restore QuickEdit and mark completion -->
<SynchronousCommand wcm:action="add"><Order>52</Order><CommandLine>reg add "HKCU\Console" /v QuickEdit /t REG_DWORD /d 1 /f</CommandLine></SynchronousCommand>
<SynchronousCommand wcm:action="add"><Order>53</Order><CommandLine>cmd /c "echo %date% %time% > C:\install.success"</CommandLine></SynchronousCommand>
<SynchronousCommand wcm:action="add"><Order>54</Order><CommandLine>reg add "HKCU\Console" /v QuickEdit /t REG_DWORD /d 1 /f</CommandLine></SynchronousCommand>
<SynchronousCommand wcm:action="add"><Order>55</Order><CommandLine>cmd /c "echo %date% %time% > C:\install.success"</CommandLine></SynchronousCommand>
</FirstLogonCommands>
</component>
</settings>
Expand Down
12 changes: 12 additions & 0 deletions scripts/cocoon-nic-autoheal.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# cocoon-nic-autoheal.ps1 — cycle every Net-class PnP device once.
#
# Triggered by the CocoonNicAutoHeal scheduled task (registered at firstboot)
# on a 1-minute repeat. Recovers chained-clone Win11 guests where vm.restore
# leaves the NIC bound at the OS layer but unable to transmit — Status reports
# 'OK' so a "Status -EQ Error" filter would miss it. Cycle unconditionally.
$ErrorActionPreference = "SilentlyContinue"
foreach ($d in (Get-PnpDevice -Class Net)) {
Disable-PnpDevice -InstanceId $d.InstanceId -Confirm:$false
Start-Sleep -Seconds 2
Enable-PnpDevice -InstanceId $d.InstanceId -Confirm:$false
}
29 changes: 29 additions & 0 deletions scripts/remediate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,33 @@ Disable-ScheduledTask -TaskName '\Microsoft\Windows\Application Experience\Micro
Disable-ScheduledTask -TaskName '\Microsoft\Windows\Defrag\ScheduledDefrag' -ErrorAction SilentlyContinue
Disable-ScheduledTask -TaskName '\Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticDataCollector' -ErrorAction SilentlyContinue

# --- viosock driver ---
$vsockCat = (netsh winsock show catalog 2>&1 | Out-String)
if ($vsockCat -notmatch 'Virtio Vsock STREAM') {
Write-Output "Installing viosock driver..."
foreach ($p in 'D:\viosock\w11\amd64\viosock.inf',
'E:\viosock\w11\amd64\viosock.inf',
'D:\Win11\amd64\viosock\viosock.inf',
'E:\Win11\amd64\viosock\viosock.inf') {
if (Test-Path $p) { pnputil /add-driver $p /install | Out-Null; break }
}
}

# --- NIC auto-heal task ---
$autoheal = schtasks /query /tn CocoonNicAutoHeal 2>&1 | Out-String
if ($LASTEXITCODE -ne 0) {
Write-Output "Re-creating CocoonNicAutoHeal task..."
@'
$ErrorActionPreference = "SilentlyContinue"
foreach ($d in (Get-PnpDevice -Class Net)) {
Disable-PnpDevice -InstanceId $d.InstanceId -Confirm:$false
Start-Sleep -Seconds 2
Enable-PnpDevice -InstanceId $d.InstanceId -Confirm:$false
}
'@ | Out-File -Encoding ASCII -FilePath 'C:\CocoonNicAutoHeal.ps1' -Force
schtasks /create /tn CocoonNicAutoHeal `
/tr 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\CocoonNicAutoHeal.ps1' `
/sc minute /mo 1 /ru SYSTEM /rl HIGHEST /f | Out-Null
}

Write-Output "=== Remediation complete ==="
16 changes: 16 additions & 0 deletions scripts/verify.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,22 @@ $vgt = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninsta
Where-Object { $_.DisplayName -match 'Virtio-win' }
Check "virtio-win guest tools installed" ($null -ne $vgt)

# --- viosock (virtio-vsock) driver: required for cocoon-agent's AF_VSOCK ---
# virtio-win-guest-tools.exe /S installs viostor / NetKvm / balloon but skips
# viosock; autounattend Order 52 runs pnputil for it. Two checks: hardware bind
# (Get-PnpDevice) plus Winsock provider registration (catalog must list AF=40).
$vsockDev = Get-PnpDevice -PresentOnly -ErrorAction SilentlyContinue |
Where-Object { $_.InstanceId -like '*VEN_1AF4*DEV_1053*' }
Check "viosock device bound (Status=OK)" ($null -ne $vsockDev -and $vsockDev.Status -eq 'OK')

$vsockCat = (netsh winsock show catalog 2>&1 | Out-String)
Check "Virtio Vsock STREAM provider registered" ($vsockCat -match 'Virtio Vsock STREAM')

# --- NIC auto-heal scheduled task ---
$autoheal = schtasks /query /tn CocoonNicAutoHeal /fo LIST 2>&1 | Out-String
Check "CocoonNicAutoHeal task registered" ($LASTEXITCODE -eq 0 -and $autoheal -match 'CocoonNicAutoHeal')
Check "C:\CocoonNicAutoHeal.ps1 present" (Test-Path 'C:\CocoonNicAutoHeal.ps1')

# --- Install marker ---
Check "C:\install.success exists" (Test-Path C:\install.success)

Expand Down