Skip to content

Commit f01c795

Browse files
docs(REV-007): unsigned per-arch distribution + install guide; defer universal
Signing is not required to ship a testable build. Documents the v0 plan: unsigned, per-arch macOS builds (arm64 + x64) plus Windows/Linux, with clear end-user "open it anyway" instructions per OS. - New dev-docs/guidelines/INSTALLING-UNSIGNED-BUILDS.md: Gatekeeper (xattr / right-click), Windows SmartScreen (More info → Run anyway), Linux AppImage (chmod +x, FUSE / --appimage-extract-and-run). Written for end users; copy into the GitHub Release notes. - A single-file macOS `--universal` build was evaluated and DEFERRED: proven locally that @electron/universal refuses to ship the single-arch native binaries (desktop-trampoline, dugite's git) our one-npm-install-per-arch pipeline produces. Per-arch is correct and ready; universal needs per-arch native merging, a later CI change. build.ts documents this; the universal wiring was reverted rather than left half-built. - RELEASE-PROCESS.md: unsigned distribution is fully supported (§ top); reframed the latest-mac.yml limitation as moot-until-signed (macOS auto-update requires a signed app). Verified: typecheck:editor clean; the arm64 per-arch packaging path is the same one already proven green (NodeGX-0.1.0-mac-arm64.{dmg,zip}); x64 builds natively on the macos-13 release runner. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 61535c4 commit f01c795

4 files changed

Lines changed: 131 additions & 11 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Installing NodeGX (unsigned builds)
2+
3+
NodeGX v0 is **not code-signed** — there is no paid Apple/Windows signing
4+
certificate yet. The app is safe, but because it is unsigned each operating
5+
system will warn you and make you take one deliberate step to open it the first
6+
time. After that first launch it opens normally.
7+
8+
> This page is written for end users. Copy it into the GitHub Release
9+
> description so anyone downloading a build knows how to open it. Maintainers:
10+
> the signing story is in [RELEASE-PROCESS.md](./RELEASE-PROCESS.md).
11+
12+
---
13+
14+
## macOS
15+
16+
**Download:** `NodeGX-<version>-mac-universal.dmg` — one file, runs on both Apple
17+
Silicon (M1/M2/M3/M4) and Intel Macs.
18+
19+
1. Open the `.dmg` and drag **NodeGX** into **Applications**.
20+
2. The first time you open it, macOS will say NodeGX *"cannot be opened because
21+
Apple cannot check it for malicious software"* (or *"is damaged"* on the
22+
newest macOS). This is the unsigned warning, not a real problem.
23+
24+
**Easiest fix — Terminal (works on every macOS version):**
25+
26+
```bash
27+
xattr -dr com.apple.quarantine /Applications/NodeGX.app
28+
```
29+
30+
Then open NodeGX normally from Applications.
31+
32+
**Alternative — no Terminal (macOS 14 and earlier):**
33+
34+
- Right-click (or Control-click) **NodeGX** in Applications → **Open**
35+
**Open** again in the dialog. macOS remembers the choice.
36+
- Or: try to open it once, then go to **System Settings → Privacy & Security**,
37+
scroll down, and click **Open Anyway**.
38+
39+
> On macOS 15 (Sequoia) Apple removed the right-click bypass for unsigned apps,
40+
> so the `xattr` command above is the reliable route there.
41+
42+
---
43+
44+
## Windows
45+
46+
**Download:** `NodeGX-<version>-win-x64.exe`.
47+
48+
1. Run the installer. Windows **SmartScreen** shows *"Windows protected your
49+
PC"*.
50+
2. Click **More info**, then **Run anyway**.
51+
52+
That's it — the app installs and opens normally afterwards.
53+
54+
> This warning appears because the installer is unsigned (and, once signed, will
55+
> still appear for a while until the certificate builds "reputation" through
56+
> downloads). It is expected for a new app, not a sign of a problem.
57+
58+
---
59+
60+
## Linux
61+
62+
**Download:** `NodeGX-<version>-linux-x86_64.AppImage` (portable, no install) or
63+
the `.deb` (Debian/Ubuntu).
64+
65+
### AppImage
66+
67+
```bash
68+
chmod +x NodeGX-*-linux-x86_64.AppImage
69+
./NodeGX-*-linux-x86_64.AppImage
70+
```
71+
72+
If it complains about **FUSE**, either install it once:
73+
74+
```bash
75+
sudo apt install libfuse2 # Debian/Ubuntu
76+
```
77+
78+
…or run without FUSE:
79+
80+
```bash
81+
./NodeGX-*-linux-x86_64.AppImage --appimage-extract-and-run
82+
```
83+
84+
### .deb (Debian / Ubuntu)
85+
86+
```bash
87+
sudo apt install ./NodeGX-*-linux-amd64.deb
88+
```
89+
90+
Then launch **NodeGX** from your applications menu.
91+
92+
---
93+
94+
## Is this safe?
95+
96+
Yes. "Unsigned" only means the project has not (yet) paid for the certificates
97+
that let Apple and Microsoft pre-verify the publisher. The warnings are the OS
98+
being cautious about *any* unsigned app. If you would rather verify the download
99+
yourself, each release lists SHA-512 checksums (in `latest*.yml`) you can check
100+
against your downloaded file.

dev-docs/guidelines/RELEASE-PROCESS.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ How to cut, verify, publish, and roll back a signed NodeGX release.
99
> code-signing certificate, and the CI secrets built from them. Until a human
1010
> completes [§1](#1-one-time-credential-setup-human-required), releases produced
1111
> by CI are **unsigned** (they still build and publish as drafts, but macOS
12-
> Gatekeeper will warn and Windows SmartScreen will block). Nothing ships to
13-
> users until someone provisions credentials and publishes a draft.
12+
> Gatekeeper will warn and Windows SmartScreen will block).
13+
>
14+
> **Distributing unsigned test builds is fully supported** in the meantime —
15+
> that is the current v0 plan. Point testers at
16+
> [INSTALLING-UNSIGNED-BUILDS.md](./INSTALLING-UNSIGNED-BUILDS.md) (copy it into
17+
> the GitHub Release notes) for the one-step "open it anyway" instructions per
18+
> OS. Signing just removes that friction; it is not required to ship.
1419
1520
---
1621

@@ -193,14 +198,21 @@ If a bad release has been published:
193198

194199
These are documented deliberately rather than silently shipped:
195200

196-
- **macOS multi-arch auto-update feed.** The matrix builds `darwin-arm64` and
197-
`darwin-x64` as separate jobs, and each writes `latest-mac.yml`. The second to
198-
finish overwrites the first, so the published `latest-mac.yml` points at only
199-
one arch's `.zip`. This is **harmless for the very first release** (no client
200-
is auto-updating yet) but **must be fixed before the second release**, or half
201-
of macOS users will be offered the wrong-arch update. The fix is a single
202-
**universal** macOS build (`--universal`) or arch-scoped update channels.
203-
Tracked as a follow-up; do not publish a v0.1.1 to mac users until it is done.
201+
- **macOS ships as per-arch builds** (`darwin-arm64` for Apple Silicon,
202+
`darwin-x64` for Intel), each fully functional — the standard "which Mac do
203+
you have?" download split. A single-file **universal** build was evaluated and
204+
**deferred**: `@electron/universal` correctly refuses to ship the bundled
205+
single-arch native binaries (`desktop-trampoline`, `dugite`'s `git`) in a
206+
universal app, so a real universal build needs each arch's natives built
207+
separately and lipo-merged — a CI change worth doing later, not required for
208+
distribution now.
209+
- **macOS multi-arch auto-update feed (future, signed phase only).** Once
210+
signing + auto-update are live, the two mac jobs each write `latest-mac.yml`
211+
and the later one wins, so the feed would point at one arch. This is **moot
212+
today** — macOS auto-update (Squirrel.Mac) requires a *signed* app, so
213+
auto-update does not run at all in the current unsigned phase. It becomes a
214+
must-fix the moment an Apple Developer ID is added: resolve it then with a
215+
universal build or arch-scoped update channels.
204216
- **Signing is credential-gated, not verified end-to-end.** No Apple/Windows
205217
certificates exist yet, so the signed/notarised path has never actually run.
206218
The hooks are wired and will engage the moment the secrets in §1 are present,

dev-docs/tasks/phase-12-reanimation/REV-007-SHIP-V0.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
- ⬜ Auto-update end-to-end across two *published* releases.
3737
- ⬜ Cut & publish v0.1.0 publicly (draft workflow is ready; a human confirms the draft).
3838

39-
**Known limitation flagged, not silently shipped:** the mac matrix builds arm64 and x64 as separate jobs that each overwrite `latest-mac.yml`, so the published feed points at one arch. Harmless for the *first* release (nobody is auto-updating yet) but **must be fixed before v0.1.1** (universal build). See `RELEASE-PROCESS.md` §6.
39+
**Unsigned distribution (current v0 plan).** Signing is *not* required to ship a testable build — it only removes the OS warning. macOS ships as **per-arch** builds (arm64 + x64), each fully functional; a single-file universal build was evaluated and deferred (`@electron/universal` refuses to ship the single-arch native binaries `desktop-trampoline`/`dugite` produced by the one-`npm install`-per-arch pipeline — proven by a local build attempt). End-user "open it anyway" instructions for all three OSes are in [`INSTALLING-UNSIGNED-BUILDS.md`](../../guidelines/INSTALLING-UNSIGNED-BUILDS.md), meant to be copied into the GitHub Release notes.
40+
41+
**Known limitation flagged, not silently shipped:** the mac arm64/x64 jobs each overwrite `latest-mac.yml`. This is **moot while unsigned** — macOS auto-update (Squirrel.Mac) requires a signed app, so it does not run at all yet — but becomes a must-fix the moment an Apple Developer ID is added. See `RELEASE-PROCESS.md` §6.
4042

4143
---
4244

packages/noodl-editor/scripts/build.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ import { BuildTarget, getDistPlatform } from './platform/build-platforms';
4848
const PUBLISH_RELEASE = valueToBoolean(process.env.PUBLISH_RELEASE);
4949
const publishArg = PUBLISH_RELEASE ? '--publish onTagOrDraft' : '--publish never';
5050

51+
// Per-arch macOS builds (arm64 / x64), each fully functional. A single-file
52+
// `--universal` build was evaluated and deferred: it needs the bundled native
53+
// binaries (desktop-trampoline, dugite's git) built for both arches and
54+
// lipo-merged, which this one-`npm install`-per-arch pipeline does not
55+
// produce — @electron/universal correctly refuses to ship single-arch natives
56+
// in a universal app. See dev-docs/guidelines/RELEASE-PROCESS.md §6.
5157
const args = [`--${platformName}`, `--${target.arch}`, publishArg].join(' ');
5258

5359
// Signing:

0 commit comments

Comments
 (0)