Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ env:
# signed + notarized when the Developer ID secrets are populated,
# unsigned when they're missing.
#
# It also produces Windows + Linux installers (build-desktop → release-desktop):
# Linux .deb + .AppImage and a Windows NSIS .exe, appended to the same GitHub
# Release. These are UNSIGNED today (Windows code-signing needs a cert — see the
# build-desktop job) and ship WITHOUT the auto-updater (the updater latest.json
# stays macOS-only; Win/Linux users update by re-downloading). The desktop jobs
# are decoupled from the macOS build/release jobs — a Win/Linux failure can't
# block a macOS release, and vice versa.
#
# Required secrets for signing (all six must be set, gated on
# APPLE_TEAM_ID since it's the last to provision):
# APPLE_CERTIFICATE_BASE64 .p12 with the Developer ID Application
Expand Down Expand Up @@ -234,6 +242,88 @@ jobs:
retention-days: 7
if-no-files-found: error

# Windows + Linux installers. Decoupled from the macOS build/release jobs (it
# neither blocks nor is blocked by them), so a flaky AppImage/NSIS build can't
# break a macOS release. UNSIGNED today:
# • Windows: SmartScreen warns until a code-signing cert is wired. To sign,
# add the cert to tauri.conf.json → bundle.windows (certificateThumbprint +
# timestampUrl, or a signCommand / Azure Trusted Signing) and pass its
# secrets here — mirror the HAS_*_SIGNING gate idiom used by the mac jobs.
# • Linux: .deb/.AppImage are conventionally unsigned; the repo is the trust
# anchor.
# No auto-updater artifacts (createUpdaterArtifacts is unset) — Win/Linux
# updates are manual re-downloads for now (docs/CROSS-PLATFORM-HARDENING.md P2).
build-desktop:
name: Build installers (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
bundles: deb,appimage
- os: windows-latest
bundles: nsis
steps:
- uses: actions/checkout@v6

- uses: pnpm/action-setup@v6
with:
version: 10

- uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm

# Linux: WebKitGTK toolchain + libfuse2 (AppImage runtime needs FUSE 2).
- name: Install Linux system deps
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
libxdo-dev \
libssl-dev \
libfuse2

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
key: ${{ matrix.os }}

- name: Install
run: pnpm install --frozen-lockfile

# `--bundles` overrides the macOS-only config targets; createUpdaterArtifacts
# is unset so this needs no signing key.
- name: Build installers (${{ matrix.bundles }})
run: pnpm tauri build --bundles ${{ matrix.bundles }}

- name: Stage installers
shell: bash
run: |
set -euo pipefail
mkdir -p staged
find src-tauri/target/release/bundle -maxdepth 2 \
\( -name '*.deb' -o -name '*.AppImage' -o -name '*.exe' \) \
-exec cp {} staged/ \;
ls -lh staged/

- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: desktop-${{ matrix.os }}
path: staged/*
retention-days: 7
if-no-files-found: error

# Mac App Store flavor: a sandboxed, Apple-Distribution-signed .pkg built by
# scripts/build-mas.sh. Independent of the DMG build/release jobs (it neither
# blocks nor is blocked by them), so a misconfig here can't break direct
Expand Down Expand Up @@ -397,3 +487,41 @@ jobs:
dmg-staging/*.app.tar.gz
dmg-staging/latest.json
dmg-staging/SHA256SUMS

# Attach the Windows/Linux installers to the same GitHub Release. Separate from
# the macOS `release` job (which owns release-notes generation) so the two
# platforms can't block each other; action-gh-release upserts by tag, so this
# just adds files to the release the macOS job creates (or creates it if this
# wins the race — both are idempotent on the tag).
release-desktop:
needs: build-desktop
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Download desktop installer artifacts
uses: actions/download-artifact@v8
with:
pattern: desktop-*
path: desktop-staging
merge-multiple: true

- name: Compute SHA256SUMS (desktop)
run: |
set -euo pipefail
cd desktop-staging
shopt -s nullglob
ls -lh
shasum -a 256 *.deb *.AppImage *.exe > SHA256SUMS-desktop
cat SHA256SUMS-desktop

- name: Add installers to the GitHub Release
uses: softprops/action-gh-release@v3
with:
name: ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
fail_on_unmatched_files: false
files: |
desktop-staging/*.deb
desktop-staging/*.AppImage
desktop-staging/*.exe
desktop-staging/SHA256SUMS-desktop
19 changes: 10 additions & 9 deletions docs/CROSS-PLATFORM-HARDENING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,20 @@ Ordered by user-visible impact.
(`libfuse2` needed on the runner for AppImage)
- Windows → `Markup_1.0.1_x64-setup.exe` (NSIS)

No bundler errors. **Remaining:** decide whether to bake these targets into
`tauri.conf.json` per-OS (vs CLI `--bundles`) and wire them into a real
release pipeline (today `release.yml` is macOS-only). `flatpak` / `msi` still
optional/unbuilt.
No bundler errors. ✅ **Now wired into `release.yml`** — the `build-desktop` +
`release-desktop` jobs build these on every `v*` tag and attach them to the
GitHub Release, decoupled from the macOS jobs (a Win/Linux failure can't block
a macOS release). `flatpak` / `msi` still optional/unbuilt.
4. **Code signing — owner's call.** The installers above are **unsigned**:
Windows needs a **code-signing certificate** (EV or OV) or SmartScreen warns
on every download; Linux AppImage/flatpak signing is lighter. Budget +
procure the Windows cert (the real cost flagged in GTM §3).
5. **Updater per-platform.** The updater endpoint (`latest.json`) and signed
artifacts are currently macOS-only. Extend the release pipeline
(`.github/workflows/release.yml`) to build, sign, and publish Win/Linux
updater artifacts, or scope the updater to macOS and document manual updates
elsewhere.
5. **Updater scoped to macOS (decided).** `latest.json` + signed updater
artifacts stay macOS-only; Win/Linux ship installers **without** the
auto-updater, so those users update by re-downloading. Adding a Win/Linux
updater later means producing signed `createUpdaterArtifacts` bundles (needs
the Windows cert from item 4) and extending `latest.json` with
`windows-x86_64` / `linux-x86_64` entries.

### P3 — verify behaviour on the real webviews (manual, can't be done in headless CI)

Expand Down
Loading