Skip to content

Validate download integrity: evict corrupt cache hits, verify downloaded sizes - #29

Merged
frigusgulo merged 1 commit into
mainfrom
26-download-integrity-validation
Jul 30, 2026
Merged

Validate download integrity: evict corrupt cache hits, verify downloaded sizes#29
frigusgulo merged 1 commit into
mainfrom
26-download-integrity-validation

Conversation

@frigusgulo

Copy link
Copy Markdown
Collaborator

Summary

Phase 2 of 3 for #26 — fixes symptom (c): truncated/corrupt downloads poisoning the local cache.

Previously a partial download (e.g. a truncated ATT.OBX.gz) was cached, "resolved" as a satisfied local dependency on every later run, and silently handed to pdp3 until someone manually found and deleted it. The cache-hit check only required the file to exist with st_size > 0, and the post-download check only rejected zero-byte files.

Changes (both in WormHole.download_one)

  1. Cache-hit validation. Existing files (including the decompressed-.gz fast path) are now validated against the sidecar _lock.json SHA-256 that DownloadPipeline writes, in strict mode. On mismatch the file and its stale sidecar are evicted and the download re-runs in the same call. Files without a sidecar keep the previous trust-if-non-empty behavior.

  2. Post-download size verification. The remote size was already fetched via fs.info() before every download but never compared afterward. Now a size mismatch deletes the partial file and retries once; a second mismatch deletes it and fails the resolution instead of caching it.

Tests

New test_download_integrity.py (10 tests, local-only — the "remote" is a file-protocol directory, so the real ConnectionPoolFactory download path is exercised):

  • truncated transfer → deleted, not cached; flaky transfer → retry succeeds
  • valid / corrupt / sidecar-less cache hits
  • gzip path incl. the exact corrupt-decompressed-cache scenario from the issue

Full local run: 422 + 43 + 35 tests pass across the three packages; ruff check/format clean.

Remaining for #26

🤖 Generated with Claude Code

Truncated or corrupt downloads could poison the local cache: a partial
file (e.g. a truncated ATT.OBX.gz) was cached, then treated as a
satisfied dependency on every later run and silently handed to pdp3
until a user manually found and deleted it.

Two changes in WormHole.download_one:

- Cache hits (including the decompressed-.gz path) are now validated
  against their sidecar lockfile SHA-256 in strict mode. On mismatch
  the file and its stale sidecar are evicted and the download re-runs
  in the same call. Files without a sidecar keep the old trust-if-
  non-empty behavior.

- Downloaded files are verified against the remote size already
  fetched via fs.info() before the transfer. On mismatch the partial
  file is deleted and the download retried once; a second mismatch
  deletes it and fails the resolution rather than caching it.

New local-only test suite exercises the real file-protocol download
path: truncated transfers (fail and retry-succeed), valid/corrupt/
sidecar-less cache hits, and the gzip decompressed-cache path.

Fixes symptom (c) of #26 (phase 2 of 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@frigusgulo
frigusgulo merged commit 4c0dfbc into main Jul 30, 2026
4 checks passed
@frigusgulo
frigusgulo deleted the 26-download-integrity-validation branch July 30, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant