From cb7d691bc9ebbd4a2477c5f4ffea7779dafe495e Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 14 May 2026 13:01:11 +0200 Subject: [PATCH 1/5] Error on binding redirects pointing to missing DLLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change verify-binding-redirects.ps1 to fail when a binding redirect references a DLL that isn't in the package layout. Previously this was silently skipped, which allowed #15765 — a redirect for DiagnosticSource 8.0.0.1 shipped in the config but the DLL was excluded from the package. The whole-package-missing case (VMR) is still a skip. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/verify-binding-redirects.ps1 | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/eng/verify-binding-redirects.ps1 b/eng/verify-binding-redirects.ps1 index 446769835c..9b18aa3df2 100644 --- a/eng/verify-binding-redirects.ps1 +++ b/eng/verify-binding-redirects.ps1 @@ -9,6 +9,16 @@ $script:isCI = $env:TF_BUILD -eq 'true' -or $env:CI -eq 'true' # In CI: validates and fails with instructions to run locally. # Locally: auto-fixes the source app.config files with the correct versions. +# Assemblies that have binding redirects but are intentionally NOT shipped in the +# CLI/SDK package. These are loaded from Visual Studio at runtime when testhost +# runs inside VS. A redirect without a DLL is safe here because the DLL comes +# from VS's probing path, not from the package layout. +$script:AllowMissingDlls = @( + "Microsoft.VisualStudio.TestWindow.Interfaces" + "Microsoft.VisualStudio.QualityTools.UnitTestFramework" + "Microsoft.Extensions.FileSystemGlobbing" +) + # Each source app.config maps to a specific exe that ships in the packages. $script:AppConfigs = @( @{ Config = "src/vstest.console/app.config"; ExeName = "vstest.console.exe" } @@ -110,7 +120,21 @@ function Verify-BindingRedirects { } if (-not $dllPath) { - Write-Host " $assemblyName - not found in package layout, skipping." + if ($assemblyName -in $script:AllowMissingDlls) { + Write-Host " $assemblyName - SKIP (allowed missing — loaded from VS at runtime)" + continue + } + + # The deploy directory exists (package was found) but the DLL is missing. + # A binding redirect pointing to a DLL that doesn't ship causes runtime + # failures (e.g. #15765). Fail so the redirect gets removed. + $errors += "$($entry.ExeName): $assemblyName has a binding redirect but the DLL is not in the package layout" + if ($script:isCI) { + Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package" -ForegroundColor Red + } + else { + Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package — remove the redirect from $($entry.Config)" -ForegroundColor Red + } continue } From 51460c5ad6ac7fc34a6ab0aeb6d4ae95c5216d81 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 14 May 2026 13:43:52 +0200 Subject: [PATCH 2/5] Remove stale DiagnosticSource and Encodings.Web redirects from vstest.console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardened validation script caught two more orphaned binding redirects in vstest.console/app.config — both DLLs are explicitly excluded from the CLI package nuspec. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/vstest.console/app.config | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/vstest.console/app.config b/src/vstest.console/app.config index f2bfcfed8c..556125c5f6 100644 --- a/src/vstest.console/app.config +++ b/src/vstest.console/app.config @@ -43,15 +43,6 @@ - - - - - - - - - From ebf2b98601a60ff3762e5cdb619438916e87cc80 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 14 May 2026 13:46:07 +0200 Subject: [PATCH 3/5] Fix review feedback: fail locally on missing-DLL errors - Missing-DLL errors now Write-Error instead of reporting success - CI message distinguishes version mismatches (auto-fixable) from missing-DLL errors (manual removal needed) - Addresses Copilot review comments on lines 133 and 138 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/verify-binding-redirects.ps1 | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/eng/verify-binding-redirects.ps1 b/eng/verify-binding-redirects.ps1 index 9b18aa3df2..91669685f0 100644 --- a/eng/verify-binding-redirects.ps1 +++ b/eng/verify-binding-redirects.ps1 @@ -2,6 +2,7 @@ $ErrorActionPreference = "Stop" Set-StrictMode -Version Latest $script:isCI = $env:TF_BUILD -eq 'true' -or $env:CI -eq 'true' +$script:hasUnfixableErrors = $false # Verifies that binding redirects in source app.config files match the actual # assembly versions of the DLLs shipped in the extracted nupkg packages. @@ -128,9 +129,11 @@ function Verify-BindingRedirects { # The deploy directory exists (package was found) but the DLL is missing. # A binding redirect pointing to a DLL that doesn't ship causes runtime # failures (e.g. #15765). Fail so the redirect gets removed. + # This cannot be auto-fixed — the redirect must be manually removed or the DLL shipped. $errors += "$($entry.ExeName): $assemblyName has a binding redirect but the DLL is not in the package layout" + $script:hasUnfixableErrors = $true if ($script:isCI) { - Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package" -ForegroundColor Red + Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package — remove the redirect or ship the DLL" -ForegroundColor Red } else { Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package — remove the redirect from $($entry.Config)" -ForegroundColor Red @@ -217,16 +220,26 @@ function Verify-BindingRedirects { if ($errors) { if ($script:isCI) { - $message = "Assembly binding redirect mismatches detected:`n" + $message = "Assembly binding redirect errors detected:`n" $message += ($errors -join "`n") - $message += "`n`nTo fix this, run the following command locally after building and packing:`n" - $message += " .\build.cmd -c $Configuration`n" - $message += "This will rebuild, pack, and auto-update the app.config files with the correct versions.`n" - $message += "Then commit the updated app.config files." + if ($configsToFix.Count -gt 0) { + $message += "`n`nFor version mismatches, run the following command locally after building and packing:`n" + $message += " .\build.cmd -c $Configuration`n" + $message += "This will rebuild, pack, and auto-update the app.config files with the correct versions.`n" + $message += "Then commit the updated app.config files." + } + if ($script:hasUnfixableErrors) { + $message += "`n`nFor missing-DLL errors, remove the binding redirect from the app.config or add the DLL to the package." + } Write-Error $message } else { - Write-Host "`nFixed $($errors.Count) binding redirect(s). Please commit the updated app.config files." -ForegroundColor Green + if ($configsToFix.Count -gt 0) { + Write-Host "`nFixed $($configsToFix.Count) version mismatch(es). Please commit the updated app.config files." -ForegroundColor Green + } + if ($script:hasUnfixableErrors) { + Write-Error "Missing-DLL binding redirect errors detected — these cannot be auto-fixed. Remove the redirect(s) listed above from the app.config file(s)." + } } } else { From 09ee89b588860c0720c72121cdd01a3d0257d1b8 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 14 May 2026 14:04:15 +0200 Subject: [PATCH 4/5] Fix em-dash encoding in verify-binding-redirects.ps1 Replace Unicode em-dash (U+2014) with ASCII hyphen in comments and strings. The em-dash gets corrupted to multi-byte garbage on CI's PowerShell, causing a parse error that breaks the entire validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/verify-binding-redirects.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/verify-binding-redirects.ps1 b/eng/verify-binding-redirects.ps1 index 91669685f0..fc27bef537 100644 --- a/eng/verify-binding-redirects.ps1 +++ b/eng/verify-binding-redirects.ps1 @@ -122,21 +122,21 @@ function Verify-BindingRedirects { if (-not $dllPath) { if ($assemblyName -in $script:AllowMissingDlls) { - Write-Host " $assemblyName - SKIP (allowed missing — loaded from VS at runtime)" + Write-Host " $assemblyName - SKIP (allowed missing - loaded from VS at runtime)" continue } # The deploy directory exists (package was found) but the DLL is missing. # A binding redirect pointing to a DLL that doesn't ship causes runtime # failures (e.g. #15765). Fail so the redirect gets removed. - # This cannot be auto-fixed — the redirect must be manually removed or the DLL shipped. + # This cannot be auto-fixed - the redirect must be manually removed or the DLL shipped. $errors += "$($entry.ExeName): $assemblyName has a binding redirect but the DLL is not in the package layout" $script:hasUnfixableErrors = $true if ($script:isCI) { - Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package — remove the redirect or ship the DLL" -ForegroundColor Red + Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package - remove the redirect or ship the DLL" -ForegroundColor Red } else { - Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package — remove the redirect from $($entry.Config)" -ForegroundColor Red + Write-Host " $assemblyName - ERROR: binding redirect exists but DLL not found in package - remove the redirect from $($entry.Config)" -ForegroundColor Red } continue } @@ -238,7 +238,7 @@ function Verify-BindingRedirects { Write-Host "`nFixed $($configsToFix.Count) version mismatch(es). Please commit the updated app.config files." -ForegroundColor Green } if ($script:hasUnfixableErrors) { - Write-Error "Missing-DLL binding redirect errors detected — these cannot be auto-fixed. Remove the redirect(s) listed above from the app.config file(s)." + Write-Error "Missing-DLL binding redirect errors detected - these cannot be auto-fixed. Remove the redirect(s) listed above from the app.config file(s)." } } } From e673793242f08f4cc50e614a5216a684a90f7440 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 14 May 2026 16:28:43 +0200 Subject: [PATCH 5/5] Remove FileSystemGlobbing from allow-list It ships in the package, so allowing it would mask a future packaging regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/verify-binding-redirects.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/eng/verify-binding-redirects.ps1 b/eng/verify-binding-redirects.ps1 index fc27bef537..54f44dcc00 100644 --- a/eng/verify-binding-redirects.ps1 +++ b/eng/verify-binding-redirects.ps1 @@ -17,7 +17,6 @@ $script:hasUnfixableErrors = $false $script:AllowMissingDlls = @( "Microsoft.VisualStudio.TestWindow.Interfaces" "Microsoft.VisualStudio.QualityTools.UnitTestFramework" - "Microsoft.Extensions.FileSystemGlobbing" ) # Each source app.config maps to a specific exe that ships in the packages.