Save metadata on SHA256-mismatched downloads and verify reused hash behavior

This commit is contained in:
Dariusz L
2026-09-10 00:58:35 +02:00
parent 2d1bc22909
commit 248ccea2ec
2 changed files with 37 additions and 2 deletions
+20
View File
@@ -239,6 +239,26 @@ def download_file(
error_msg = f"SHA256 mismatch: expected {expected_sha256}, got {actual_sha256}"
if bad_path:
error_msg += f"; file kept at {bad_path}"
# Use the intended filename so removing .badsha also makes
# the already computed hash available to local model info.
# Never attach the rejected file's hash to an existing model.
sidecar_model_path = bad_path if os.path.exists(dest_path) else dest_path
try:
payload = facade.build_model_resolver_metadata(
sidecar_model_path,
{"sha256": actual_sha256, "size": downloaded},
category,
)
payload.update({
"expected_sha256": expected_sha256,
"sha256_verified": False,
})
metadata_path = facade.get_model_resolver_sidecar_path(sidecar_model_path)
facade.write_json_atomic(metadata_path, payload, indent=2)
result["metadata_path"] = metadata_path
log.info(f"Metadata saved for SHA256-mismatched download: {metadata_path}")
except Exception as exc:
log.warning(f"Could not save metadata for {bad_path}: {exc}")
with download_lock:
download_progress[download_id]["status"] = "error"
download_progress[download_id]["error"] = error_msg
+17 -2
View File
@@ -371,7 +371,6 @@ class ModelResolverRobustnessTests(unittest.TestCase):
{},
),
),
patch("core.download.api.context.write_model_resolver_metadata") as write_metadata,
):
result = download_model(
"https://example.com/mismatched.safetensors",
@@ -391,7 +390,23 @@ class ModelResolverRobustnessTests(unittest.TestCase):
self.assertTrue(os.path.isfile(bad_path))
with open(bad_path, "rb") as bad_handle:
self.assertEqual(payload, bad_handle.read())
write_metadata.assert_not_called()
with open(result["metadata_path"], encoding="utf-8") as handle:
saved = json.load(handle)
actual_sha256 = hashlib.sha256(payload).hexdigest()
self.assertEqual(actual_sha256, saved["sha256"])
self.assertEqual(expected_sha256, saved["expected_sha256"])
self.assertFalse(saved["sha256_verified"])
self.assertEqual("completed", saved["hash_status"])
self.assertEqual(len(payload), saved["size"])
self.assertFalse(saved["from_civitai"])
os.replace(bad_path, model_path)
with patch("core.path_utils.hashlib.sha256", side_effect=AssertionError("must reuse saved hash")):
self.assertEqual(actual_sha256, read_completed_metadata_sha256(model_path))
from core.sources.civitai import get_model_info_for_file
with patch("core.sources.civitai.calculate_file_sha256", side_effect=AssertionError("must reuse saved hash")):
info = get_model_info_for_file(model_path, local_only=True)
self.assertEqual(actual_sha256, info["sha256"])
response.close.assert_called_once_with()
def test_base_model_mapping_fuzzy_resolution(self):