unsloth/.github/scripts/virgin-windows-probe.ps1
danielhanchen f09a1e71a9 Tighten the clean-machine CI comments
Comments only, no assertion logic, pins or leg definitions touched.

Reflowed every rationale block to denser wording and removed the
duplication that had built up across repeated steps: the desktop
workflow repeated the fork-PR skip, the desktop-v* tag resolution and
the restore-runner note once per platform, and the installer workflow
repeated its path-filter rationale in both the pull_request and push
blocks. Those now point at the first copy.

Every WHY is kept: why the masked legs avoid install.sh --local, what
UNSLOTH_CI_SOURCE_OVERLAY is for, why `absent` tests "must not work"
rather than command -v, why the .venv_t5_* sidecars are in the macho
scan scope, why the signature check is main-executables-only, why each
nobuild allowlist entry is a pure-Python sdist, why the WSL job gates
and what the pipe truncation was, and why the virgin container's
overlay=false row is still pinned.

Proved comments-only three ways: both workflow revisions parsed with
yaml.safe_load_all and every leaf walked (only `run:` scalars differ);
every changed bash body and .sh compared byte-for-byte after
`bash --pretty-print -n`; every changed pwsh body and .ps1 compared as
a token stream with Comment and NewLine tokens dropped. A negative
control injecting one non-comment line into each layer makes all of
them fail.
2026-07-29 06:33:16 +00:00

178 lines
9.2 KiB
PowerShell

# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved.
# Runs INSIDE a Windows container, proving the environment is genuinely virgin BEFORE
# anything is installed into it. This is the entire point of the container lane: the
# hosted-runner Windows legs of clean-machine-install-ci.yml only simulate absence
# (rename the toolcache Python dir, scrub the Machine and User registry PATH), while
# this asserts real absence on an image that never had a toolchain. Without it the lane
# proves nothing the masked legs did not already prove.
$ErrorActionPreference = 'Continue'
$failures = @()
function Section($t) { Write-Host ""; Write-Host "=== $t ===" }
# ── The interpreter itself ────────────────────────────────────────────────────
# install.ps1 must run under Windows PowerShell 5.1, which is what a real Windows
# box ships. pwsh 7 is a runner-image extra no user is promised. nanoserver has
# NEITHER, which is why this lane is on servercore.
Section 'interpreter'
Write-Host "PSVersion : $($PSVersionTable.PSVersion)"
Write-Host "PSEdition : $($PSVersionTable.PSEdition)"
Write-Host "CLRVersion : $($PSVersionTable.CLRVersion)"
Write-Host "Host : $($Host.Name)"
if ($PSVersionTable.PSEdition -ne 'Desktop') {
$failures += "PSEdition is '$($PSVersionTable.PSEdition)', not Desktop -- this is not Windows PowerShell 5.1"
}
if ($PSVersionTable.PSVersion.Major -ne 5) {
$failures += "PSVersion is $($PSVersionTable.PSVersion), not 5.x"
}
Section 'operating system'
cmd /c ver
$cv = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue
if ($cv) {
Write-Host "ProductName : $($cv.ProductName)"
Write-Host "EditionID : $($cv.EditionID)"
Write-Host "InstallationType: $($cv.InstallationType)"
Write-Host "CurrentBuild : $($cv.CurrentBuild).$($cv.UBR)"
}
Write-Host "USERNAME : $env:USERNAME"
Write-Host "USERPROFILE : $env:USERPROFILE"
Write-Host "LOCALAPPDATA : $env:LOCALAPPDATA"
Write-Host "PROCESSOR_ARCH : $env:PROCESSOR_ARCHITECTURE"
# install.ps1:254/258 does Join-Path $env:USERPROFILE ".unsloth\studio" with no null
# guard, so an unset USERPROFILE aborts under ErrorActionPreference=Stop. The lane sets
# UNSLOTH_STUDIO_HOME, but record whether a bare container would have survived without.
if ([string]::IsNullOrWhiteSpace($env:USERPROFILE)) {
Write-Host "::warning::USERPROFILE is unset in this container; install.ps1's default install root would abort"
}
# ── The assertion the whole lane exists for ───────────────────────────────────
Section 'virginity: developer toolchain must be ABSENT'
# python/py/git/cmake/cl/winget are the six the task names. uv is added because
# install.ps1 would happily reuse a preinstalled one and skip its own bootstrap.
$mustBeAbsent = @('python', 'python3', 'py', 'git', 'cmake', 'cl', 'winget', 'uv')
foreach ($t in $mustBeAbsent) {
$c = Get-Command $t -ErrorAction SilentlyContinue
$where = if ($c) { $c.Source } else { 'ABSENT' }
Write-Host (" {0,-10} {1}" -f $t, $where)
if ($c) { $failures += "$t is present at $($c.Source) -- this container is NOT virgin" }
}
Section 'informational: present but not a developer toolchain'
# OS components, not a toolchain. curl.exe and tar.exe ship in System32 on Server 2022
# and are the only transport into a container with no git; naming them keeps the
# premise honest rather than silently relying on them.
foreach ($t in 'cmd', 'powershell', 'curl', 'tar', 'certutil', 'msiexec', 'reg', 'where', 'pwsh', 'node', 'npm', 'msbuild', 'dotnet', 'gcc') {
$c = Get-Command $t -ErrorAction SilentlyContinue
Write-Host (" {0,-10} {1}" -f $t, $(if ($c) { $c.Source } else { 'ABSENT' }))
}
Section 'virginity: no toolchain on disk either'
# A binary can be off PATH and still be found by uv's interpreter discovery or py.exe's
# registry view -- exactly how the hosted Windows leg once reported `python ABSENT` and
# then installed with the runner's 3.13.14. So check disk and registry too.
$badPaths = @(
'C:\Python27', 'C:\Python3*', 'C:\Program Files\Python*', 'C:\Program Files (x86)\Python*',
'C:\Program Files\Git', 'C:\Program Files\CMake', 'C:\Program Files\Microsoft Visual Studio',
'C:\Program Files (x86)\Microsoft Visual Studio', 'C:\hostedtoolcache', 'C:\ProgramData\chocolatey'
)
foreach ($p in $badPaths) {
# Wildcards can match several dirs; take the first so the message names a real
# path instead of stringifying an array.
$hit = @(Get-Item -Path $p -ErrorAction SilentlyContinue) | Select-Object -First 1
if ($hit) {
Write-Host " PRESENT $($hit.FullName)"
$failures += "toolchain directory exists on disk: $($hit.FullName)"
} else {
Write-Host " absent $p"
}
}
$pyReg = @('HKLM:\SOFTWARE\Python', 'HKCU:\SOFTWARE\Python')
foreach ($k in $pyReg) {
if (Test-Path $k) {
Write-Host " PRESENT $k"
$failures += "a registered Python install exists at $k"
} else {
Write-Host " absent $k"
}
}
Section 'PATH as the container sees it'
Write-Host "Process PATH:"
($env:PATH -split ';') | Where-Object { $_ } | ForEach-Object { Write-Host " $_" }
foreach ($scope in 'Machine', 'User') {
Write-Host "$scope PATH: $([System.Environment]::GetEnvironmentVariable('Path', $scope))"
}
# ── The VC++ runtime question the hosted leg cannot answer ────────────────────
Section 'VC++ runtime (honest measurement)'
# The hosted image ships the VC++ 2015-2022 runtime in System32 and cannot lose it
# without breaking the runner (see the HONESTY NOTE in clean-machine-install-ci.yml),
# so `import torch` succeeding there does NOT prove a no-winget machine has the
# runtime. This container is the only environment in CI that can answer it, so their
# absence is asserted, not merely recorded: if a future base image starts shipping
# them the lane silently degrades into another masked leg.
foreach ($dll in 'vcruntime140.dll', 'vcruntime140_1.dll', 'msvcp140.dll') {
$p = Join-Path $env:WINDIR "System32\$dll"
$present = Test-Path $p
Write-Host (" {0,-20} {1}" -f $dll, $(if ($present) { 'PRESENT' } else { 'ABSENT' }))
if ($present) { $failures += "System32\$dll is present -- this image already ships the VC++ runtime, which is the one thing the hosted runner cannot un-ship" }
}
foreach ($k in 'HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64') {
$r = Get-ItemProperty $k -ErrorAction SilentlyContinue
Write-Host (" {0} -> {1}" -f $k, $(if ($r) { "Installed=$($r.Installed) $($r.Major).$($r.Minor)" } else { 'absent' }))
}
# ── Can the installer's transport work at all here? ───────────────────────────
Section 'outbound HTTPS and TLS'
# install.ps1 never sets [Net.ServicePointManager]::SecurityProtocol, so it inherits the
# .NET Framework default. Test the DEFAULT first: if that fails and Tls12 works, the
# installer has a real portability bug on hardened images, not a container quirk.
Write-Host "default SecurityProtocol: $([Net.ServicePointManager]::SecurityProtocol)"
$probeUrls = @(
'https://www.python.org/ftp/python/',
'https://astral.sh/uv/install.ps1',
'https://pypi.org/simple/',
'https://aka.ms/vs/17/release/vc_redist.x64.exe'
)
$defaultOk = @{}
foreach ($u in $probeUrls) {
try {
$null = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 60 -Method Head -ErrorAction Stop
Write-Host " OK (default TLS) $u"; $defaultOk[$u] = $true
} catch {
Write-Host " FAIL (default TLS) $u -- $($_.Exception.Message)"; $defaultOk[$u] = $false
}
}
if ($defaultOk.Values -contains $false) {
Write-Host "retrying the failures with an explicit Tls12..."
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
foreach ($u in $probeUrls) {
if ($defaultOk[$u]) { continue }
try {
$null = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 60 -Method Head -ErrorAction Stop
Write-Host " OK (Tls12) $u"
Write-Host "::warning::$u needs an explicit Tls12; install.ps1 never sets SecurityProtocol, so this is a real installer portability gap"
} catch {
Write-Host " FAIL (Tls12) $u -- $($_.Exception.Message)"
$failures += "no outbound HTTPS to $u even with Tls12 -- the container cannot reach the installer's download hosts"
}
}
}
# ── Verdict ───────────────────────────────────────────────────────────────────
Section 'verdict'
if ($failures.Count -gt 0) {
foreach ($f in $failures) { Write-Host "::error::$f" }
Write-Host "VIRGINITY ASSERTION FAILED ($($failures.Count) problem(s))"
exit 1
}
Write-Host "VIRGINITY ASSERTION PASSED"
Write-Host "no python, py, git, cmake, cl, winget or uv on PATH, on disk, or in the registry"
exit 0