|
11 | 11 |
|
12 | 12 | permissions: |
13 | 13 | contents: read |
14 | | - id-token: write # Azure OIDC: the launch/exit smoke test signs the exe first, |
15 | | - # because an unsigned uiAccess binary refuses to launch |
16 | 14 |
|
17 | 15 | jobs: |
18 | 16 | build: |
@@ -123,125 +121,10 @@ jobs: |
123 | 121 | throw "Release exe imports non-system runtime/dependency DLLs: $($blocked -join '; ')" |
124 | 122 | } |
125 | 123 |
|
126 | | - # ---- launch/exit smoke test ------------------------------------------------- |
127 | | - # Replays the winget validation harness's launch-and-quit sequence and fails on any |
128 | | - # nonzero exit code — it treats one as a failed run (winget-pkgs PR #408205: Clipp |
129 | | - # 1.4.0.150 came back "returned exit code: -1073741189" = 0xC000027B, |
130 | | - # STATUS_STOWED_EXCEPTION; ../WM_NIGHT died the same way in #393605). |
131 | | - # |
132 | | - # This MUST test the shipped bits: build_windows.ps1 stamps uiAccess=true into every |
133 | | - # Release exe, and an unsigned uiAccess binary REFUSES TO LAUNCH ("A referral was |
134 | | - # returned from the server"). Stripping the stamp to make it launchable would test a |
135 | | - # binary we never ship, so CI signs first — same Trusted Signing path as the release |
136 | | - # workflow — and launches the real thing. |
137 | | - # |
138 | | - # Signing needs the AZURE_* secrets, which are absent on fork PRs. Those legs skip |
139 | | - # the smoke test rather than fail: nothing to verify without a signature. |
140 | | - - name: Can we sign? (smoke test needs a signed binary) |
141 | | - id: cansign |
142 | | - env: |
143 | | - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} |
144 | | - run: | |
145 | | - $ok = [bool]$env:AZURE_CLIENT_ID |
146 | | - "ok=$($ok.ToString().ToLower())" >> $env:GITHUB_OUTPUT |
147 | | - if (-not $ok) { |
148 | | - Write-Host "::notice::No signing credentials (fork PR?) — skipping the launch/exit smoke test." |
149 | | - } |
150 | | -
|
151 | | - - name: Azure login (Trusted Signing) |
152 | | - if: steps.cansign.outputs.ok == 'true' |
153 | | - uses: azure/login@v2 |
154 | | - with: |
155 | | - client-id: ${{ secrets.AZURE_CLIENT_ID }} |
156 | | - tenant-id: ${{ secrets.AZURE_TENANT_ID }} |
157 | | - subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} |
158 | | - |
159 | | - - name: Sign Windows artifacts |
160 | | - if: steps.cansign.outputs.ok == 'true' |
161 | | - uses: azure/trusted-signing-action@v0 |
162 | | - with: |
163 | | - endpoint: ${{ vars.ARTIFACT_SIGNING_ENDPOINT }} |
164 | | - trusted-signing-account-name: ${{ vars.ARTIFACT_SIGNING_ACCOUNT }} |
165 | | - certificate-profile-name: ${{ vars.ARTIFACT_SIGNING_CERTIFICATE_PROFILE }} |
166 | | - files-folder: ${{ github.workspace }}\build\windows-release |
167 | | - files-folder-filter: exe,com |
168 | | - file-digest: SHA256 |
169 | | - timestamp-rfc3161: http://timestamp.acs.microsoft.com |
170 | | - timestamp-digest: SHA256 |
171 | | - # The action's dependency cache keys are arch-agnostic, so the amd64 and |
172 | | - # arm64 matrix legs poison each other's TrustedSigning module cache |
173 | | - # (Azure/trusted-signing-action#146). Fresh install costs ~1 min per leg. |
174 | | - cache-dependencies: false |
175 | | - |
176 | | - - name: Verify signature and uiAccess stamp |
177 | | - if: steps.cansign.outputs.ok == 'true' |
178 | | - run: | |
179 | | - $exe = ".\build\windows-release\clipp.exe" |
180 | | - $sig = Get-AuthenticodeSignature $exe |
181 | | - if ($sig.Status -ne 'Valid') { |
182 | | - throw "Signature on $exe is not Valid: $($sig.Status) — $($sig.StatusMessage)" |
183 | | - } |
184 | | - Write-Host "[+] signed by: $($sig.SignerCertificate.Subject)" |
185 | | - # Assert we are about to launch a uiAccess binary — the whole point is that the |
186 | | - # shipped configuration is what gets exercised. |
187 | | - $mt = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.*\*\mt.exe" -ErrorAction SilentlyContinue | |
188 | | - Sort-Object FullName -Descending | Select-Object -First 1 |
189 | | - if ($mt) { |
190 | | - $manifest = Join-Path $env:RUNNER_TEMP 'shipped.manifest' |
191 | | - & $mt.FullName -nologo -inputresource:"$exe;#1" -out:"$manifest" | Out-Null |
192 | | - $xml = Get-Content -Raw $manifest |
193 | | - if ($xml -match 'uiAccess="true"') { Write-Host '[+] uiAccess=true present (shipped configuration).' } |
194 | | - else { Write-Host '::warning::uiAccess=true NOT present in the embedded manifest.' } |
195 | | - } |
196 | | -
|
197 | | - - name: Enable WER local crash dumps |
198 | | - if: steps.cansign.outputs.ok == 'true' |
199 | | - run: | |
200 | | - # A stowed exception is a WinRT/COM fail-fast: it bypasses unhandled-exception |
201 | | - # filters, so Clipp's own crash handler never sees it and writes nothing. WER |
202 | | - # LocalDumps catches it at a lower level — the only way to get a dump at all. |
203 | | - $dumps = Join-Path $env:RUNNER_TEMP 'werdumps' |
204 | | - New-Item -ItemType Directory -Force $dumps | Out-Null |
205 | | - $key = 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\clipp.exe' |
206 | | - New-Item -Path $key -Force | Out-Null |
207 | | - Set-ItemProperty -Path $key -Name DumpFolder -Value $dumps -Type ExpandString |
208 | | - Set-ItemProperty -Path $key -Name DumpType -Value 2 -Type DWord # full dump |
209 | | - Set-ItemProperty -Path $key -Name DumpCount -Value 5 -Type DWord |
210 | | - "WER_DUMP_DIR=$dumps" >> $env:GITHUB_ENV |
211 | | -
|
212 | | - # -RequireWindow: this runner has a virgin HKCU, so no group key exists and Clipp |
213 | | - # must open its first-run XAML-Islands window — the exact path a validation VM takes, |
214 | | - # and the one a developer box with a configured key never exercises. If the window |
215 | | - # never appears, the island failed to come up: that is a failure, not a shrug. |
216 | | - # Graceful path: tray-menu Exit runs main()'s full teardown and must return 0. |
217 | | - - name: Smoke test — graceful exit (signed, uiAccess-stamped exe) |
218 | | - if: steps.cansign.outputs.ok == 'true' |
219 | | - run: .\scripts\exitcode_smoke.ps1 -ExePath ".\build\windows-release\clipp.exe" -RequireWindow -CloseMode TrayExit |
220 | | - |
221 | | - # Harness path: close the main window like Process.CloseMainWindow, then verify the |
222 | | - # app stays resident instead of self-terminating. A 0xC000027B here IS the winget |
223 | | - # validation failure reproduced — this is the leg that can actually catch it. |
224 | | - - name: Smoke test — winget harness sequence |
225 | | - if: steps.cansign.outputs.ok == 'true' |
226 | | - run: .\scripts\exitcode_smoke.ps1 -ExePath ".\build\windows-release\clipp.exe" -RequireWindow -CloseMode Harness |
227 | | - |
228 | | - - name: Collect crash diagnostics |
229 | | - if: failure() && steps.cansign.outputs.ok == 'true' |
230 | | - run: | |
231 | | - Write-Host '--- Application Error / WER events (last 30 min) ---' |
232 | | - Get-WinEvent -FilterHashtable @{ |
233 | | - LogName = 'Application'; StartTime = (Get-Date).AddMinutes(-30) |
234 | | - } -ErrorAction SilentlyContinue | |
235 | | - Where-Object { $_.ProviderName -in 'Application Error', 'Windows Error Reporting' -and |
236 | | - $_.Message -match 'clipp' } | |
237 | | - ForEach-Object { $_.TimeCreated; $_.Message; '---' } |
238 | | - Write-Host "--- Dumps in $env:WER_DUMP_DIR ---" |
239 | | - Get-ChildItem $env:WER_DUMP_DIR -ErrorAction SilentlyContinue |
240 | | -
|
241 | | - - name: Upload crash dumps |
242 | | - if: failure() && steps.cansign.outputs.ok == 'true' |
243 | | - uses: actions/upload-artifact@v4 |
244 | | - with: |
245 | | - name: werdumps-${{ matrix.arch }} |
246 | | - path: ${{ env.WER_DUMP_DIR }} |
247 | | - if-no-files-found: ignore |
| 124 | + # NOTE: the launch/exit smoke test (scripts/exitcode_smoke.ps1) deliberately does NOT |
| 125 | + # run here. It has to drive a SIGNED binary — an unsigned uiAccess exe refuses to |
| 126 | + # launch — and signing on every push/PR would burn Trusted Signing operations for a |
| 127 | + # check that only matters at release time. It lives in _release.yml instead, where it |
| 128 | + # runs against the INSTALLED, signed MSIX: the only configuration in which uiAccess is |
| 129 | + # actually granted (WindowsApps is a secure path), which is what winget's validation |
| 130 | + # exercises. |
0 commit comments