aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-03 11:25:45 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-03 11:25:45 +0200
commit75669dcc4f060733f0fcf3b6de574b8f4630d4a1 (patch)
tree4a3d1190374a3dfdc76396de26ac650dd3352a2c
parentdd671eb3647801317736327ab5b7cbfaa05d3866 (diff)
downloadmeshbay-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.json8
-rw-r--r--packages/meshbay-client/package.json26
-rw-r--r--packages/meshbay-hub/tests/test_desktop_shell.py44
-rwxr-xr-xpackaging/build/build-client.sh43
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