Skip to content

ngclient: add download_target_bytes() - #2992

Open
ChrisJr404 wants to merge 1 commit into
theupdateframework:developfrom
ChrisJr404:download-target-bytes
Open

ngclient: add download_target_bytes()#2992
ChrisJr404 wants to merge 1 commit into
theupdateframework:developfrom
ChrisJr404:download-target-bytes

Conversation

@ChrisJr404

Copy link
Copy Markdown

Adds Updater.download_target_bytes(), which downloads and verifies a target and hands back the content as bytes instead of writing it to the cache dir, so callers like sigstore-python that just want the verified bytes in memory don't have to round-trip through a file.

The verification path is shared, not duplicated: I pulled the URL-building out of download_target() into a small _target_file_url() helper, and both methods then do the same _fetcher.download_file() + targetinfo.verify_length_and_hashes() against the same downloaded stream. The only difference is what happens after verification succeeds - download_target() copies to disk, download_target_bytes() reads the stream and returns it. So the length/hash checks are byte-for-byte identical between the two.

On the cache-timing concern from #1556 (re #1168): the new method deliberately does not touch the local target cache at all. It doesn't call find_cached_target(), doesn't read an existing cached file, and doesn't persist anything. Since it never consults the cache, there's no cache-hit/miss timing to leak - it always downloads and verifies. Callers who want caching keep using download_target() + find_cached_target().

One thing worth flagging: because a target's hash can't be checked until it's fully downloaded, the bytes variant buffers the whole target in memory. That's fine for the small artifacts this is aimed at, but it's not suitable for very large targets - I noted that in the docstring. The streaming/iterator idea from the issue thread would be a separate, larger API and I left it out here.

Tests in tests/test_updater_fetch_target.py, mirroring the existing download_target tests against the repository simulator:

  • test_fetch_target_bytes (dataset-driven, same three target cases): returned bytes match expected content, and nothing gets written to the cache dir (find_cached_target stays None).
  • test_invalid_target_download_bytes: hash mismatch and length mismatch both still raise RepositoryError, and nothing is persisted.

tox-equivalent locally: pytest tests/test_updater_*.py green (updater suites 27 passed / 13 subtests), black/isort clean at line-length 80, mypy clean on updater.py, pylint 9.91 (only pre-existing __init__ arg-count warnings, untouched by this change).

Fixes #1556

Add an Updater API that downloads and verifies a target and returns its
content as bytes instead of writing it into the local cache. sigstore-python
and similar callers want the verified bytes in memory and don't need the
file on disk.

The URL-building logic is pulled out into a shared _target_file_url() helper
so both download_target() and download_target_bytes() run the exact same
length/hash verification against the same downloaded stream; only the output
differs (write to disk vs return bytes).

Fixes theupdateframework#1556

Signed-off-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com>
@ChrisJr404
ChrisJr404 requested a review from a team as a code owner August 18, 2026 00:17
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.

ngclient: feature request "download target as bytes"

1 participant