Skip to content

Commit a412cef

Browse files
anandgupta42claude
andauthored
fix: [#958] make Windows installer Pester env injection deterministic (#959)
The `Windows Installer (Pester)` CI job began failing on the v0.8.9 release commit although `install.ps1` and its tests were unchanged (the commit only touched `CHANGELOG.md` and renamed a test). The same code passed on the two prior pushes (#930, #946); the `windows-latest` runner image changed in between, and a re-run reproduced the failure deterministically. `Invoke-Installer` set `PROCESSOR_*` vars via `[Environment]::SetEnvironmentVariable` (Process scope) on the Pester host and spawned `& pwsh -File`, relying on inheritance. `PROCESSOR_ARCHITECTURE` is a loader-managed variable; the updated runner re-initializes it for spawned processes, so the override no longer reached the child (it arrived blank -> `Unsupported OS/Arch: windows/`). Custom vars like `PROCESSOR_ARCHITEW6432` are unaffected, which is why the WOW64 test kept passing. Apply the requested env vars inside the child's own session via a `pwsh -Command` preamble (after the loader runs), removing vars whose value is empty, and pass the script args as bareword command-line tokens so parameter names bind as names (matching the original `-File @ScriptArgs` semantics). Verified green on windows-latest: 9/9 Pester tests pass. This is a test-harness fix only - the shipped `install.ps1` and v0.8.9 binaries are correct; real users always have a populated `PROCESSOR_ARCHITECTURE`. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8fea433 commit a412cef

1 file changed

Lines changed: 29 additions & 10 deletions

File tree

test/windows/install.Tests.ps1

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,43 @@ BeforeAll {
1515
# Invoke install.ps1 in a child pwsh with a controlled environment and return
1616
# @{ Code = <exit code>; Output = <combined stdout+stderr> }. PROCESSOR_* env
1717
# vars are passed per-call so we can simulate WOW64 / ARM64 hosts.
18+
#
19+
# The requested env vars are applied INSIDE the child session (via a -Command
20+
# preamble), not by mutating this host's Process-scope environment and relying
21+
# on inheritance. PROCESSOR_ARCHITECTURE is a loader-managed variable: the
22+
# windows-latest runner re-initializes it for a spawned process, so a
23+
# Process-scope override here does not reliably reach `pwsh -File` (the child
24+
# saw it blank). Setting it in the child's own session, after the loader has
25+
# run, is deterministic. An empty value removes the var so detection of a
26+
# "missing" PROCESSOR_ARCHITEW6432 falls through correctly.
1827
function Invoke-Installer {
1928
param(
2029
[string[]]$ScriptArgs = @(),
2130
[hashtable]$Env = @{}
2231
)
23-
$saved = @{}
32+
# Single-quote PowerShell literals by doubling embedded single quotes.
33+
$sq = "'"; $escSq = "''"
34+
$preamble = ""
2435
foreach ($k in $Env.Keys) {
25-
$saved[$k] = [Environment]::GetEnvironmentVariable($k)
26-
[Environment]::SetEnvironmentVariable($k, $Env[$k])
27-
}
28-
try {
29-
$output = & pwsh -NoProfile -File $script:InstallScript @ScriptArgs 2>&1 | Out-String
30-
return @{ Code = $LASTEXITCODE; Output = $output }
31-
} finally {
32-
foreach ($k in $Env.Keys) {
33-
[Environment]::SetEnvironmentVariable($k, $saved[$k])
36+
$v = $Env[$k]
37+
if ([string]::IsNullOrEmpty($v)) {
38+
$preamble += "Remove-Item -Path Env:$k -ErrorAction SilentlyContinue; "
39+
} else {
40+
$vEsc = $v.Replace($sq, $escSq)
41+
$preamble += "`$env:$k = '$vEsc'; "
3442
}
3543
}
44+
# Pass the script args as bareword command-line tokens (e.g. `-Version
45+
# 0.0.0-nonexistent`) so parameter NAMES bind as names - matching the
46+
# original `pwsh -File <script> @ScriptArgs` semantics. Quoting them as
47+
# literals (or array-splatting) binds positionally instead, so $Version
48+
# would receive the literal string "-Version". The harness only ever passes
49+
# shell-safe tokens (-Help, -Version, version strings; no spaces/quotes).
50+
$argTokens = $ScriptArgs -join " "
51+
$scriptEsc = $script:InstallScript.Replace($sq, $escSq)
52+
$command = "$preamble & '$scriptEsc' $argTokens"
53+
$output = & pwsh -NoProfile -Command $command 2>&1 | Out-String
54+
return @{ Code = $LASTEXITCODE; Output = $output }
3655
}
3756
}
3857

0 commit comments

Comments
 (0)