From cd89ad313ec818e5c0f7de3f21fd6b8c1d3119dc Mon Sep 17 00:00:00 2001 From: mrdulasolutions Date: Tue, 12 May 2026 19:43:50 -0400 Subject: [PATCH] fix(sidecar/prepare-node): prefer process.execPath; reject shims MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.1.8's release tarball came out to 9.4 MB instead of the expected ~70 MB because prepare-node-binary.mjs bundled an 86 KB stub instead of the real Node binary. The script picked /opt/homebrew/bin/node on the macos-latest runner, which exists but appears to be a small launcher/shim rather than the full binary. Running the bundled sidecar would crash at startup with garbage from that file. Two complementary fixes: 1. Prefer `process.execPath` — the node interpreter actually running this script. It's by definition a real Node binary in the version the build expects. Especially reliable in CI where setup-node@v4 places node in a stable cache path and execPath resolves there. 2. Reject any candidate smaller than 10 MB with a warning. Real Node binaries are at least ~60 MB on macOS; anything in the hundreds of KB range is a shim and would produce a non-functional bundled node. Warn and skip rather than silently shipping garbage. Verified locally: now picks /usr/local/bin/node (process.execPath) and produces a 112.7 MB bundled node. The build would have shipped an 86 KB stub before this patch. Co-Authored-By: Claude Opus 4.7 --- sidecar/scripts/prepare-node-binary.mjs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sidecar/scripts/prepare-node-binary.mjs b/sidecar/scripts/prepare-node-binary.mjs index 0bc8249..9c45cbc 100644 --- a/sidecar/scripts/prepare-node-binary.mjs +++ b/sidecar/scripts/prepare-node-binary.mjs @@ -35,8 +35,14 @@ function rustTargetTriple() { } function findSystemNode() { + // Prefer the running interpreter itself — it's by definition a real, + // full Node binary in the version this build expects. Avoids the + // failure mode we hit on macos-latest GitHub runners, where + // /opt/homebrew/bin/node is an ~86 KB shim rather than the actual + // ~80 MB binary, producing a broken bundled node in the .app. const candidates = [ process.env.AOS_BUNDLED_NODE, + process.execPath, // <- the node running this very script "/opt/homebrew/bin/node", "/usr/local/bin/node", "/opt/local/bin/node", @@ -44,14 +50,23 @@ function findSystemNode() { for (const cand of candidates) { if (existsSync(cand)) { try { - statSync(cand); // confirm it's accessible + const st = statSync(cand); + // Sanity check: real Node binaries are at least 10 MB. Anything + // smaller is almost certainly a wrapper / shim / launcher and + // would produce a non-functional bundled node. + if (st.size < 10 * 1024 * 1024) { + console.warn( + `skipping ${cand}: only ${(st.size / 1024 / 1024).toFixed(1)} MB — looks like a shim, not the real node binary`, + ); + continue; + } return cand; } catch { // skip } } } - // Try `which` + // Try `which` as a last resort try { const which = execSync("command -v node").toString().trim(); if (which) return which;