Skip to content

Commit 313af16

Browse files
authored
Merge pull request voquill#483 from voquill/fix/windows-updater-signature
Fix Windows updater signature verification failures
2 parents 8a2bce2 + 6533555 commit 313af16

2 files changed

Lines changed: 109 additions & 1 deletion

File tree

‎.github/workflows/_release-desktop-impl.yml‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,9 +872,20 @@ jobs:
872872
Write-Host "Uploading $destName to release $env:RELEASE_TAG"
873873
gh release upload $env:RELEASE_TAG $destName --clobber
874874
875+
# Azure Trusted Signing (above) rewrites the NSIS exe after Tauri computed
876+
# its updater signature, so the sig and latest.json must be regenerated from
877+
# the final bytes before the channel manifest is published.
878+
resign-windows-updater:
879+
name: Re-sign Windows updater
880+
needs: [metadata, build]
881+
uses: ./.github/workflows/resign-windows-updater.yml
882+
with:
883+
release_tag: ${{ needs.metadata.outputs.tag_name }}
884+
secrets: inherit
885+
875886
update-channel:
876887
name: Update channel release
877-
needs: [metadata, build]
888+
needs: [metadata, build, resign-windows-updater]
878889
runs-on: ubuntu-latest
879890
permissions:
880891
contents: write
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Re-sign Windows updater
2+
3+
# Azure Trusted Signing modifies the NSIS installer *after* Tauri generates its
4+
# minisign updater signature, which invalidates it and breaks auto-updates with
5+
# "signature verification failed". This workflow re-signs the final exe bytes,
6+
# patches latest.json, and verifies every signature in the manifest before
7+
# publishing. It runs as part of the desktop release pipeline and can be
8+
# dispatched manually to repair an already-published release.
9+
10+
on:
11+
workflow_call:
12+
inputs:
13+
release_tag:
14+
description: "Release tag holding the artifacts (e.g. desktop-v0.0.650)"
15+
required: true
16+
type: string
17+
channel_tag:
18+
description: "Channel tag that should also receive the patched latest.json (e.g. desktop-prod)"
19+
required: false
20+
type: string
21+
default: ""
22+
workflow_dispatch:
23+
inputs:
24+
release_tag:
25+
description: "Release tag holding the artifacts (e.g. desktop-v0.0.650)"
26+
required: true
27+
type: string
28+
channel_tag:
29+
description: "Channel tag that should also receive the patched latest.json (e.g. desktop-prod)"
30+
required: false
31+
type: string
32+
default: ""
33+
34+
jobs:
35+
resign:
36+
name: Re-sign and verify updater signatures
37+
runs-on: ubuntu-latest
38+
permissions:
39+
contents: write
40+
env:
41+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42+
GH_REPO: ${{ github.repository }}
43+
RELEASE_TAG: ${{ inputs.release_tag }}
44+
CHANNEL_TAG: ${{ inputs.channel_tag }}
45+
steps:
46+
- name: Download latest.json and updater artifacts
47+
run: |
48+
set -euo pipefail
49+
mkdir -p dist
50+
gh release download "$RELEASE_TAG" --pattern "latest.json" --dir dist --clobber
51+
jq -r '.platforms[].url | sub(".*/"; "")' dist/latest.json | sort -u | while read -r asset; do
52+
gh release download "$RELEASE_TAG" --pattern "$asset" --dir dist --clobber
53+
done
54+
55+
- name: Re-sign NSIS installers
56+
env:
57+
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
58+
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_PRIVATE_KEY_PASSWORD }}
59+
run: |
60+
set -euo pipefail
61+
shopt -s nullglob
62+
for exe in dist/*-setup.exe; do
63+
npx --yes @tauri-apps/cli@2 signer sign "$exe"
64+
sig="$(cat "${exe}.sig")"
65+
name="$(basename "$exe")"
66+
jq --arg name "$name" --arg sig "$sig" \
67+
'.platforms |= with_entries(if (.value.url | endswith("/" + $name)) then .value.signature = $sig else . end)' \
68+
dist/latest.json > dist/latest.json.tmp
69+
mv dist/latest.json.tmp dist/latest.json
70+
done
71+
72+
- name: Verify every signature in latest.json
73+
env:
74+
TAURI_UPDATER_PUBLIC_KEY: ${{ secrets.TAURI_UPDATER_PUBLIC_KEY }}
75+
run: |
76+
set -euo pipefail
77+
sudo apt-get update -qq >/dev/null
78+
sudo apt-get install -y -qq minisign >/dev/null
79+
pub="$( (base64 -d <<<"$TAURI_UPDATER_PUBLIC_KEY" 2>/dev/null || printf '%s' "$TAURI_UPDATER_PUBLIC_KEY") | grep -m1 '^RW' )"
80+
jq -r '.platforms | to_entries[] | [.key, (.value.url | sub(".*/"; "")), .value.signature] | @tsv' dist/latest.json \
81+
| while IFS=$'\t' read -r platform asset sig; do
82+
printf '%s' "$sig" | base64 -d > asset.minisig
83+
minisign -Vm "dist/$asset" -x asset.minisig -P "$pub" >/dev/null
84+
echo "verified: $platform ($asset)"
85+
done
86+
87+
- name: Publish re-signed artifacts
88+
run: |
89+
set -euo pipefail
90+
shopt -s nullglob
91+
for sig in dist/*-setup.exe.sig; do
92+
gh release upload "$RELEASE_TAG" "$sig" --clobber
93+
done
94+
gh release upload "$RELEASE_TAG" dist/latest.json --clobber
95+
if [[ -n "$CHANNEL_TAG" ]]; then
96+
gh release upload "$CHANNEL_TAG" dist/latest.json --clobber
97+
fi

0 commit comments

Comments
 (0)