diff --git a/Make.bat b/Make.bat index c4f714f5c77..09fee73b901 100644 --- a/Make.bat +++ b/Make.bat @@ -310,9 +310,33 @@ REM Main build sequence Ends ECHO Downloading Electron to %TMPDIR%... REM Get a fresh copy of electron. - REM WGET - FOR /f "tokens=*" %%i IN ('npm info electron version') DO SET "ELECTRON_VERSION=%%i" + REM Resolve the electron version from runtime\yarn.lock, NOT from the npm + REM registry and NOT from the range in runtime\package.json. The registry's + REM `latest` dist-tag lands any newly published electron release in shipped + REM binaries without review, whilst the package.json range is only a lower + REM bound, so yarn is free to resolve it to a build other than the one we + REM ship. The lockfile is the single source of truth, and `yarn info` + REM reports its resolution without touching the network or needing + REM node_modules. + REM + REM It must run inside runtime\ though: outside a yarn project, `yarn info` + REM silently falls back to querying the registry and still exits 0, so check + REM the lockfile is present first and validate what comes back. + IF NOT EXIST "%WD%\runtime\yarn.lock" ( + ECHO ERROR: %WD%\runtime\yarn.lock not found; cannot resolve the pinned Electron version. + EXIT /B 1 + ) + SET "ELECTRON_VERSION=" + PUSHD "%WD%\runtime" || EXIT /B 1 + FOR /f "delims=" %%i IN ('yarn info electron --json ^| node -e "const lines=require('fs').readFileSync(0,'utf8').split('\n').filter(Boolean);const pkg=lines.map(l=>{try{return JSON.parse(l);}catch(e){return null;}}).find(o=>o&&typeof o.value==='string'&&o.value.startsWith('electron@npm:'));const version=(pkg&&pkg.children&&pkg.children.Version)||'';process.stdout.write(/^[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?$/.test(version)?version:'');"') DO SET "ELECTRON_VERSION=%%i" + POPD + IF "%ELECTRON_VERSION%"=="" ( + ECHO ERROR: Could not resolve the pinned Electron version from %WD%\runtime\yarn.lock. + EXIT /B 1 + ) + + REM WGET :GET_NW wget https://github.com/electron/electron/releases/download/v%ELECTRON_VERSION%/electron-v%ELECTRON_VERSION%-win32-x64.zip -O "%TMPDIR%\electron-v%ELECTRON_VERSION%-win32-x64.zip" IF %ERRORLEVEL% NEQ 0 GOTO GET_NW diff --git a/pkg/linux/build-functions.sh b/pkg/linux/build-functions.sh index a98e42cbcf6..f596791bae0 100644 --- a/pkg/linux/build-functions.sh +++ b/pkg/linux/build-functions.sh @@ -202,14 +202,32 @@ _build_runtime() { ELECTRON_ARCH="arm64" fi - # Resolve the electron version from runtime/package.json, NOT from - # `npm info electron version`. The latter fetches whatever currently - # carries the `latest` dist-tag on the npm registry, which means any - # newly published electron release lands in shipped binaries without - # review. Keep the build deterministic and pinned. - ELECTRON_VERSION=$(sed -nE 's/.*"electron":[[:space:]]*"\^?([0-9.]+)".*/\1/p' "${SOURCEDIR}/runtime/package.json" | head -1) + # Resolve the electron version from runtime/yarn.lock, NOT from the npm + # registry and NOT from the range in runtime/package.json. The registry's + # `latest` dist-tag lands any newly published electron release in shipped + # binaries without review, whilst the package.json range is only a lower + # bound, so yarn is free to resolve it to a build other than the one we + # ship. The lockfile is the single source of truth, and `yarn info` reports + # its resolution without touching the network or needing node_modules. + # + # It must run inside runtime/ though: outside a yarn project, `yarn info` + # silently falls back to querying the registry and still exits 0, so check + # the lockfile is present first and validate what comes back. + if [ ! -f "${SOURCEDIR}/runtime/yarn.lock" ]; then + echo "ERROR: ${SOURCEDIR}/runtime/yarn.lock not found; cannot resolve the pinned electron version" >&2 + exit 1 + fi + + ELECTRON_VERSION=$(cd "${SOURCEDIR}/runtime" && yarn info electron --json | node -e " + const lines = require('fs').readFileSync(0, 'utf8').split('\n').filter(Boolean); + const pkg = lines.map(l => { try { return JSON.parse(l); } catch (e) { return null; } }) + .find(o => o && typeof o.value === 'string' && o.value.startsWith('electron@npm:')); + const version = (pkg && pkg.children && pkg.children.Version) || ''; + process.stdout.write(/^[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?$/.test(version) ? version : ''); + ") + if [ -z "${ELECTRON_VERSION}" ]; then - echo "ERROR: could not resolve electron version from runtime/package.json" >&2 + echo "ERROR: could not resolve the pinned electron version from ${SOURCEDIR}/runtime/yarn.lock" >&2 exit 1 fi diff --git a/pkg/mac/build-functions.sh b/pkg/mac/build-functions.sh index 50e29cdf067..51b126d483a 100644 --- a/pkg/mac/build-functions.sh +++ b/pkg/mac/build-functions.sh @@ -33,14 +33,32 @@ _build_runtime() { test -d "${BUILD_ROOT}" || mkdir "${BUILD_ROOT}" # Get a fresh copy of electron - # Resolve the electron version from runtime/package.json, NOT from - # `npm info electron version`. The latter fetches whatever currently - # carries the `latest` dist-tag on the npm registry, which means any - # newly published electron release lands in shipped binaries without - # review. Keep the build deterministic and pinned. - ELECTRON_VERSION=$(sed -nE 's/.*"electron":[[:space:]]*"\^?([0-9.]+)".*/\1/p' "${SOURCE_DIR}/runtime/package.json" | head -1) + # Resolve the electron version from runtime/yarn.lock, NOT from the npm + # registry and NOT from the range in runtime/package.json. The registry's + # `latest` dist-tag lands any newly published electron release in shipped + # binaries without review, whilst the package.json range is only a lower + # bound, so yarn is free to resolve it to a build other than the one we + # ship. The lockfile is the single source of truth, and `yarn info` reports + # its resolution without touching the network or needing node_modules. + # + # It must run inside runtime/ though: outside a yarn project, `yarn info` + # silently falls back to querying the registry and still exits 0, so check + # the lockfile is present first and validate what comes back. + if [ ! -f "${SOURCE_DIR}/runtime/yarn.lock" ]; then + echo "ERROR: ${SOURCE_DIR}/runtime/yarn.lock not found; cannot resolve the pinned electron version" >&2 + exit 1 + fi + + ELECTRON_VERSION=$(cd "${SOURCE_DIR}/runtime" && yarn info electron --json | node -e " + const lines = require('fs').readFileSync(0, 'utf8').split('\n').filter(Boolean); + const pkg = lines.map(l => { try { return JSON.parse(l); } catch (e) { return null; } }) + .find(o => o && typeof o.value === 'string' && o.value.startsWith('electron@npm:')); + const version = (pkg && pkg.children && pkg.children.Version) || ''; + process.stdout.write(/^[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?$/.test(version) ? version : ''); + ") + if [ -z "${ELECTRON_VERSION}" ]; then - echo "ERROR: could not resolve electron version from runtime/package.json" >&2 + echo "ERROR: could not resolve the pinned electron version from ${SOURCE_DIR}/runtime/yarn.lock" >&2 exit 1 fi