fix: reject failed or incomplete downloads - #487
Conversation
c60501c to
c3ed0a7
Compare
ctrlaltf24
left a comment
There was a problem hiding this comment.
PR scope too large - rationale ambiguous.
What was the actual issue?
Why the sweeping changes?
|
Thanks for the feedback. This came from a static code scan which found that failed or interrupted downloads could be treated as valid when the server did not provide size or checksum metadata. That could allow an error response, partial transfer, or unverifiable cached file to continue into installation or execution. A failed replacement could also damage an existing valid file. The change reaches several callers because they all rely on the same download behavior and could continue after a failure. I addressed the shared failure contract rather than adding separate checks at each call site, and removed the unsafe resume path instead of adding more protocol complexity. Most of the added lines are tests covering those affected paths. I agree that the rationale should have been clearer and the review surface is large. I am happy to simplify or separate parts of the change if that would make it easier to review. |
|
I'm mostly concerned with the things that appear to be changing paths and whatnot. If the changes could be contained to logos_reuse_download that would be ideal. Sorry for coming on a little strong, but the testing required to validate this change is much higher than the slight benefit of having it. I agree for robustness this can be a good change - just trying to limit the fallout/impact. |
|
Ok, that's reasonable. I can rework this so the changes are contained within logos_reuse_download. There are two calls that would remain outside that protection. One skips logos_reuse_download when the recommended AppImage already exists. The other executes a cached updater binary before logos_reuse_download is called. Would you prefer those remain as they are or should those be updated? They're uncommon cases, but an interrupted or corrupted cached file could potentially be used before any validation runs. |
|
I don't see the changes you're speaking about in the diff. How about this: anything outside of logos_reuse_download have a comment rationalizing the change and try to keep the changes outside that scope to a minimum. Sound reasonable? |
Summary
This PR fixes a download validation failure in which an HTTP error response,
interrupted transfer, or unverifiable cached file could be accepted as a valid artifact.
Downloads now require a successful response and completed transfer before validation and
atomic publication. Cached files are reused only with matching trustworthy metadata, and
callers either receive the accepted path or stop. The change is covered by 58 deterministic
tests with no public network dependency.
Root cause
The file download path wrote directly to the final target, did not reject unsuccessful
responses before writing, and returned the same implicit value after success and caught
request failures.
Verification checked size or MD5 only when the server supplied it, then returned success
when both were absent. Resume also appended responses without requiring a valid
206response and consistent
Content-Range.Changes
200 OKresponse and finite(10, 30)second connect and read inactivitytimeouts for the affected requests.
require a fresh GET and are not cached as proof that metadata is absent.
with
os.replace().200without validators is treated as transport complete, not cryptographically verified.copies through the same staging process.
and self update callers so follow on work stops after failure.
typed failure, and remove credentials, query strings, and fragments from diagnostics.
ip.metest with mocks and a localThreadingHTTPServer.No dependency or CI configuration changes are included.
Safety properties
After this change:
artifacts;
failed; and
failed download.
Testing
Tested commit:
c3ed0a752f492d9c6cec2c59af33b553404265ffBase:
43fa3e508dce3f11a15339dd9e65a4973fc57ffcpython -m unittest -v tests.test_network— 58 of 58 passed.podman --network=none— all 58 network tests and Ruff passed.--versionand--helpsmoke tests passedwithout network access.
404,500, truncated, and unsolicited206responses whilepreserving existing targets. They also cover unsupported HEAD, metadata free GET,
restart from byte zero, sanitized diagnostics, and the recommended AppImage handoff.
deliberately corrupted cache. Manual AppImage testing preserved the target and symlink
on failure, then published and linked the accepted executable after success.
The formal
bash ./quality-gate.sh --fullrun exits1because of four known upstreambaseline unittest failures on the host and 21 existing mypy findings. The same environment
comparison found no unittest or mypy regression unique to this branch; pristine upstream
has 24 mypy findings. I have not represented the overall gate as passing.
Compatibility and limitations
reuse.
200without size or digest metadata is accepted only after normal streamcompletion, which establishes transport completion rather than cryptographic integrity.