From 7b65e9a7b11df1dfe0584b0741377573262cebdb Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sun, 19 Jul 2026 19:36:15 +0100 Subject: [PATCH] Keep Windows installer compatible with TLS 1.2 runtimes Contract-Neutral: Legacy Windows PowerShell TLS enum compatibility preserves the existing installer transport contract without changing its public interface --- scripts/install.ps1 | 11 +++++++-- scripts/installtests/install_ps1_test.go | 30 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/scripts/install.ps1 b/scripts/install.ps1 index dc5a4e11df..3b46f565f3 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -762,8 +762,15 @@ $serverChecksum = $null $serverSshSignature = $null try { - # Configure TLS 1.2 minimum - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 + # Configure TLS 1.2 minimum. The Tls13 enum member only exists on + # .NET Framework 4.8+ / .NET Core; referencing it directly crashes + # Windows PowerShell 5.1 on older frameworks, so add it opportunistically. + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + try { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 + } catch { + # TLS 1.3 unavailable on this framework; TLS 1.2 remains enforced. + } $downloadPreflightResponse = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action { Invoke-WebRequest -Uri $DownloadUrl -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop diff --git a/scripts/installtests/install_ps1_test.go b/scripts/installtests/install_ps1_test.go index e89e5dc2e9..45051eaee4 100644 --- a/scripts/installtests/install_ps1_test.go +++ b/scripts/installtests/install_ps1_test.go @@ -27,6 +27,36 @@ func TestInstallPS1ParsesWithPowerShell(t *testing.T) { } } +func TestInstallPS1KeepsTLS13OptionalOnLegacyWindowsPowerShell(t *testing.T) { + content, err := os.ReadFile(repoFile("scripts", "install.ps1")) + if err != nil { + t.Fatalf("read install.ps1: %v", err) + } + + script := string(content) + tls12Fallback := `[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12` + optionalTLS13 := `[Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13` + tls12Index := strings.Index(script, tls12Fallback) + tls13Index := strings.Index(script, optionalTLS13) + if tls12Index == -1 { + t.Fatal("install.ps1 must establish TLS 1.2 before probing optional TLS 1.3 support") + } + if tls13Index == -1 { + t.Fatal("install.ps1 must enable TLS 1.3 when the runtime exposes it") + } + if tls12Index >= tls13Index { + t.Fatal("install.ps1 must establish the TLS 1.2 fallback before referencing the optional TLS 1.3 enum") + } + + compatibilityBlock := script[tls12Index:tls13Index] + if !strings.Contains(compatibilityBlock, "try {") { + t.Fatal("install.ps1 must guard the optional TLS 1.3 enum behind a compatibility try block") + } + if !strings.Contains(script[tls13Index:], "} catch {") { + t.Fatal("install.ps1 must retain TLS 1.2 when the optional TLS 1.3 enum is unavailable") + } +} + func TestWindowsAgentLifecycleHarnessParsesWithPowerShell(t *testing.T) { pwsh, err := exec.LookPath("pwsh") if err != nil {