Skip to content

Commit 825bec6

Browse files
authored
framework: close download tempfile before extracting tarball (#745)
1 parent d6844a0 commit 825bec6

1 file changed

Lines changed: 28 additions & 23 deletions

File tree

  • packages/testing/src/consensus_testing

packages/testing/src/consensus_testing/keys.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -715,29 +715,34 @@ def download_keys(scheme: str) -> None:
715715

716716
print(f"Downloading {scheme} keys from {url}...")
717717

718-
# Download to a temporary file to avoid partial-write corruption.
719-
with tempfile.NamedTemporaryFile(suffix=".tar.gz", delete=False) as tmp_file:
720-
tmp_path = Path(tmp_file.name)
721-
try:
722-
# Stream the response directly into the temp file.
723-
with urllib.request.urlopen(url) as response:
724-
shutil.copyfileobj(response, tmp_file)
725-
726-
# Remove any existing keys for this scheme before extracting.
727-
target_dir = base_dir / f"{scheme}_scheme"
728-
if target_dir.exists():
729-
shutil.rmtree(target_dir)
730-
base_dir.mkdir(parents=True, exist_ok=True)
731-
732-
# Extract the archive into the base directory.
733-
# The archive root is the scheme directory itself.
734-
with tarfile.open(tmp_path, "r:gz") as tar:
735-
tar.extractall(path=base_dir, filter="data")
736-
737-
print(f"Extracted {scheme} keys to {target_dir}/")
738-
finally:
739-
# Always clean up the temporary download file.
740-
tmp_path.unlink(missing_ok=True)
718+
# Reserve a temp path; we open it explicitly below so the writer can close
719+
# before the reader opens.
720+
tmp_fd, tmp_name = tempfile.mkstemp(suffix=".tar.gz")
721+
os.close(tmp_fd)
722+
tmp_path = Path(tmp_name)
723+
724+
try:
725+
# Close the writer before opening the reader.
726+
# Otherwise Python's userspace buffer can withhold the tail of the gzip stream.
727+
# That produces a near-end decompression failure that looks like a truncated download.
728+
with urllib.request.urlopen(url) as response, tmp_path.open("wb") as out:
729+
shutil.copyfileobj(response, out)
730+
731+
# Remove any existing keys for this scheme before extracting.
732+
target_dir = base_dir / f"{scheme}_scheme"
733+
if target_dir.exists():
734+
shutil.rmtree(target_dir)
735+
base_dir.mkdir(parents=True, exist_ok=True)
736+
737+
# Extract the archive into the base directory.
738+
# The archive root is the scheme directory itself.
739+
with tarfile.open(tmp_path, "r:gz") as tar:
740+
tar.extractall(path=base_dir, filter="data")
741+
742+
print(f"Extracted {scheme} keys to {target_dir}/")
743+
finally:
744+
# Always clean up the temporary download file.
745+
tmp_path.unlink(missing_ok=True)
741746

742747
print("Download complete!")
743748

0 commit comments

Comments
 (0)