From 3163a5ee75f6ed15889c3a444f8b1f15250f388d Mon Sep 17 00:00:00 2001 From: Mojtaba Karimi Date: Thu, 4 Jun 2026 12:54:40 +0200 Subject: [PATCH] ci(windows): sign exe and installer with Azure Trusted Signing Sign the bare .exe before the MSI is built (so the packed copy carries the signature) and the linked .msi afterwards, via azure/artifact-signing-action with SHA256 digests and Microsoft's RFC3161 timestamp server. Credentials come from the AZURE_* repository secrets. Also fix the MSI version fallback: workflow_dispatch runs use the branch name as ref_name, which is not a valid numeric ProductVersion, so candle failed on any non-tag run. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 39 ++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b43a3fcb..b5c1b708 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,6 +78,24 @@ jobs: - name: Build run: cargo build --release + - name: Sign executable (Azure Trusted Signing) + # Sign the bare .exe *before* the MSI is built so the copy packed + # into the installer carries the signature too. AZURE_CLIENT_SECRET + # authenticates the App Registration; the remaining AZURE_* secrets + # select the Trusted Signing account / certificate profile. + uses: azure/artifact-signing-action@v2 + with: + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + endpoint: ${{ secrets.AZURE_ENDPOINT }} + signing-account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }} + certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }} + files: ${{ github.workspace }}\target\release\OpenCADStudio.exe + file-digest: SHA256 + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Convert SVG icon to ICO shell: pwsh run: | @@ -93,7 +111,10 @@ jobs: shell: pwsh run: | $version = "${{ github.ref_name }}" -replace '^v', '' - if (-not $version) { $version = "0.0.0" } + # workflow_dispatch runs use the branch name as ref_name, which + # is not a valid MSI ProductVersion — fall back to 0.0.0 so test + # builds still produce an installer. + if ($version -notmatch '^\d+(\.\d+){0,3}$') { $version = "0.0.0" } # WiX Toolset 3.x is pre-installed on windows-latest; $env:WIX # points to the install root. candle compiles .wxs → .wixobj # and light links it into the final .msi. @@ -120,6 +141,22 @@ jobs: & $light $wixObj -out $msiPath if ($LASTEXITCODE -ne 0) { throw "light failed" } + - name: Sign MSI installer (Azure Trusted Signing) + # The installer itself must be signed separately — light produces a + # fresh, unsigned .msi even though the .exe inside is already signed. + uses: azure/artifact-signing-action@v2 + with: + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + endpoint: ${{ secrets.AZURE_ENDPOINT }} + signing-account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }} + certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }} + files: ${{ github.workspace }}\OpenCADStudio.msi + file-digest: SHA256 + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Upload artifacts to release if: github.event_name == 'release' shell: pwsh