fix: build-docker.sh: fix --no-init usage
What changed, and why it matters
This commit fixes a build script used to create Trezor firmware inside Docker. Previously, when reusing an existing build environment, the script could silently build old source code instead of the requested branch or tag. It also now correctly resolves annotated Git tags to actual commits and stops the build if the environment setup file changed. These are reliability and supply-chain integrity fixes rather than a direct remote exploit, but a stale build could lead to shipping unintended or older firmware.
Treat as a build-integrity hardening patch. Verify that release builds using build-docker.sh with --no-init now produce artifacts matching the requested tag/commit and that CI/release workflows pick up this fix before the next firmware release.
Security signals we found
Silent stale-source build risk under --no-init
Annotated tag dereference fix prevents tag-vs-commit mismatch
Environment drift check prevents building with outdated toolchain/environment
Supply-chain/build-integrity hardening in release build script
Evidence from the diff
The patch modifies build-docker.sh in three ways: (1) it forces git rev-parse to dereference annotated tags to commits via TAG^{commit}; (2) when –no-init reuses a snapshot, it now fetches and checks out the requested COMMIT_HASH so the build does not stay pinned to the snapshot’s original commit; (3) when –no-init is used, it compares the current shell.nix against the initialized /shell.nix and aborts if the environment definition changed. The changes prevent silent source/environment mismatches during reproducible firmware builds.
Changed components
build-docker.shTrezor firmware reproducible build pipelineInspect captured patch +24 / −1
diff --git a/build-docker.sh b/build-docker.sh
index 83d27dab..45a34018 100755
--- a/build-docker.sh
+++ b/build-docker.sh
@@ -137,7 +137,7 @@ if [ -n "${DIRSUFFIX_OVERRIDE:-}" ] && [ "$OPT_BUILD_NORMAL" -eq 1 ] && [ "$OPT_
fi
TAG="$1"
-COMMIT_HASH="$(git rev-parse "$TAG")"
+COMMIT_HASH="$(git rev-parse "$TAG^{commit}")"
PRODUCTION=${PRODUCTION:-1}
if which wget > /dev/null ; then
@@ -216,6 +216,29 @@ EOF
fi # init
# append common part to script
+cat <<EOF >> "$SCRIPT_NAME"
+ # With --no-init the snapshot's checkout is pinned at the commit it was
+ # created from. Bring it to the requested commit, so that the environment can
+ # be reused when only the sources moved (e.g. a signed secmon binary was
+ # committed between the secmon and firmware builds). Toolchain changes still
+ # require a re-init.
+ if [ "\$(git rev-parse HEAD)" != "${COMMIT_HASH}" ]; then
+ echo ">>> UPDATING CHECKOUT TO $TAG (${COMMIT_HASH})"
+ git fetch --depth=1 origin "$TAG"
+ git checkout --detach "${COMMIT_HASH}"
+ fi
+EOF
+
+if [ $INIT -eq 0 ]; then
+ cat <<EOF >> "$SCRIPT_NAME"
+ if ! sed "s|./ci/|./|" shell.nix | cmp -s - /shell.nix; then
+ echo "shell.nix changed since this environment was initialized."
+ echo "Re-run without --no-init to rebuild it."
+ exit 1
+ fi
+EOF
+fi
+
cat <<EOF >> "$SCRIPT_NAME"
$GIT_CLEAN_REPO
git submodule update --init --recursive --depth 1
Why this scored 35/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.