From 85250cd220aea6f66ef3cac2f0771503054b6e9c Mon Sep 17 00:00:00 2001 From: Jeremy Date: Tue, 27 Oct 2026 11:46:32 +0000 Subject: [PATCH] fix(installer): harden install-policy checks and packaging-lint workflow --- .github/workflows/packaging-lint.yml | 9 +++++++-- packaging/windows/check-install-policy.ps1 | 13 ++++++++++--- packaging/windows/test-install-policy.ps1 | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/packaging-lint.yml b/.github/workflows/packaging-lint.yml index c1394c403..da85536c4 100644 --- a/.github/workflows/packaging-lint.yml +++ b/.github/workflows/packaging-lint.yml @@ -30,6 +30,8 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install the pinned packaging toolchain shell: pwsh run: | @@ -37,8 +39,11 @@ jobs: dotnet tool install --tool-path $tools wix --version 5.0.2 if ($LASTEXITCODE -ne 0) { throw 'WiX installation failed.' } $tools >> $env:GITHUB_PATH - & (Join-Path $tools 'wix.exe') extension add -g WixToolset.UI.wixext/5.0.2 WixToolset.Util.wixext/5.0.2 - if ($LASTEXITCODE -ne 0) { throw 'WiX extension installation failed.' } + $policy = Get-Content -Raw -LiteralPath packaging/windows/install-policy.json | ConvertFrom-Json + foreach ($extension in @($policy.extensions)) { + & (Join-Path $tools 'wix.exe') extension add -g "WixToolset.$extension.wixext/5.0.2" + if ($LASTEXITCODE -ne 0) { throw "WiX extension $extension installation failed." } + } - name: Build and check non-executable installer fixtures shell: pwsh run: ./packaging/windows/test-install-policy.ps1 -OutputDirectory (Join-Path $env:RUNNER_TEMP 'craft-install-policy-tests') diff --git a/packaging/windows/check-install-policy.ps1 b/packaging/windows/check-install-policy.ps1 index 00b683d70..451295a2e 100644 --- a/packaging/windows/check-install-policy.ps1 +++ b/packaging/windows/check-install-policy.ps1 @@ -122,9 +122,11 @@ try { Set-SessionProperty $session 'CRAFT_USER_DIR' 'D:\Existing user app' Set-SessionProperty $session 'CRAFT_MACHINE_DIR' 'E:\Existing machine app' $action = if ($scope -eq '1') { 'CraftRestoreMachineFolder' } else { 'CraftRestoreUserFolder' } - if (-not $explicit) { - if ($session.DoAction($action) -ne 1) { throw 'Remembered-folder property action failed.' } - } + # Evaluate the compiled condition, so the test exercises it instead of calling the action directly. + $restore = @(Read-Rows $database ('SELECT `Condition` FROM `InstallExecuteSequence` WHERE `Action` = ''{0}''' -f $action) 1)[0] + $selected = $session.EvaluateCondition($restore[0]) -eq 1 + if ($selected -eq [bool]$explicit) { throw "$action must run only when no folder was supplied (condition: $($restore[0]))." } + if ($selected -and $session.DoAction($action) -ne 1) { throw 'Remembered-folder property action failed.' } $expected = if ($explicit) { $explicit } elseif ($scope -eq '1') { 'E:\Existing machine app' } else { 'D:\Existing user app' } if ((Get-SessionProperty $session 'INSTALLFOLDER') -ne $expected) { throw 'Custom or remembered folder was not preserved.' } } @@ -145,6 +147,11 @@ try { throw 'Silent updates must restore the folder before directory costing.' } } + foreach ($resolver in @('CraftUFromLegacyExe','CraftMFromLegacyExe')) { + if (-not ($execute['AppSearch'] -lt $execute[$resolver] -and $execute[$resolver] -lt $execute['LaunchConditions'])) { + throw 'Both legacy folder resolvers must run after AppSearch and before the launch checks.' + } + } # Switching the first-page choice must reset BOTH properties, including a back-and-forth change. $events = @(Read-Rows $database 'SELECT `Event`, `Argument`, `Condition`, `Ordering` FROM `ControlEvent` WHERE `Dialog_` = ''CraftScopeDlg'' AND `Control_` = ''Next'' ORDER BY `Ordering`' 4) # Model the full-UI upgrade entry with an existing machine-wide copy. Run diff --git a/packaging/windows/test-install-policy.ps1 b/packaging/windows/test-install-policy.ps1 index 21199ca7f..d455d19d1 100644 --- a/packaging/windows/test-install-policy.ps1 +++ b/packaging/windows/test-install-policy.ps1 @@ -38,7 +38,7 @@ foreach ($arch in $Architectures) { $sources = @($policy.sources | ForEach-Object { Join-Path $PSScriptRoot $_ }) $msi = Join-Path $stage "$($policy.id)-NOT-INSTALLABLE.msi" $extensions = @($policy.extensions | ForEach-Object { '-ext'; "WixToolset.$_.wixext" }) - & wix build @sources -arch $arch -wx @extensions ` + & wix build @sources -arch $arch @extensions ` -culture en-US -d 'Version=0.0.1' -d 'DisplayVersion=0.0.1-metadata-test' ` -d "BinDir=$stage" -d "IconPath=$(Join-Path $root $policy.icon)" ` -d "DocsDir=$(Join-Path $stage 'docs')" -d "ModelsDir=$(Join-Path $stage 'models')" `