Spanda

Control Center desktop release runbook

Production macOS builds and optional signed auto-update for @spanda/control-center-desktop.

Current release: 0.6.3 — tag desktop-v0.6.3 (GitHub Release + workflow artifacts).

Full versioning policy (UI display, CLI, API fields, automatic bumps): control-center-versioning.md.


What operators get

Artifact Source
macOS .dmg / .app.tar.gz GitHub Release for desktop-v* (when CI bundle succeeds)
Unsigned fallback Workflow artifact control-center-desktop-macos-<version>
API backend Separate — spanda control-center serve (desktop does not embed spanda-api)
  1. Start the API: spanda control-center serve --bind 127.0.0.1:8080
  2. Install the desktop app from the GitHub Release
  3. Confirm version: sidebar shows vX.Y.Z, or spanda control-center --version
  4. Optional: VITE_CONTROL_CENTER_URL at dev time; production builds default to local API URL from env

Prerequisites (maintainers)

Platform Requirements
macOS CI macos-latest runner (workflow default)
Codesign (optional) APPLE_SIGNING_IDENTITY, APPLE_NOTARIZE_PROFILE
Auto-update (optional) TAURI_UPDATER_PUBKEY, TAURI_SIGNING_PRIVATE_KEY
Windows (future) WINDOWS_SIGNING_CERT (optional CI secret)

Without Apple secrets, CI still produces unsigned bundles and publishes a GitHub Release (installers or artifact download link in release notes).


Version sync

Keep these three files on the same semver before tagging:

File Field
packages/control-center-desktop/package.json "version"
packages/control-center-desktop/src-tauri/Cargo.toml version
packages/control-center-desktop/src-tauri/tauri.conf.json "version"
./scripts/verify_desktop_release_ready.sh

This runs control_center_desktop_smoke.sh (Tauri cargo check) and fails on version mismatch.

The Control Center UI semver (packages/web) is a separate workspace manifest but is shown in the sidebar and API; align it with desktop releases when shipping coordinated Control Center features. See control-center-versioning.md.


Release a new version

Automatic (preferred)

  1. Label the PR before merge: release:patch, release:minor, or release:major.
  2. Ensure the PR changes Control Center paths (see scripts/control_center_paths_changed.sh).
  3. Merge to main; after CI Integration passes, Auto release bumps desktop and pushes desktop-v*.

Manual

1. Bump versions

python3 scripts/bump_version.py minor --stream desktop --dry-run
python3 scripts/bump_version.py minor --stream desktop
./scripts/verify_desktop_release_ready.sh
git add packages/control-center-desktop/
git commit -m "chore: release desktop v0.6.4"
git push origin main

Or edit all three manifest files manually, then run ./scripts/verify_desktop_release_ready.sh.

2. Tag and push

git tag desktop-v0.6.4
git push origin desktop-v0.6.4

Tag pattern desktop-v* must match the semver in the manifests.

Alternative: Actions → Bump version → stream desktop, choose patch/minor/major, enable Push release tag.

3. Watch CI

GitHub → Actions → Desktop Control Center release

The workflow (.github/workflows/desktop-release.yml):

  1. Runs control_center_desktop_smoke.sh
  2. Builds Tauri bundle (TAURI_BUILD=1; --no-sign when TAURI_SIGNING_PRIVATE_KEY is unset)
  3. Optionally runs sign_tauri_macos.sh when Apple secrets are set
  4. Uploads workflow artifacts (control-center-desktop-macos-<version>)
  5. Creates a GitHub Release with .dmg / .app.tar.gz when present

Manual trigger: Actions → Desktop Control Center release → Run workflow (no Release unless triggered by tag).


GitHub Actions secrets (optional)

Secret Purpose
TAURI_UPDATER_PUBKEY Embed updater public key at build (build.rs)
TAURI_SIGNING_PRIVATE_KEY Sign updater artifacts; omit to pass --no-sign
APPLE_SIGNING_IDENTITY macOS codesign
APPLE_NOTARIZE_PROFILE notarytool profile for stapled notarization

Set SPANDA_DESKTOP_UPDATER_ACTIVE=1 in CI when TAURI_UPDATER_PUBKEY is configured.


Local build

export TAURI_BUILD=1
npm run build --workspace=@spanda/control-center-desktop
# Optional after bundle:
./scripts/sign_tauri_macos.sh

Artifacts: packages/control-center-desktop/src-tauri/target/release/bundle/


Auto-update (optional upgrade)

  1. Generate updater keypair: npm run tauri signer generate -- -w ~/.tauri/spanda-updater.key
  2. Set TAURI_UPDATER_PUBKEY in CI (injected via src-tauri/build.rs)
  3. Set TAURI_SIGNING_PRIVATE_KEY for signed updater artifacts
  4. Enable with SPANDA_DESKTOP_UPDATER_ACTIVE=1 on release builds
  5. Host update manifests at https://releases.spanda.dev/control-center/... (endpoint template in tauri.conf.json)

Until updater secrets are configured, operators install new versions manually from GitHub Releases.


Key rotation

  1. Generate new updater keypair
  2. Ship dual-signed release accepting previous pubkey window (30 days)
  3. Update CI secrets and plugins.updater.pubkey injection
  4. Document rotation in fleet change log

Troubleshooting

Symptom Likely cause Fix
verify_desktop_release_ready.sh version mismatch package.json / Cargo.toml / tauri.conf.json out of sync python3 scripts/bump_version.py patch --stream desktop or align manually
Tag pushed, no GitHub Release Workflow failed before release step Check Actions log; fix build; new patch tag
Release has no .dmg Bundle step failed or wrong paths Download workflow artifact instead
App won’t open on macOS Unsigned build Right-click → Open, or configure Apple signing secrets and re-release
Desktop can’t reach API API not running or wrong URL Start spanda control-center serve; set VITE_CONTROL_CENTER_URL in dev
Sidebar version ≠ installed desktop tag Streams diverged or old API Match desktop-v* install with running API build; see control-center-versioning.md