Skip to content

Phase 5C: sign updater bundles + commit Tauri pubkey#16

Open
wudi wants to merge 1 commit into
masterfrom
phase-5c-signing
Open

Phase 5C: sign updater bundles + commit Tauri pubkey#16
wudi wants to merge 1 commit into
masterfrom
phase-5c-signing

Conversation

@wudi

@wudi wudi commented May 15, 2026

Copy link
Copy Markdown
Contributor

Closes the auto-updater loop opened in #15. Once this merges + a v0.1.2 release is tagged, installed v0.1.2 users start receiving signed updates automatically.

What this PR does

src-tauri/tauri.conf.json

plugins.updater.pubkey populated with the minisign public key. The matching private key + password live in GitHub repo secrets that you (as the maintainer) added manually. The pubkey is public-by-design — it ships in every client bundle anyway, used to verify downloads.

.github/workflows/release.yml

Two changes to the Build Tauri bundle step:

  • Pass TAURI_SIGNING_PRIVATE_KEY and TAURI_SIGNING_PRIVATE_KEY_PASSWORD env (mapped from the two new secrets) to tauri-action. With these set, the action emits *.app.tar.gz / *.AppImage.tar.gz / *.nsis.zip alongside the user-facing installers, each paired with a .sig file.

And one change to the Collect & rename artifacts step:

  • New copy_sig helper + extra for loops to copy the updater bundles into dist-release/ under the same AnySpace-${VERSION}-${LABEL}.{ext} naming the backend manifest endpoint expects, plus their matching .sig files. Silently skips if .sig is missing (build run without secrets → unsigned → no .sig), so a secrets-not-set mistake degrades to "backend keeps returning 204" rather than breaking the release.

dist-release/* is already the glob both the GitHub Release publish step and the R2 upload step use, so the new artifacts flow downstream automatically.

backend/README.md

New Release engineering — signed auto-updates (phase 5) section documenting:

  • The two GitHub secrets (TAURI_PRIVATE_KEY, TAURI_KEY_PASSWORD) and where they come from
  • The pubkey-in-config ↔ private-key-in-secret relationship
  • The rotation procedure (regenerate locally → update both secret + pubkey in config → cut new release → old clients on old pubkey need manual reinstall)

You also need to

If you haven't already, add the two repo secrets at
https://github.com/anyspacedev/anyspace/settings/secrets/actions:

Secret Value
TAURI_PRIVATE_KEY The full contents of the private key file I generated this session (the long base64 blob starting dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5...)
TAURI_KEY_PASSWORD AYdAggxHIwDl2-n1BmuJiQ7xnxuoIBJU

Confirm once both are in and I'll shred the local copy at ~/.tauri/anyspace.key.

Verified

  • cargo check clean (the pubkey is compile-time embedded by tauri::generate_context!() — invalid base64 would have failed here).
  • yaml.safe_load passes on the modified workflow.

After merge

Tag a v0.1.2 with git tag v0.1.2 && git push origin v0.1.2 — the release workflow signs the bundles, uploads them alongside the existing DMG/MSI/AppImage, and the next time any installed copy hits https://api.anyspace.dev/updates/..., it'll get a real manifest back instead of 204.

Closes the auto-updater loop opened in #15. Once this merges + a v0.1.2
release is tagged, installed v0.1.2 users start receiving signed updates
automatically; v0.1.1 users have to manually grab v0.1.2 once (no
working updater shipped in 0.1.1).

src-tauri/tauri.conf.json
- plugins.updater.pubkey populated with the minisign public key (the
  matching private key + password are in GitHub repo secrets
  TAURI_PRIVATE_KEY / TAURI_KEY_PASSWORD).
- Pubkey is public-by-design (it ships in every client bundle anyway
  to verify downloads).

.github/workflows/release.yml
- Build Tauri bundle step picks up the signing env:
    TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
    TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
  With these set, tauri-action emits *.app.tar.gz / *.AppImage.tar.gz /
  *.nsis.zip alongside the user-facing installers, each paired with a
  .sig file.
- Collect & rename step copies the updater bundles into dist-release
  under the same `AnySpace-${VERSION}-${LABEL}.{ext}` naming the backend
  manifest endpoint expects, plus their matching .sig files via a small
  copy_sig helper. Helper skips silently if .sig is missing (build run
  without secrets → unsigned → no .sig → release silently has no updater
  artifacts), so the workflow can't fail solely on a secrets-not-set
  configuration mistake; the consequence shows up as the backend
  continuing to 204 every request.
- dist-release/* is already what the GitHub Release + R2 upload steps
  glob over, so no further wiring needed downstream.

backend/README.md
- New "Release engineering — signed auto-updates (phase 5)" section
  documenting the two secrets, the pubkey-in-config relationship, and
  the rotation procedure.

Verified: cargo check clean (tauri.conf.json embeds at compile time);
yaml.safe_load passes on the workflow.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant