diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-03 11:25:45 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-03 11:25:45 +0200 |
| commit | 75669dcc4f060733f0fcf3b6de574b8f4630d4a1 (patch) | |
| tree | 4a3d1190374a3dfdc76396de26ac650dd3352a2c | |
| parent | dd671eb3647801317736327ab5b7cbfaa05d3866 (diff) | |
| download | meshbay-75669dcc4f060733f0fcf3b6de574b8f4630d4a1.tar.gz | |
chore(client): build against the latest Electron, and stop defining the package twice
Chromium CVEs are fixed in Electron releases, and a client built against
an old one ships those holes to every user. That is a certain harm; a
build that breaks on a new Electron is a repairable one. build-client.sh
now bumps to the latest on every build, prints the comparison, and lets
the build fail if it cannot cope — the failure is the signal to fix, not
a reason to stay behind. It writes package.json and the lockfile on
purpose: the new pin is meant to be committed. A registry it cannot reach
is a warning, not a failure.
Exercised by pinning back to 42.9.2 and building: "==> Electron 42.9.2 ->
44.1.1", exit 0, electron=44.1.1 in the packaged output. Note npm audit
would have said nothing about any of this — Chromium CVEs fixed in
Electron do not reliably reach the npm advisory database.
Separately, package.json declared linux.target [deb, rpm] with its own
deb/rpm depends, so `npm run dist` built a second package under the same
name. The two had drifted: /opt/MeshBay/meshbay-client against
/opt/meshbay-client/meshbay, and Depends: python3-meshbay-common naming
none of the Electron runtime libraries the real DEBIAN/control lists — it
would have installed cleanly and then refused to start. Nothing in the
tree referenced `npm run dist`, which is why the drift was free to
happen. That config is gone, "dist" delegates to build-client.sh, and
test_desktop_shell.py refuses its return.
`--dir` was re-run with no linux block at all: exit 0, same binary
build-client.sh consumes. It needs appId, productName and files, nothing
else.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbwJDbNTkiRUh7HTWEoyss
| -rw-r--r-- | packages/meshbay-client/package-lock.json | 8 | ||||
| -rw-r--r-- | packages/meshbay-client/package.json | 26 | ||||
| -rw-r--r-- | packages/meshbay-hub/tests/test_desktop_shell.py | 44 | ||||
| -rwxr-xr-x | packaging/build/build-client.sh | 43 |
4 files changed, 95 insertions, 26 deletions
diff --git a/packages/meshbay-client/package-lock.json b/packages/meshbay-client/package-lock.json index 2cf4f09..e86a523 100644 --- a/packages/meshbay-client/package-lock.json +++ b/packages/meshbay-client/package-lock.json @@ -13,7 +13,7 @@ "castv2-client": "^1.2.0" }, "devDependencies": { - "electron": "^42.11.1", + "electron": "^44.1.1", "electron-builder": "^26.15.3" } }, @@ -1568,9 +1568,9 @@ } }, "node_modules/electron": { - "version": "42.11.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-42.11.1.tgz", - "integrity": "sha512-mRYYjGDRWCyU+h4FU/0ruqxL/rXc+h2VCLhTb19KHu18HCUFWQAeFS/mFwnEKT/7GQCwlIHOhHie5ICLPXW6aw==", + "version": "44.1.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-44.1.1.tgz", + "integrity": "sha512-N2WCq2sbOkqQgvXJYx2lS6UiO8bF+Yr67trDnS6JKa2WxTCRQsAjGl57SUtdW9h6r5PlduBFjIhxhgd3dzv1hg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/packages/meshbay-client/package.json b/packages/meshbay-client/package.json index 7d88f5b..42af9c5 100644 --- a/packages/meshbay-client/package.json +++ b/packages/meshbay-client/package.json @@ -10,10 +10,10 @@ "scripts": { "start": "electron .", "sync-ui": "node scripts/sync-ui.js", - "dist": "npm run sync-ui && electron-builder --linux deb rpm" + "dist": "bash ../../packaging/build/build-client.sh" }, "devDependencies": { - "electron": "^42.11.1", + "electron": "^44.1.1", "electron-builder": "^26.15.3" }, "build": { @@ -22,25 +22,7 @@ "files": [ "src/**", "ui/**" - ], - "linux": { - "target": [ - "deb", - "rpm" - ], - "category": "Network", - "synopsis": "Peer-to-peer file sharing, streaming and group chat" - }, - "deb": { - "depends": [ - "python3-meshbay-common" - ] - }, - "rpm": { - "depends": [ - "python3-meshbay-common" - ] - } + ] }, "dependencies": { "bonjour-service": "^1.4.4", @@ -50,6 +32,6 @@ "protobufjs": "^7.6.5" }, "allowScripts": { - "electron@42.11.1": true + "electron@44.1.1": true } } diff --git a/packages/meshbay-hub/tests/test_desktop_shell.py b/packages/meshbay-hub/tests/test_desktop_shell.py index b82804e..f1dd399 100644 --- a/packages/meshbay-hub/tests/test_desktop_shell.py +++ b/packages/meshbay-hub/tests/test_desktop_shell.py @@ -13,6 +13,7 @@ Every assertion here corresponds to a sentence in `docs/desktop-client-v1.md` person with an installed client is what confirms the rest. """ +import json import re from pathlib import Path @@ -332,3 +333,46 @@ def test_a_chosen_folder_that_has_gone_is_not_silently_replaced(): assert "config.downloadDir && !chosen" in begin, ( "a chosen-but-missing folder falls through to the default instead of asking") assert "showSaveDialog" in begin + + +# ── one definition of the package, not two ─────────────────────────────────── + +def test_package_json_does_not_define_a_second_linux_package(): + """ + `packaging/build/` builds the client's `.deb` and `.rpm`: `build-client.sh` + runs electron-builder for `--dir` only, then the tree is assembled by hand + and `dpkg-deb`/`rpmbuild` package it from `packaging/deb/meshbay-client/ + DEBIAN/control` and `packaging/rpm/meshbay-client.spec`. + + `package.json` used to *also* declare `linux.target: [deb, rpm]` with its + own `deb.depends`/`rpm.depends`, so `npm run dist` produced a second + package under the same name — and the two had already drifted. The + electron-builder one installed to `/opt/MeshBay/meshbay-client` (against + `/opt/meshbay-client/meshbay`), and declared `Depends: + python3-meshbay-common` while naming none of the Electron runtime + libraries the real control file lists — so it would have installed + cleanly and then refused to start. + + Nothing referenced `npm run dist`, which is why nobody noticed. It now + delegates to `build-client.sh`, and this keeps the second definition from + growing back. + """ + pkg = json.loads((CLIENT / "package.json").read_text(encoding="utf-8")) + build = pkg.get("build", {}) + + for key in ("deb", "rpm", "appImage", "snap", "pacman"): + assert key not in build, ( + f"package.json's build.{key} defines packaging that " + "packaging/build/ already owns — two definitions of one package " + "drift, and the last pair already had") + + targets = build.get("linux", {}).get("target") + assert not targets, ( + f"build.linux.target is {targets!r}: electron-builder is used for " + "--dir only. A target list here makes `electron-builder` emit a " + "package that competes with the one packaging/build/ ships") + + dist = pkg.get("scripts", {}).get("dist", "") + assert "electron-builder" not in dist, ( + "the dist script builds packages with electron-builder again; it " + "should delegate to packaging/build/build-client.sh") diff --git a/packaging/build/build-client.sh b/packaging/build/build-client.sh index d42000a..7bac10c 100755 --- a/packaging/build/build-client.sh +++ b/packaging/build/build-client.sh @@ -46,6 +46,49 @@ mkdir -p "$ROOT" # --- Build the Electron app ----------------------------------------------- cd "$CLIENT" +# --- Electron: always build against the latest release -------------------- +# +# Chromium CVEs are fixed in Electron releases, and a client built against an +# old one ships those holes to every user. That is a certain harm; a build that +# breaks on a new Electron is a repairable one. So this bumps to the latest on +# every build and lets the build fail if it cannot cope — the failure is the +# signal to fix, not a reason to stay behind. +# +# It writes package.json and package-lock.json, so the build leaves the repo +# dirty on purpose: the new pin is meant to be committed. `npm audit` will not +# tell you any of this — Chromium CVEs fixed in Electron do not reliably reach +# the npm advisory database, which is why this check exists at all. +echo " checking for a newer Electron" +PINNED=$(node -p "require('./package-lock.json').packages['node_modules/electron'].version" 2>/dev/null || echo "unknown") +LATEST=$(npm view electron version 2>/dev/null || echo "") + +if [ -z "$LATEST" ]; then + echo " !! could not reach the npm registry — building against the pinned Electron $PINNED" >&2 +elif [ "$LATEST" = "$PINNED" ]; then + echo " Electron $PINNED is the latest" +else + echo "" + echo " ==> Electron $PINNED -> $LATEST" + echo "" + npm install --save-dev --ignore-scripts "electron@$LATEST" 2>&1 | tail -2 + # allowScripts pins an exact version; leave it matching so npm does not + # start refusing a script a future Electron reintroduces. + node -e " + const fs = require('node:fs'); + const p = JSON.parse(fs.readFileSync('package.json', 'utf8')); + if (p.allowScripts) { + for (const k of Object.keys(p.allowScripts)) { + if (k.startsWith('electron@')) { + delete p.allowScripts[k]; + p.allowScripts['electron@$LATEST'] = true; + } + } + fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n'); + } + " + echo " package.json and package-lock.json updated — commit them" +fi + echo " npm ci" npm ci --ignore-scripts 2>&1 | tail -3 |