test: Detect truncated download in get_previous_releases.py
What changed, and why it matters
This commit fixes a test-support script that downloads old Bitcoin Core releases. Previously, if a download was cut short (for example by a network error), the script would silently keep the incomplete file. Now it checks whether the downloaded bytes match the expected size and throws an error if they don't. This is a reliability fix in a developer/test tool, not a direct security fix in the Bitcoin software users run.
No urgent action for end users. Developers and CI maintainers should ensure this patch is applied so that previous-release test archives are validated for completeness before use. Consider also verifying checksums/signatures of downloaded releases in addition to size checks.
Security signals we found
Missing integrity check on downloaded executable archives
Silent acceptance of truncated or zero-length downloads
Test infrastructure supply-chain reliability issue
Evidence from the diff
In test/get_previous_releases.py, the download_from_url() function previously used response.getheader(‘Content-Length’, 0), defaulting to 0 when the header was missing. It also never compared progress_bytes to total_size after the loop, so truncated or zero-byte responses could be accepted. The patch removes the default (so a missing Content-Length now raises ValueError/int failure) and adds an explicit post-download size check that raises RuntimeError if fewer bytes were received than advertised. This prevents silently using incomplete release archives in test environments.
Changed components
test/get_previous_releases.pydownload_from_url() functionInspect captured patch +4 / −1
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index 0ca00ace..2afd8da6 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -122,7 +122,7 @@ def download_from_url(url, archive):
if response.status != 200:
raise RuntimeError(f"HTTP request failed with status code: {response.status}")
- total_size = int(response.getheader('Content-Length', 0))
+ total_size = int(response.getheader("Content-Length"))
progress_bytes = 0
with open(archive, 'wb') as file:
@@ -134,6 +134,9 @@ def download_from_url(url, archive):
progress_bytes += len(chunk)
progress_hook(progress_bytes, total_size)
+ if progress_bytes < total_size:
+ raise RuntimeError(f"Download incomplete: expected {total_size} bytes, got {progress_bytes} bytes")
+
print('\n', flush=True, end="") # Flush to avoid error output on the same line.
Why this scored 19/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.