build: check for unindexed firmware deltas
What changed, and why it matters
This commit updates an internal release script that checks Blockstream Jade firmware files hosted on a Google Cloud bucket. It adds a check for 'delta' firmware files that exist on the server but are not listed in the index. If any are found, the script now logs commands to delete them and fails the check. The change is a build/release hygiene improvement, not a fix for an active exploit or a vulnerability in the device firmware itself.
No immediate user action is required. This is a release-process hardening change. Operators running the firmware-server validation script should ensure the updated script is used in CI/release workflows so unindexed delta files are caught before publication.
Security signals we found
Detection of unindexed firmware delta artifacts on release infrastructure
Script generates deletion commands for extra files and fails the release check
Prevents stale/orphaned delta files from remaining on the public firmware server
Evidence from the diff
The patch modifies release/scripts/checkfwsvr.sh, which mirrors and validates the contents of gs://jadefw.blockstream.com/bin. It introduces an EXTRA_LOG and logic to compare delta files present in ${LOCAL_DIR}/${hwdir}/deltas against delta filenames referenced in index.json. Unindexed deltas are reported with rm -f commands and cause the script to exit with an error. The script already checked for missing files; this extends it to detect extra/unindexed delta files. There is no change to firmware, cryptography, or device runtime behavior.
Changed components
release/scripts/checkfwsvr.shInspect captured patch +25 / −2
diff --git a/release/scripts/checkfwsvr.sh b/release/scripts/checkfwsvr.sh
index 0b447ad..acb9612 100755
--- a/release/scripts/checkfwsvr.sh
+++ b/release/scripts/checkfwsvr.sh
@@ -2,6 +2,7 @@
LOCAL_DIR="${1:-fwsvr_mirror}"
MISSING_LOG="missing.log"
+EXTRA_LOG="extra.log"
GCLOUD_BUCKET="gs://jadefw.blockstream.com/bin"
HWDIRS="jade jade1.1 jade2.0 jadedev jade1.1dev jade2.0dev"
@@ -29,7 +30,7 @@ gcloud storage rsync ${GCLOUD_BUCKET} ${LOCAL_DIR} --recursive --delete-unmatche
rm -f ${LOCAL_DIR}/_.gstmp
echo "Checking firmware server files, hashes and indices"
-rm -f "${MISSING_LOG}"
+rm -f "${MISSING_LOG}" "${EXTRA_LOG}"
function get_uncompressed_hash() {
# We add a gzip header to allow gzip to decompress the zlib data
@@ -40,6 +41,7 @@ function get_uncompressed_hash() {
for hwdir in ${HWDIRS}; do
for index_name in index.json LATEST BETA PREVIOUS; do
index_file="${LOCAL_DIR}/${hwdir}/${index_name}"
+ delta_file_names=""
if [ ! -f "${index_file}" ]; then
echo "Missing Index: ${index_file}" >> "${MISSING_LOG}"
fw_file_names=""
@@ -47,6 +49,8 @@ for hwdir in ${HWDIRS}; do
if [ "${index_name}" == index.json ]; then
# jq filter: <roots>/<release types>/<fw types>/<filename>
fw_file_names=$(jq -r ".[] | .[] | .[] | .filename" "${index_file}")
+ delta_file_names=$(echo ${fw_file_names} | tr ' ' '\n' | \
+ grep "^deltas/" | sed 's/^deltas\///g' | sort | uniq)
else
fw_file_names=$(cat "${index_file}")
fi
@@ -71,14 +75,33 @@ for hwdir in ${HWDIRS}; do
;;
esac
done
+
+ if [ -n "${delta_file_names}" ]; then
+ # Find delta files present in the bucket but not in the index
+ delta_files=$(ls ${LOCAL_DIR}/${hwdir}/deltas | sort | uniq)
+ diffs=$(diff <(printf "%s\n" "${delta_files}") \
+ <(printf "%s\n" "${delta_file_names}") \
+ | grep '^< ' | sed 's/^< /rm -f /g')
+ if [ -n "${diffs}" ]; then
+ echo "pushd ${LOCAL_DIR}/${hwdir}/deltas" >> "${EXTRA_LOG}"
+ printf "%s\n" "${diffs}" >> "${EXTRA_LOG}"
+ echo "popd" >> "${EXTRA_LOG}"
+ fi
+ fi
done
done
-# TODO: find files that are present but not listed in the indices
+# TODO: find firmware files that are present but not listed in index.jon
if [ -f "${MISSING_LOG}" ]; then
+ echo "ERROR: Missing files:"
cat "${MISSING_LOG}"
exit 1
fi
+if [ -f "${EXTRA_LOG}" ]; then
+ echo "ERROR: Extra files. remove with:"
+ cat "${EXTRA_LOG}"
+ exit 1
+fi
echo "ALL GOOD!"
exit 0
Why this scored 25/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.