Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 15:49:16 -05:00
Commit graph pkg-proxy/internal/handler/stale_cache_test.go
Author SHA1 Message Date
Simon Chrzanowski
2d258ddc4b Verify npm tarballs against dist.integrity
The proxy cached the first tarball upstream sent for a version without
checking it against the packument, so a tampered tarball was served to
every client after it.

- Pass the packument's dist.integrity to the existing integrity checks, so
  a fresh tarball is verified as it is stored or streamed; a mismatch is
  discarded and returns 502, or aborts the streamed response
- Record it with the cached version, so cache hits are verified against it
  through the same check as before
- Verify with integrity.Result.Verify, which accepts any digest of the
  strongest algorithm listed
- Fetch unverified as before when dist.integrity is missing or cannot be
  parsed, or the packument cannot be fetched
2026-10-14 15:40:36 +02:00
montehurd
4ce6c37bd9 Give each fetch its own storage path
Every fetch of an artifact wrote one path, so fetches with different URLs
or digests, which do not share a coalescing key, could overwrite each
other's bytes, serve the wrong ones, or delete them on a digest mismatch
while the other was about to open them.

storeArtifact now writes {ecosystem}/{name}/{version}/{fetch id}/{filename},
with a random id per fetch. Most ecosystems learn the digest only after
the fetch, and storage has no rename, so the id is the one rule that fits
all of them. Existing records keep their paths and stay readable. On a
file:// bucket, Delete now removes an emptied fetch directory, which
fileblob leaves behind, and no other directory, since another fetch may
be creating its own inside it.

A path a record stops pointing at is queued in pending_deletes rather
than deleted, since a request that read the record may still open it. A
loop deletes queued paths after max(1h, direct_serve_ttl), whether or not
max_size is set. UpsertArtifact and clears apply only if the record still
holds the path the caller read, so racing commits each queue the path
they replaced and a clear never orphans a newer commit. Eviction still
deletes inline, and counts space as freed only when the record still
pointed at what it deleted.
2026-09-23 16:14:43 -07:00
montehurd
7835f7a7a9
Discard a stale cache entry under the coalescing key (#348)
The digest-aware cache check discarded a stale entry before its caller
took the key. A slow caller could delete an entry another caller's
fetch had just committed, and everyone sharing that fetch then failed
to open it.

The check now only reports the miss. The caller running the shared
fetch discards the entry under the key, after the recheck, so one a
previous fetch refreshed is served, not deleted. The mismatch warning
fires once per refresh instead of once per request.

Swift HEAD no longer discards either, having no fetch to do it under.
It probes upstream as before, and the next GET replaces the entry.

Different digests or URLs, or no digest, use different keys and can
still collide on the storage path. That is the storage layout follow-up.
2026-09-16 08:20:27 +01:00