Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
51 changes: 45 additions & 6 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -464,12 +464,51 @@ try {
# pass. Only cosign actually completing can bring it back to 0. That is
# the whole guarantee behind RFC-0001 R8, and it was one line away.
$global:LASTEXITCODE = 255
& $cosign verify-blob `
--certificate-identity-regexp "https://github.com/$GitHubRepo/.github/workflows/release.yml@refs/tags/v.*" `
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' `
--certificate (Join-Path $tmpDir "$binaryFile.cert") `
--signature (Join-Path $tmpDir "$binaryFile.sig") `
(Join-Path $tmpDir $binaryFile) 2>$null
# AND THE STDERR WINDOW, WITHOUT WHICH SUCCESS ITSELF IS FATAL.
#
# cosign writes "Verified OK" to STDERR on the SUCCESS path. Windows
# PowerShell 5.1 turns any native-command stderr into a
# NativeCommandError record, and this script runs under
# `$ErrorActionPreference = 'Stop'` (line 27) -- so the record is
# TERMINATING and the installer dies at the moment verification
# passes. `2>$null` does not save it: 5.1 raises the record before
# the redirection applies. Measured on a real Windows 11 box against
# the published v0.10.17 installer:
#
# Verifying cosign signature...
# cosign.exe : Verified OK
# + & $cosign verify-blob `
# + FullyQualifiedErrorId : NativeCommandError
#
# ...and nothing was installed. So `tracebloc client` cannot be
# installed on Windows at all, and tracebloc/client's installer
# Step 4 fails with it, which drops Step 5 to manual sign-in and
# Step 6 to the hand-typed credential prompt.
#
# INVISIBLE ON POWERSHELL 7, which is why it survived: pwsh 7 does
# not make error records out of native stderr, so it passes there
# and fails on the Windows default.
#
# THIS FILE ALREADY HAD THE FIX, 230 LINES UP. `Test-CosignRuns`
# opens exactly this window for `cosign version` and says why. The
# idiom was simply never applied to the call that matters.
#
# NOT piped to Out-Null: `$LASTEXITCODE` is the entire verdict here
# and piping a native command through a cmdlet is a documented way
# to lose it. The window makes the record non-terminating; `2>$null`
# still discards the text.
$prevEap = $ErrorActionPreference
try {
$ErrorActionPreference = 'Continue'
& $cosign verify-blob `
--certificate-identity-regexp "https://github.com/$GitHubRepo/.github/workflows/release.yml@refs/tags/v.*" `
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' `
--certificate (Join-Path $tmpDir "$binaryFile.cert") `
--signature (Join-Path $tmpDir "$binaryFile.sig") `
(Join-Path $tmpDir $binaryFile) 2>$null
} finally {
$ErrorActionPreference = $prevEap
}
if ($LASTEXITCODE -ne 0) {
# No TRACEBLOC_ALLOW_UNVERIFIED branch here, deliberately.
# Verification RAN and said no.
Expand Down
27 changes: 27 additions & 0 deletions scripts/tests/install-ps1-verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,33 @@ else
bad 'a post-cosign artifact fetch is missing its size cap'
fi


# ── 5d. every native call sits in a stderr window (cli, Windows PowerShell 5.1)
# THE SUCCESS PATH WAS FATAL. cosign writes "Verified OK" to STDERR when a
# signature VERIFIES. Windows PowerShell 5.1 turns native-command stderr into a
# NativeCommandError record, and this installer runs under
# `$ErrorActionPreference = 'Stop'`, so that record TERMINATES the run at the
# moment verification succeeds. `2>$null` does not prevent it -- 5.1 raises the
# record before the redirection applies. Measured on a real Windows 11 box
# against the published v0.10.17 installer: "cosign.exe : Verified OK" followed
# by NativeCommandError, and nothing installed.
#
# Invisible on PowerShell 7, which does not make error records out of native
# stderr -- so it passes wherever it is tested and fails on the Windows default.
#
# THE INVARIANT, and it catches the next native call someone adds: every `& $...`
# invocation must sit inside an `$ErrorActionPreference = 'Continue'` window.
# There are exactly two (cosign version, cosign verify-blob) and there must be at
# least as many windows as calls.
native_calls=$(grep -cE '^[[:space:]]*&[[:space:]]*\$' "$INSTALLER" || true)
eap_windows=$(grep -cF "ErrorActionPreference = 'Continue'" "$INSTALLER" || true)
if [ "$native_calls" -eq 0 ]; then
bad 'no native invocation found at all -- this guard would pass vacuously'
elif [ "$eap_windows" -ge "$native_calls" ]; then
ok "every native invocation ($native_calls) sits in a stderr window ($eap_windows)"
else
bad "a native invocation runs outside an ErrorActionPreference window ($native_calls calls, $eap_windows windows) -- cosign's 'Verified OK' on stderr will terminate the install under Windows PowerShell 5.1"
fi
# ── 6. behavioural tier ─────────────────────────────────────────────────────
# pwsh is preinstalled on GitHub-hosted ubuntu runners. If it is missing we
# cannot tell whether the helpers behave, and "cannot tell" is a finding, not a
Expand Down
Loading