From 34d5ba2b6a27d6e383380e89a96c769ba07cf5e8 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Mon, 5 Oct 2026 12:38:34 +0800 Subject: [PATCH] fix(assemble): support single-url entries (sha-verified download) Index entries without a parts list (url + sha256 only) were assembled as empty artifacts, instant-failing every hf-publish run for them. --- scripts/assemble_release.py | 2 ++ tests/test_assemble_release.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/scripts/assemble_release.py b/scripts/assemble_release.py index 29050adb..8cbe1683 100644 --- a/scripts/assemble_release.py +++ b/scripts/assemble_release.py @@ -29,6 +29,8 @@ def _download(url: str, expected_sha: str, label: str) -> bytes: def assemble(entry: dict, out: Path, index_dir: Path | None = None) -> Path: parts = entry.get("parts") or [] chunks: list[bytes] = [] + if not parts and entry.get("url"): + chunks = [_download(entry["url"], entry.get("sha256", ""), entry["url"].rsplit("/", 1)[-1])] for p in parts: name = p["url"].rsplit("/", 1)[-1] chunks.append(_download(p["url"], p["sha256"], name)) diff --git a/tests/test_assemble_release.py b/tests/test_assemble_release.py index 0d965b18..a59104a6 100644 --- a/tests/test_assemble_release.py +++ b/tests/test_assemble_release.py @@ -59,6 +59,24 @@ def test_sha_mismatch_rejected(self): with self.assertRaisesRegex(ValueError, "sha256"): assemble(self._entry(base, self.bad_sha), out) + def test_single_url_entry_assembles_and_verifies(self): + base = self._serve(_files_handler({"x-1.0.zip": self.whole})) + d = tempfile.TemporaryDirectory() + self.addCleanup(d.cleanup) + out = Path(d.name) / "x.zip" + entry = {"url": f"{base}/x-1.0.zip", "sha256": self.sha, "filename": "x-1.0.zip"} + assemble(entry, out) + self.assertEqual(out.read_bytes(), self.whole) + + def test_single_url_entry_sha_mismatch_rejected(self): + base = self._serve(_files_handler({"x-1.0.zip": self.whole})) + d = tempfile.TemporaryDirectory() + self.addCleanup(d.cleanup) + out = Path(d.name) / "x.zip" + entry = {"url": f"{base}/x-1.0.zip", "sha256": self.bad_sha, "filename": "x-1.0.zip"} + with self.assertRaisesRegex(ValueError, "sha256"): + assemble(entry, out) + def test_part_sha_mismatch_rejected(self): parts = {"x.part-00": b"X" * 1024, "x.part-01": PART_B} base = self._serve(_files_handler(parts))