diff --git a/install.ps1 b/install.ps1 index d63f1001d..3b087321b 100644 --- a/install.ps1 +++ b/install.ps1 @@ -7,8 +7,22 @@ $ErrorActionPreference = "Stop" -# Enforce TLS 1.2+ (older PowerShell defaults to TLS 1.0 which GitHub rejects) -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 +# Enforce TLS 1.2+ (older PowerShell defaults to TLS 1.0 which GitHub rejects). +# +# TLS 1.3 is added ONLY where schannel can actually negotiate it: Windows 11 and +# Server 2022 (build 20348+). On Windows 10 the enum value still exists from +# .NET Framework 4.8 onward, so the assignment succeeds and nothing warns -- but +# the handshake then fails outright with "The request was aborted: Could not +# create SSL/TLS secure channel". An unsupported protocol flag in this bitmask +# is a hard failure, not a graceful downgrade, so every Windows 10 user was +# blocked at the first download (#1856). The enum-name probe additionally keeps +# the script parsing on .NET Framework 4.7, where Tls13 is not defined at all. +$CbmProtocols = [Net.SecurityProtocolType]::Tls12 +if ([Environment]::OSVersion.Version.Build -ge 20348 -and + ([enum]::GetNames([Net.SecurityProtocolType]) -contains 'Tls13')) { + $CbmProtocols = $CbmProtocols -bor [Net.SecurityProtocolType]::Tls13 +} +[Net.ServicePointManager]::SecurityProtocol = $CbmProtocols Add-Type -AssemblyName System.Net.Http $Repo = "DeusData/codebase-memory-mcp" diff --git a/tests/test_windows_bundle_contract.sh b/tests/test_windows_bundle_contract.sh index a40ac3083..4c4c681cd 100644 --- a/tests/test_windows_bundle_contract.sh +++ b/tests/test_windows_bundle_contract.sh @@ -242,6 +242,38 @@ require( "install.ps1 version probes must relax EAP with restore and pre-seed LASTEXITCODE (#1255)", ) +# ── 3c. The TLS bitmask must not name a protocol schannel cannot negotiate ─── +# Windows 10's schannel has no TLS 1.3 (it arrives with Windows 11 / Server +# 2022, build 20348). .NET Framework 4.8 still DEFINES SecurityProtocolType +# .Tls13, so setting the bit succeeds silently and nothing warns -- then the +# first HTTPS request dies with "Could not create SSL/TLS secure channel", +# because an unsupported flag in this bitmask is a hard failure rather than a +# downgrade. That blocked the installer on every Windows 10 machine before it +# downloaded a single byte (#1856). Pin both halves of the guard: the build +# gate, and the enum-name probe that keeps the script parsing on 4.7, where +# Tls13 does not exist. +require( + "[Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13" not in installer, + "install.ps1 must not set the TLS 1.3 bit unconditionally -- it hard-fails " + "the handshake on Windows 10, whose schannel cannot negotiate it (#1856)", +) +require( + re.search(r"\[Environment\]::OSVersion\.Version\.Build\s+-ge\s+20348", installer) is not None, + "install.ps1 must gate TLS 1.3 on build 20348+ (Windows 11 / Server 2022) (#1856)", +) +require( + re.search( + r"\[enum\]::GetNames\(\[Net\.SecurityProtocolType\]\)\s+-contains\s+'Tls13'", installer + ) + is not None, + "install.ps1 must probe the enum before naming Tls13, so it still parses on " + ".NET Framework 4.7 where the member is undefined (#1856)", +) +require( + "[Net.ServicePointManager]::SecurityProtocol = $CbmProtocols" in installer, + "install.ps1 must assign the computed protocol set, not a literal bitmask (#1856)", +) + # ── 4. Package-manager shims resolve the single Windows binary ─────────────── single_binary_contracts = { "pkg/npm/install.js": (