contrib: "set -e" behaves weird in subshells followed by OR. don't use.
What changed, and why it matters
This commit fixes a subtle shell-script bug in Electrum's build scripts. Because of how Bash handles 'set -e' inside subshells followed by '||', errors inside those build steps were silently ignored instead of stopping the build. That could let a broken or incomplete build continue, potentially producing a bad release binary. The fix removes the '|| fail' wrappers so the scripts now correctly abort on failure.
Review build logs from recent releases to confirm no prior silently-failed build steps produced artifacts. Ensure CI captures non-zero exits from these scripts. Consider adding explicit error checks or 'set -euo pipefail' consistently across build scripts. No runtime user action is required.
Security signals we found
Build-pipeline failure-handling defect
Silent ignore of build errors could lead to incomplete or tampered release artifacts
Supply-chain integrity risk if broken binaries are packaged and distributed
No direct code injection or memory corruption vulnerability
Evidence from the diff
The patch removes ‘) || fail “…”’ constructs after subshell blocks in four build scripts. In Bash, ‘set -e’ is disabled inside a subshell command list when that subshell is part of a command followed by ‘||’, so failures inside the subshell do not trigger exit. The previous code intended to catch failures with ‘|| fail’, but because the subshell itself returned success even after internal failures (due to this shell behavior), the ‘fail’ branch never ran. Removing the ‘|| fail’ wrapper restores ‘set -e’ behavior inside the subshell, causing the script to abort on the first failing command. This affects build steps for AppImage runtime, AppImage finalization, Wine PyInstaller, macOS PyInstaller, and macOS locale generation.
Changed components
contrib/build-linux/appimage/build.shcontrib/build-linux/appimage/make_appimage.shcontrib/build-wine/prepare-wine.shcontrib/osx/make_osx.shInspect captured patch +6 / −6
diff --git a/contrib/build-linux/appimage/build.sh b/contrib/build-linux/appimage/build.sh
index d986bef..8c1bfd7 100755
--- a/contrib/build-linux/appimage/build.sh
+++ b/contrib/build-linux/appimage/build.sh
@@ -50,7 +50,7 @@ else
info "not doing fresh clone."
fi
-# build the type2-runtime binary, this build step uses a separate docker container
+# build the type2-runtime binary, this build step uses a separate docker container
# defined in the type2-runtime repo (patched with type2-runtime-reproducible-build.patch)
TYPE2_RUNTIME_REPO_DIR="$PROJECT_ROOT_OR_FRESHCLONE_ROOT/contrib/build-linux/appimage/.cache/appimage/type2-runtime"
(
@@ -74,7 +74,7 @@ TYPE2_RUNTIME_REPO_DIR="$PROJECT_ROOT_OR_FRESHCLONE_ROOT/contrib/build-linux/app
rm -rf "$TYPE2_RUNTIME_REPO_DIR/out"
info "runtime build successful: $(sha256sum "$TYPE2_RUNTIME_REPO_DIR/runtime-x86_64")"
-) || fail "Failed to build type2-runtime"
+)
info "building binary..."
# check uid and maybe chown. see #8261
diff --git a/contrib/build-linux/appimage/make_appimage.sh b/contrib/build-linux/appimage/make_appimage.sh
index 6370391..061a12a 100755
--- a/contrib/build-linux/appimage/make_appimage.sh
+++ b/contrib/build-linux/appimage/make_appimage.sh
@@ -181,7 +181,7 @@ info "finalizing AppDir."
mv usr/include usr/include.tmp
delete_blacklisted
mv usr/include.tmp usr/include
-) || fail "Could not finalize AppDir"
+)
info "Copying additional libraries"
(
diff --git a/contrib/build-wine/prepare-wine.sh b/contrib/build-wine/prepare-wine.sh
index 57396e9..f9553f7 100755
--- a/contrib/build-wine/prepare-wine.sh
+++ b/contrib/build-wine/prepare-wine.sh
@@ -95,7 +95,7 @@ info "Building PyInstaller."
popd
# sanity check bootloader is there:
[[ -e "PyInstaller/bootloader/Windows-$PYINST_ARCH-intel/runw.exe" ]] || fail "Could not find runw.exe in target dir!"
-) || fail "PyInstaller build failed"
+)
info "Installing PyInstaller."
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-warn-script-location ./pyinstaller
diff --git a/contrib/osx/make_osx.sh b/contrib/osx/make_osx.sh
index 5f20324..608806c 100755
--- a/contrib/osx/make_osx.sh
+++ b/contrib/osx/make_osx.sh
@@ -117,7 +117,7 @@ PYINSTALLER_COMMIT="306d4d92580fea7be7ff2c89ba112cdc6f73fac1"
popd
# sanity check bootloader is there:
[[ -e "PyInstaller/bootloader/Darwin-64bit/runw" ]] || fail "Could not find runw in target dir!"
-) || fail "PyInstaller build failed"
+)
info "Installing PyInstaller."
python3 -m pip install --no-build-isolation --no-dependencies \
--cache-dir "$PIP_CACHE_DIR" --no-warn-script-location "$CACHEDIR/pyinstaller"
@@ -144,7 +144,7 @@ info "preparing electrum-locale."
"$CONTRIB/locale/build_cleanlocale.sh"
# we want the binary to have only compiled (.mo) locale files; not source (.po) files
rm -r "$PROJECT_ROOT/electrum/locale/locale"/*/electrum.po
-) || fail "failed generating locale"
+)
if ls "$DLL_TARGET_DIR"/libsecp256k1.*.dylib 1> /dev/null 2>&1; then
Why this scored 41/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.