Skip to content

Ship Orbit as installable packages for macOS, Linux, and Windows #43

@nekrut

Description

@nekrut

Context

Orbit is an Electron app currently runnable only via `cd app && npm start` (dev mode). Alpha testers can't be expected to clone a repo. To distribute pre-built binaries we need to:

  1. Configure platform-specific makers (electron-forge already partially wired).
  2. Provide proper app icons.
  3. Decide a code-signing strategy for macOS (Gatekeeper) and Windows (SmartScreen).
  4. Wire CI to build + publish releases on git tags.

Current state, confirmed by reading `app/forge.config.ts` and `app/package.json`:

  • Forge config: `maker-zip` (darwin + linux), `maker-dmg` (darwin). No `.deb`/`.rpm`/AppImage maker for Linux. No Windows installer maker.
  • Icon: `app/resources/icon.png` exists but is 597×451 (non-square) — wrong for macOS (.icns wants 1024×1024 square) and Windows (.ico wants square multi-res).
  • Metadata: `productName: "Orbit"`, `executableName: "orbit"`, version `0.1.0`, description set. Good.
  • CI: Recently-merged `.github/workflows/build.yml` (PR ci: cross-platform matrix build (closes #37) #40) already runs `electron-forge package` on macOS + Linux + Windows — the unpacked build. `make` (which runs the makers above) is not yet in CI.

Approach

Seven small phases, each independently committable. Order matters — earlier phases unblock later ones.

Phase 1 — Square icon assets

The current `icon.png` is non-square; this will produce ugly results in all installers. Generate a proper icon set from a single 1024×1024 source PNG.

Files to add/modify:

  • `app/resources/icon.png` — replace with 1024×1024 square master.
  • `app/resources/icon.icns` — for macOS; generate via `iconutil` (macOS) or `png2icns` (cross-platform via Node).
  • `app/resources/icon.ico` — for Windows; generate via `png-to-ico` (Node) with sizes 16/32/48/64/128/256.
  • `app/forge.config.ts` — keep `icon: "resources/icon"` (forge auto-picks `.icns` on Mac, `.ico` on Windows, `.png` on Linux).

If we don't have a 1024×1024 master, the simplest stopgap is to letterbox/upscale the existing 597×451 to a 1024×1024 PNG.

Phase 2 — Linux makers

Add the three Linux package makers to `app/forge.config.ts`:

  • `@electron-forge/maker-deb` — produces `Orbit_0.1.0_amd64.deb` for Ubuntu/Debian (the alpha tester pool).
  • `@electron-forge/maker-rpm` — produces `.rpm` for Fedora/RHEL/SUSE testers.
  • `@reforged/maker-appimage` — produces a single-file `Orbit-0.1.0.AppImage` that runs on most distros without install. Most universal.

Install all three as devDependencies in `app/package.json`.

Linux build deps (CI/native): `dpkg`, `fakeroot`, `rpm` packages — usually pre-installed on `ubuntu-latest` GitHub runners but worth verifying.

Phase 3 — Windows makers

Add Windows package makers to `app/forge.config.ts`:

  • `@electron-forge/maker-squirrel` — produces `Orbit-0.1.0 Setup.exe` (Squirrel.Windows installer, the standard Electron approach). Auto-update-friendly. Recommended primary.
  • `@electron-forge/maker-zip` for `win32` — portable `.zip` of the unpacked app for users who can't run installers.

Skip `maker-wix` (`.msi`) for v0.1.0 — primarily for enterprise group-policy deployment, overkill for alpha.

Architecture: build x64 only for v0.1.0. ARM Windows is small slice and Electron's arm64 Windows builds are still rough.

Build host: Squirrel installers can be cross-compiled from Linux/Mac with `wine` installed, but the reliable path is to build Windows artifacts on a Windows runner (`windows-latest` in CI). Phase 6 wires this.

Phase 4 — macOS DMG polish

`maker-dmg` is already configured. Default DMG works but is plain. Optional polish (background image, iconSize, layout) — skip for v0.1.0, current DMG is functional.

Architecture: by default forge builds for the host arch. For Mac alpha, build both `arm64` and `x64` (or a universal binary). Recommend two separate DMGs for v0.1.0 (`Orbit-0.1.0-arm64.dmg`, `Orbit-0.1.0-x64.dmg`) — clearer for testers, smaller.

Phase 5 — Code-signing decision (macOS + Windows)

User-facing friction point. Two paths per OS, decided independently.

macOS:

  • A1 — Unsigned (free): ship unsigned DMGs. Gatekeeper blocks first launch with "Orbit can't be opened because Apple cannot check it for malicious software." Workaround: right-click → Open. Document this. Acceptable for alpha.
  • A2 — Apple Developer ID + notarization ($99/yr): requires an Apple Developer account, Developer ID Application cert, and app-specific password. Signing + notarization wired via `osxSign` + `osxNotarize` blocks in `forge.config.ts`. Smooth install for testers.

Windows:

  • B1 — Unsigned (free): SmartScreen warns "Microsoft Defender SmartScreen prevented an unrecognized app from starting." User clicks "More info" → "Run anyway." Same alpha tradeoff as Mac.
  • B2 — Code-signing certificate (~$200–500/yr): standard cert from DigiCert/Sectigo/etc. SmartScreen still warns until the cert builds reputation. EV cert ($300–700/yr) gets immediate trust but requires a hardware token, awkward in CI. Wired via `certificateFile` + `certificatePassword` in `maker-squirrel`, or via Azure Trusted Signing.

Linux requires no signing. AppImage and .deb both run unsigned without warnings.

This is a decision, not a code change.

Phase 6 — CI release workflow

Extend `.github/workflows/build.yml` with a `release` job:

  • Trigger: push of a tag matching `v*` (e.g. `v0.1.0`).
  • Matrix: `macos-latest` (arm64), `macos-13` (x64 — Intel runner), `ubuntu-latest`, `windows-latest`.
  • Steps: checkout → setup-node → `npm ci` → `cd app && npm ci && npx electron-forge make`.
  • Artifact upload: `softprops/action-gh-release` for direct attachment to a GitHub Release on tag push.
  • Secrets (only if signing):
    • macOS (path A2): `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID`, `CSC_LINK` (base64 cert), `CSC_KEY_PASSWORD`.
    • Windows (path B2): `WINDOWS_CERT_PFX_BASE64`, `WINDOWS_CERT_PASSWORD`.

Output on a clean release run, all attached to the `v0.1.0` GitHub Release:

  • `Orbit-0.1.0-arm64.dmg`, `Orbit-0.1.0-x64.dmg` + zips
  • `Orbit_0.1.0_amd64.deb`, `Orbit-0.1.0-1.x86_64.rpm`, `Orbit-0.1.0.AppImage`
  • `Orbit-0.1.0 Setup.exe`, `Orbit-0.1.0-win32-x64.zip`

Phase 7 — Release docs

`RELEASING.md` (root): bump `app/package.json` version, `git tag v0.1.0 && git push origin v0.1.0`, CI builds + publishes automatically. Manual local: `cd app && npx electron-forge make`.

`INSTALL.md` or README section:

  • macOS: download `.dmg`, drag to Applications. If unsigned: right-click → Open first time.
  • Windows: run `Orbit-*-Setup.exe`. If unsigned: SmartScreen → "More info" → "Run anyway."
  • Ubuntu/Debian: `sudo dpkg -i Orbit_*.deb`.
  • Fedora/RHEL: `sudo rpm -i Orbit-*.rpm`.
  • Other Linux: AppImage, `chmod +x`, run.

Critical files

  • `app/forge.config.ts` — makers (phases 2, 3, 4) + signing (phase 5)
  • `app/package.json` — devDependencies for new makers (phases 2, 3)
  • `app/resources/icon.{png,icns,ico}` — assets (phase 1)
  • `.github/workflows/build.yml` — release job (phase 6)
  • `RELEASING.md`, `INSTALL.md` — docs (phase 7)

Verification

  1. Local Linux: `cd app && npx electron-forge make`; install the .deb, run AppImage, launch Orbit.
  2. Local macOS (if available): `make`; mount DMG, drag to /Applications, launch.
  3. Local Windows (if available): `make`; run Setup.exe, click through SmartScreen.
  4. CI dry run: push a `v0.0.0-test` tag, watch release job, confirm artifacts attach. Delete tag.
  5. Tester smoke: one tester per OS installs and files a test issue via the in-app Report button (PR Add in-app issue reporter (closes #33, option A) #42).

Unresolved questions (resolve before implementation)

  1. Apple Developer ID — sign-up + budget? (A1 vs A2 in phase 5)
  2. Windows code-signing cert — sign-up + budget? (B1 vs B2 in phase 5)
  3. macOS architecture — universal binary or separate arm64/x64 DMGs?
  4. Linux package formats — all three (deb + rpm + AppImage), or just deb + AppImage?
  5. Distribution channel — GitHub Releases only, or also a download page on a galaxyproject site?
  6. Auto-update — ship in v0.1.0 (`update.electronjs.org`-compatible), or defer post-alpha?
  7. Icon master — does a 1024×1024 source exist, or do we letterbox the 597×451 for now?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions