ci: sign Windows builds with Azure Artifact Signing
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (pull_request) Successful in 4s
Secret Scan / scan (push) Successful in 6s
Build App (Preview) / create-release (pull_request) Successful in 2s
Build App (Preview) / build-macos (pull_request) Successful in 3m19s
Build App (Preview) / test (pull_request) Successful in 4m59s
Build App (Preview) / build-linux (pull_request) Successful in 5m18s
Build App (Preview) / build-windows (pull_request) Failing after 5m32s
Build App (Preview) / prune-previews (pull_request) Skipped
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (pull_request) Successful in 4s
Secret Scan / scan (push) Successful in 6s
Build App (Preview) / create-release (pull_request) Successful in 2s
Build App (Preview) / build-macos (pull_request) Successful in 3m19s
Build App (Preview) / test (pull_request) Successful in 4m59s
Build App (Preview) / build-linux (pull_request) Successful in 5m18s
Build App (Preview) / build-windows (pull_request) Failing after 5m32s
Build App (Preview) / prune-previews (pull_request) Skipped
Releases and PR previews now sign the app binary, the MSI, the NSIS installer and its uninstaller. "Verify signatures" fails the job on any unsigned or untimestamped .exe/.msi, so an unsigned installer can't ship quietly. - windows-signing-setup.ps1 fetches Microsoft.ArtifactSigning.Client 1.0.128 and a job-local .NET 10.0.12 runtime, each pinned by hash. Nothing is installed on the build VM. It also writes the dlib metadata and exports TAURI_CONFIG with bundle.windows.signCommand. - windows-sign.ps1 runs the installed signtool with /dlib, SHA-256 and the Microsoft timestamp server, with retries. Credentials come only from the AZURE_* environment. The metadata excludes every credential type except EnvironmentCredential, because InteractiveBrowserCredential would hang a job running as SYSTEM. - The signing files go in the workspace, not %TEMP%, because the uninstaller is signed from 32-bit makensis and WOW64 redirects SYSTEM's %TEMP%. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# windows-verify-signatures.ps1 <path-or-wildcard>... - fail unless every file
|
||||
# carries a valid, timestamped Authenticode signature.
|
||||
#
|
||||
# The check that makes signing load-bearing rather than hopeful: Tauri skips
|
||||
# signing silently in some configurations (no sign command, --no-sign), and an
|
||||
# unsigned installer looks exactly like a signed one until SmartScreen blocks
|
||||
# it on a user's machine. Every pattern must match at least one file, so a
|
||||
# bundle that was never produced cannot pass either.
|
||||
|
||||
param([Parameter(Mandatory = $true, ValueFromRemainingArguments = $true)][string[]]$Patterns)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (-not $env:TRIPLE_C_SIGNTOOL) { throw 'TRIPLE_C_SIGNTOOL is not set - run windows-signing-setup.ps1 first' }
|
||||
|
||||
$files = foreach ($pattern in $Patterns) {
|
||||
$found = @(Get-ChildItem -Path $pattern -File -ErrorAction SilentlyContinue)
|
||||
if ($found.Count -eq 0) { throw "Nothing to verify matches $pattern" }
|
||||
$found
|
||||
}
|
||||
|
||||
$failed = @()
|
||||
foreach ($file in $files) {
|
||||
# signtool's own check: chain to a trusted root under the default
|
||||
# Authenticode policy.
|
||||
# Stop relaxed for the native call, as in windows-sign.ps1.
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$verifyOutput = & $env:TRIPLE_C_SIGNTOOL verify /pa $file.FullName 2>&1 | ForEach-Object { "$_" }
|
||||
$signtoolOk = ($LASTEXITCODE -eq 0)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (-not $signtoolOk) { $verifyOutput | Write-Host }
|
||||
|
||||
# And the timestamp, which signtool verify does not require.
|
||||
$sig = Get-AuthenticodeSignature -FilePath $file.FullName
|
||||
$timestamped = $null -ne $sig.TimeStamperCertificate
|
||||
|
||||
if ($signtoolOk -and $sig.Status -eq 'Valid' -and $timestamped) {
|
||||
Write-Host "OK $($file.Name) - $($sig.SignerCertificate.Subject)"
|
||||
} else {
|
||||
Write-Host "FAIL $($file.Name) - status $($sig.Status), signtool $(if ($signtoolOk) {'ok'} else {'failed'}), timestamped $timestamped"
|
||||
$failed += $file.Name
|
||||
}
|
||||
}
|
||||
if ($failed.Count -gt 0) { throw "Not validly signed: $($failed -join ', ')" }
|
||||
Write-Host "All $(@($files).Count) files are signed and timestamped."
|
||||
Reference in New Issue
Block a user