-
Notifications
You must be signed in to change notification settings - Fork 14
Fix Windows Tauri signing order #584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,13 +12,14 @@ build | |
| stage pinned runtime DLLs, and compile maple.exe without bundling. | ||
|
|
||
| bundle | ||
| Verify maple.exe is Authenticode-signed, then generate the NSIS installer | ||
| from that signed app executable. The installer itself is not signed here. | ||
| Generate the NSIS installer. Tauri patches and signs maple.exe through | ||
| bundle.windows.signCommand during bundling, signs the installer, then restores | ||
| target/release/maple.exe to its original unsigned/unpatched bytes. | ||
|
|
||
| finalize | ||
| Verify Authenticode signatures on maple.exe and the NSIS installer, create | ||
| the final Tauri updater signature for the signed installer, and emit release | ||
| reproducibility manifests. | ||
| Verify Authenticode signatures on the NSIS installer, create the final Tauri | ||
| updater signature for the signed installer, and emit release reproducibility | ||
| manifests. | ||
| EOF | ||
| } | ||
|
|
||
|
|
@@ -74,7 +75,10 @@ run_bundle_phase() { | |
| configure_reproducible_build_metadata | ||
|
|
||
| app_exe="$(windows_release_app_exe)" | ||
| verify_windows_authenticode_signatures "${app_exe}" | ||
| if [ ! -f "${app_exe}" ]; then | ||
| echo "Windows app executable is missing before bundling: ${app_exe}" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| cd "${FRONTEND_DIR}" | ||
| remove_build_tree "${TAURI_DIR}/target/release/bundle/nsis" | ||
|
|
@@ -83,21 +87,24 @@ run_bundle_phase() { | |
| bun tauri bundle --verbose --bundles nsis --config "$(windows_tauri_release_bundle_config)" | ||
|
|
||
| setup_exe="$(windows_release_setup_exe_required)" | ||
| # Tauri restores target/release/maple.exe after bundling. The durable signed | ||
| # artifact at this point is the NSIS installer; installed-payload verification | ||
| # should inspect an extracted installer payload, not the restored build output. | ||
| verify_windows_authenticode_signatures "${setup_exe}" | ||
| print_file_hashes "${setup_exe}" | ||
| verify_frontend_dist_unchanged | ||
| } | ||
|
|
||
| run_finalize_phase() { | ||
| local app_exe setup_exe repro_dir | ||
| local setup_exe repro_dir | ||
| local windows_runtime_dlls=() | ||
|
|
||
| print_source_provenance | ||
| configure_reproducible_build_metadata | ||
| configure_tauri_updater_signing_key | ||
|
|
||
| app_exe="$(windows_release_app_exe)" | ||
| setup_exe="$(windows_release_setup_exe_required)" | ||
| verify_windows_authenticode_signatures "${app_exe}" "${setup_exe}" | ||
| verify_windows_authenticode_signatures "${setup_exe}" | ||
|
Comment on lines
98
to
+107
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚩 Authenticode verification scope narrowed from exe+installer to installer-only The finalize phase previously verified Authenticode signatures on both Was this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| rm -f "${setup_exe}.sig" | ||
| sign_tauri_updater_artifacts "${setup_exe}" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| $ErrorActionPreference = "Stop" | ||
| Set-StrictMode -Version 3.0 | ||
|
|
||
| $moduleName = "ArtifactSigning" | ||
| $moduleVersion = "0.1.8" | ||
| $moduleSha256 = "3221344b8c627915d3870f23e80816f31a5d8c2bae1d7c0cdd6c9652f6c4e089" | ||
| $moduleUrl = "https://www.powershellgallery.com/api/v2/package/$moduleName/$moduleVersion" | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($env:RUNNER_TEMP)) { | ||
| $baseTemp = [System.IO.Path]::GetTempPath() | ||
| } else { | ||
| $baseTemp = $env:RUNNER_TEMP | ||
| } | ||
|
|
||
| $moduleRoot = Join-Path $baseTemp "maple-powershell-modules" | ||
| $moduleDir = Join-Path $moduleRoot "$moduleName/$moduleVersion" | ||
| $downloadDir = Join-Path $baseTemp "maple-powershell-downloads" | ||
| $packagePath = Join-Path $downloadDir "$moduleName.$moduleVersion.nupkg" | ||
|
|
||
| New-Item -ItemType Directory -Force -Path $downloadDir | Out-Null | ||
| New-Item -ItemType Directory -Force -Path $moduleRoot | Out-Null | ||
|
|
||
| Invoke-WebRequest -Uri $moduleUrl -OutFile $packagePath -TimeoutSec 120 | ||
|
|
||
| $actualSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $packagePath).Hash.ToLowerInvariant() | ||
| if ($actualSha256 -ne $moduleSha256) { | ||
| throw "$moduleName $moduleVersion hash mismatch. Expected $moduleSha256 but got $actualSha256." | ||
| } | ||
|
|
||
| if (Test-Path -LiteralPath $moduleDir) { | ||
| Remove-Item -LiteralPath $moduleDir -Recurse -Force | ||
| } | ||
| New-Item -ItemType Directory -Force -Path $moduleDir | Out-Null | ||
| Expand-Archive -LiteralPath $packagePath -DestinationPath $moduleDir -Force | ||
|
|
||
| $manifestPath = Join-Path $moduleDir "$moduleName.psd1" | ||
| Import-Module -Name $manifestPath -Force -ErrorAction Stop | ||
| $loadedModule = Get-Module $moduleName | Where-Object { $_.Version -eq [version]$moduleVersion } | Select-Object -First 1 | ||
| if (-not $loadedModule) { | ||
| throw "$moduleName $moduleVersion was not loaded from $manifestPath." | ||
| } | ||
| if (-not (Get-Command Invoke-ArtifactSigning -ErrorAction SilentlyContinue)) { | ||
| throw "Invoke-ArtifactSigning was not exported by $manifestPath." | ||
| } | ||
|
|
||
| if (-not [string]::IsNullOrWhiteSpace($env:GITHUB_ENV)) { | ||
| "MAPLE_WINDOWS_ARTIFACT_SIGNING_MODULE_ROOT=$moduleRoot" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 | ||
| if ([string]::IsNullOrWhiteSpace($env:PSModulePath)) { | ||
| "PSModulePath=$moduleRoot" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 | ||
| } else { | ||
| "PSModulePath=$moduleRoot;$env:PSModulePath" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 | ||
| } | ||
| } | ||
|
|
||
| Write-Host "$moduleName $moduleVersion installed with verified SHA-256 $moduleSha256" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| param( | ||
| [Parameter(Mandatory = $true)] | ||
| [string]$File | ||
| ) | ||
|
|
||
| $ArtifactSigningVersion = "0.1.8" | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
| Set-StrictMode -Version 3.0 | ||
|
|
||
| if (-not (Test-Path -LiteralPath $File -PathType Leaf)) { | ||
| throw "Windows artifact to sign was not found: $File" | ||
| } | ||
|
|
||
| $requiredEnv = @( | ||
| "MAPLE_WINDOWS_ARTIFACT_SIGNING_ENDPOINT", | ||
| "MAPLE_WINDOWS_ARTIFACT_SIGNING_ACCOUNT_NAME", | ||
| "MAPLE_WINDOWS_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME" | ||
| ) | ||
|
|
||
| foreach ($name in $requiredEnv) { | ||
| if ([string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($name))) { | ||
| throw "$name is required for Windows Artifact Signing." | ||
| } | ||
| } | ||
|
|
||
| $moduleRoot = $env:MAPLE_WINDOWS_ARTIFACT_SIGNING_MODULE_ROOT | ||
| if (-not [string]::IsNullOrWhiteSpace($moduleRoot)) { | ||
| $moduleManifest = Join-Path $moduleRoot "ArtifactSigning/$ArtifactSigningVersion/ArtifactSigning.psd1" | ||
| if (-not (Test-Path -LiteralPath $moduleManifest -PathType Leaf)) { | ||
| throw "ArtifactSigning module manifest was not found: $moduleManifest" | ||
| } | ||
| Import-Module -Name $moduleManifest -Force -ErrorAction Stop | ||
| } else { | ||
| Import-Module ArtifactSigning -RequiredVersion $ArtifactSigningVersion -ErrorAction Stop | ||
| } | ||
|
|
||
| $loadedModule = Get-Module ArtifactSigning | Where-Object { $_.Version -eq [version]$ArtifactSigningVersion } | Select-Object -First 1 | ||
| if (-not $loadedModule) { | ||
| throw "ArtifactSigning $ArtifactSigningVersion was not loaded." | ||
| } | ||
|
|
||
| $params = @{ | ||
| Endpoint = $env:MAPLE_WINDOWS_ARTIFACT_SIGNING_ENDPOINT | ||
| CodeSigningAccountName = $env:MAPLE_WINDOWS_ARTIFACT_SIGNING_ACCOUNT_NAME | ||
| CertificateProfileName = $env:MAPLE_WINDOWS_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME | ||
| Files = $File | ||
| FileDigest = "SHA256" | ||
| TimestampRfc3161 = "http://timestamp.acs.microsoft.com" | ||
| TimestampDigest = "SHA256" | ||
| ExcludeEnvironmentCredential = $true | ||
| ExcludeWorkloadIdentityCredential = $true | ||
| ExcludeManagedIdentityCredential = $true | ||
| ExcludeSharedTokenCacheCredential = $true | ||
| ExcludeVisualStudioCredential = $true | ||
| ExcludeVisualStudioCodeCredential = $true | ||
| ExcludeAzureCliCredential = $false | ||
| ExcludeAzurePowerShellCredential = $true | ||
| ExcludeAzureDeveloperCliCredential = $true | ||
| ExcludeInteractiveBrowserCredential = $true | ||
| } | ||
|
Comment on lines
+43
to
+61
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚩 Module parameter names mapped from GitHub Action input names to PowerShell cmdlet parameters The old GitHub Action used kebab-case input names (e.g., Was this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| Invoke-ArtifactSigning @params | ||
|
|
||
| Write-Host ("signed-windows-artifact {0}" -f (Split-Path -Leaf $File)) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Keep verifying the patched app executable after bundling.
Line 89 and Line 103 now verify only the NSIS setup. Since the app exe is the artifact Tauri mutates and
signCommandis expected to sign, verify${app_exe}after bundling as well; otherwise a signed installer can ship an unsigned or wrong-subject installed executable.Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents