@@ -378,6 +378,11 @@ jobs:
378378 SIGN : ${{ secrets.GPG_PRIVATE_KEY != '' && '1' || '' }}
379379 SIGN_KEY : ${{ secrets.GPG_KEY_ID }}
380380 APPIMAGETOOL_SIGN_PASSPHRASE : ${{ secrets.GPG_PASSPHRASE }}
381+ # minisign key for the auto-updater — makes `tauri build` emit a `.sig`
382+ # next to each updatable artifact (AppImage / NSIS). Distinct from the
383+ # GPG key above, which signs the AppImage file for manual verification.
384+ TAURI_SIGNING_PRIVATE_KEY : ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
385+ TAURI_SIGNING_PRIVATE_KEY_PASSWORD : ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
381386 run : |
382387 # Inject the real product version (module.prop is the single source of
383388 # truth) so the bundles aren't the 0.0.0 placeholder.
@@ -442,3 +447,73 @@ jobs:
442447 with :
443448 tag_name : ${{ needs.prepare.outputs.version }}
444449 files : dist/*
450+
451+ # Per-platform slice of the updater manifest: the `.sig` content + the asset
452+ # URL. The `updater-manifest` job merges every platform's slice into one
453+ # latest.json (the updater endpoint must list all platforms in a single file).
454+ - name : Build updater manifest fragment
455+ shell : bash
456+ run : |
457+ case "${{ matrix.target }}" in
458+ *linux*) plat=linux-x86_64; sig=$(find dist -maxdepth 1 -name '*.AppImage.sig' | head -1) ;;
459+ *windows*) plat=windows-x86_64; sig=$(find dist -maxdepth 1 -name '*-setup.exe.sig' | head -1) ;;
460+ *) plat=""; sig="" ;;
461+ esac
462+ if [ -z "${sig:-}" ]; then
463+ echo "no updater signature for ${{ matrix.target }} (signing key unset?) — skipping"
464+ exit 0
465+ fi
466+ # GitHub rewrites spaces in uploaded asset names to dots — match that so
467+ # the URL resolves (the AppImage carries the "Kasumi Proxy" product name).
468+ asset=$(basename "${sig%.sig}" | tr ' ' '.')
469+ tag="${{ needs.prepare.outputs.version }}"
470+ url="https://github.com/loss-and-quick/Kasumi-Proxy/releases/download/${tag}/${asset}"
471+ mkdir -p frag
472+ jq -n --arg p "$plat" --arg s "$(cat "$sig")" --arg u "$url" \
473+ '{($p): {signature: $s, url: $u}}' > "frag/${plat}.json"
474+ cat "frag/${plat}.json"
475+
476+ - name : Upload updater manifest fragment
477+ if : hashFiles('frag/*.json') != ''
478+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
479+ with :
480+ name : updater-frag-${{ matrix.target }}
481+ path : frag/*.json
482+ retention-days : 1
483+
484+ # ── Merge the per-platform updater slices into a single latest.json and attach
485+ # it to the release — this is the static endpoint the desktop updater polls. ──
486+ updater-manifest :
487+ needs : [prepare, desktop]
488+ if : needs.prepare.outputs.skip != 'true'
489+ runs-on : ubuntu-latest
490+ steps :
491+ - name : Download manifest fragments
492+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
493+ with :
494+ pattern : updater-frag-*
495+ path : frag
496+ merge-multiple : true
497+
498+ - name : Assemble latest.json
499+ shell : bash
500+ run : |
501+ if ! compgen -G "frag/*.json" >/dev/null; then
502+ echo "no updater fragments — skipping latest.json"
503+ exit 0
504+ fi
505+ tag="${{ needs.prepare.outputs.version }}"
506+ platforms=$(jq -s 'add' frag/*.json)
507+ jq -n \
508+ --arg version "${tag#v}" \
509+ --arg pub "$(date -u +%FT%TZ)" \
510+ --argjson platforms "$platforms" \
511+ '{version: $version, pub_date: $pub, platforms: $platforms}' > latest.json
512+ cat latest.json
513+
514+ - name : Upload latest.json to the release
515+ if : hashFiles('latest.json') != ''
516+ uses : softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
517+ with :
518+ tag_name : ${{ needs.prepare.outputs.version }}
519+ files : latest.json
0 commit comments