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

1,094 commits

Author SHA1 Message Date
Simon Chrzanowski
3a0e79d6b4 Fuzz SBOM parsing and test concurrent project uploads
FuzzParse checks that an uploaded body never makes the inventory panic
and that every component it records has a package URL, ecosystem and
version. TestSaveProjectConcurrentUploads saves one project from eight
uploads at once and checks that each succeeds and the components of
exactly one remain.
2026-10-31 18:26:17 +01:00
Simon Chrzanowski
fd16ba1664 Let in-flight blobs finish when one fails
errgroup.WithContext cancelled the blobs being fetched as soon as one
failed. A client pull sharing one of those fetches failed with it, and the
next run had to fetch them again. A failure now only stops further blobs
from starting.
2026-10-31 18:15:11 +01:00
Simon Chrzanowski
83a018bfd4 Test that stats versions add up with orphan publish times
Covers namespaced npm and Maven PURLs, a publish time under an alias of
a package row's ecosystem, and a PURL starting with the orphan prefix,
and checks the per-ecosystem versions against GetCacheStats' total.
2026-10-31 18:09:05 +01:00
Simon Chrzanowski
f0c96e87a8 Keep the stored copy when upstream cuts a metadata document off
A body that ended before its Content-Length was read as complete in
memory: ReadMetadataSized took the transport's io.ErrUnexpectedEOF for
the end of a body shorter than its size hint. The half document was
served and cached, or failed the filter with a 502, instead of the stored
copy being served. Upstream bodies are now read through a reader that
marks their read errors, and such a failure is an upstream failure on
both paths: streamed, it no longer counts as a failure to store, which
had sent the request to the bounded in-memory path.

A stored packument whose bytes no longer match its row's digest is now
fetched again like a missing one.

Tests also cover concurrent requests sharing one fetch, client
revalidation and upstream failures with nothing cached. The stream tests
build cooldown through cooldown.NewPolicy as the server does, since a
bare cooldown.Config parses itself on first use without locking.
2026-10-31 17:50:24 +01:00
Simon Chrzanowski
11ff4cf314 Fetch an npm packument again when its stored copy is gone within the TTL
A row within its TTL was served without checking its blob, so a missing
blob failed the streamed read and the request fell back to the bounded
in-memory path. A read that finds the stored copy missing now fetches the
packument again into storage, ignoring that row, and reads it once more,
for packument, version and tarball requests.
2026-10-31 16:55:15 +01:00
Simon Chrzanowski
c4979b9e76 Count stored publish times under their ecosystem in the stats
Cooldown stores the publish time of every version it looks up, also of
packages nobody downloaded, which have no package row. The ecosystem stats
counted those versions as unattributed. They now count under the type of
their package PURL; only a PURL that can't be parsed stays unattributed.
2026-10-31 15:19:11 +01:00
simon chrzanowski
1979fb098e
Accept Swift source repository PURLs in the denylist and retention rules (#641)
* Accept Swift source repository PURLs in the denylist and retention rules

Closes #613. pkg:swift/github.com/apple/swift-nio, as SBOM tools and GHSA
write Swift packages, is resolved to its registry identity through the
upstream's /identifiers:

- Denylist entries are resolved at startup, and the proxy refuses to start
  when one can't be, since a skipped entry would let the version through.
- Retention keys are accepted at validation and kept pending. The
  retention loop resolves them before each sweep, and Swift isn't swept
  while any is pending, so a rule that keeps a package is never skipped.

The mirror's source URL helper moves to the handler as SwiftSourceURL.

* Resolve Swift source denylist entries in proxy mirror too

serve resolved source-form Swift denylist entries through the upstream,
but proxy mirror built its denylist directly, so such an entry never
matched a mirror download. Both now use server.ConfigureDenylist, and
neither runs when an entry can't be resolved.

* Apply Swift source policies to every listed identity

A Swift registry may list several identities for one source repository,
but a denylist entry or retention rule naming the repository only
covered the first. Denying pkg:swift/github.com/acme/widget@1.0.0 let
acme.widget through when the registry listed other.widget first, and a
never-evict rule cleared the cached apple.swift-nio archive when
other.swift-nio came first.

Both now cover every identity the registry lists. A retention rule that
conflicts with another rule for any of them stays pending, with none
applied. Mirroring a source PURL still downloads the first identity.
2026-10-31 11:34:05 +00:00
Simon Chrzanowski
1cadc4a7ba Compare Go main modules with their case
purl v0.2.1 keeps the case of Go module paths, so the inventory no
longer lowercases syft's mainModule. Module paths are case-sensitive:
github.com/azure/foo is a dependency of github.com/Azure/foo, not part
of it.
2026-10-31 11:33:31 +01:00
Simon Chrzanowski
7a77baf01a Keep namespace/name for Swift package URLs in the handler mapping
With purl v0.2.1, FullName returns a Swift package as its registry
identity, scope.name. The mirror splits namespace/name again to find
the scope or the source repository, so HandlerPackage keeps that form,
as mirrorTarget did before the two mappings were shared.
2026-10-31 11:33:31 +01:00
Simon Chrzanowski
c6635f3165 Merge remote-tracking branch 'origin/main' into feat/project-inventory 2026-10-31 11:29:24 +01:00
Andrew Nesbitt
3eadb3eb46
Preserve Swift and Go compatibility when upgrading PURL (#642)
* Handle Swift registry identities in cache and vulnerability APIs

* Preserve Go cache and policy behavior when upgrading PURL
2026-10-31 09:49:35 +00:00
Simon Chrzanowski
a79a58b04e Guard the fake registry's manifests in mirror tests
TestMirrorImageKeepsTagMovedByPullDuringWalk moves a tag while a blob is
served. With blobs fetched concurrently, another blob request reads the
manifest map at the same time, which the race detector caught on
Windows.
2026-10-31 08:27:39 +01:00
Simon Chrzanowski
4ae534eba3 Fetch an image's blobs concurrently when mirroring
The image mirror fetched the config and layer blobs of a manifest one
after another, so a run took as long as all layers together. It now
fetches up to three at once, as many as a Docker pull does by default.
For a Home Assistant image (550 MB in ten blobs) that would leave
mostly the time of its largest layer.
2026-10-31 07:58:51 +01:00
Simon Chrzanowski
479f26e09e Start project pruning with the project API and move enrichment routes out of serve 2026-10-30 19:29:11 +01:00
Simon Chrzanowski
9458dc84e1 Share one PURL-to-handler mapping between the mirror and the inventory
packageurl.HandlerPackage returns the ecosystem and name the handlers store
a package URL under. The mirror and the inventory both use it, which
settles where they disagreed: distribution namespaces of apk, alpm, bsd,
deb and rpm are dropped, PyPI and NuGet names use purl's comparison form,
and Maven names are group:artifact as the handler stores them, where the
mirror used group/artifact.
2026-10-30 19:29:11 +01:00
Simon Chrzanowski
04f732e147 Record APK snapshots from the document a request serves
A snapshot was recorded after the response by reading the metadata cache
again, so a refresh that replaced the cached copy in between lost the
version the request served. Record it from the served bytes before
responding instead, and compare a new snapshot with the version current
at its own time, so one recorded late keeps its place in the history.
2026-10-30 19:26:36 +01:00
Simon Chrzanowski
3ce582c733 Keep the last good Composer index when upstream sends one that doesn't parse
parseComposerUpstreamIndex now returns an error for a packages.json that
is not a JSON object or has the advisories and filter fields in the wrong
shape, and fetchUpstreamIndex passes it to the metadata cache as validate.
A malformed 200 is no longer stored: with metadata caching the stored
copy is served as when upstream fails, and without it the error keeps
the copy in memory.
2026-10-30 19:25:41 +01:00
Simon Chrzanowski
760623e617 Serve the stored npm packument on upstream 404 and refetch on a 304 for a missing blob 2026-10-30 19:25:09 +01:00
Simon Chrzanowski
6ee0ef08f1 Merge #642 (purl v0.2.1, registries v0.13.0) into feat/change-feeds 2026-10-30 19:23:28 +01:00
Simon Chrzanowski
d01d32e310 Merge remote-tracking branch 'origin/main' into feat/project-inventory
# Conflicts:
#	internal/server/dashboard.go
2026-10-30 19:22:04 +01:00
Simon Chrzanowski
d0435f6137 Merge remote-tracking branch 'origin/main' into feat/change-feeds 2026-10-30 19:21:37 +01:00
Simon Chrzanowski
f3c38bee42 Merge remote-tracking branch 'origin/main' into feat/composer-advisories 2026-10-30 19:21:32 +01:00
Simon Chrzanowski
9941d79561 Document the published container image and add a Docker health check 2026-10-30 19:19:01 +01:00
Andrew Nesbitt
f32b46b71a
Preserve Go cache and policy behavior when upgrading PURL 2026-10-30 18:02:30 +00:00
Andrew Nesbitt
ba95de17f3
Handle Swift registry identities in cache and vulnerability APIs 2026-10-30 14:41:45 +00:00
Simon Chrzanowski
ddba210a60 Serialize snapshot recording per document on Postgres
AddMetadataSnapshot takes a transaction-scoped advisory lock on the
document before its check and insert, so two replicas recording the same
version can't both read the previous digest and both insert. SQLite runs
one write at a time, so it keeps the single statement.
2026-10-30 15:31:31 +01:00
Simon Chrzanowski
53cac1fb74 Merge remote-tracking branch 'origin/main' into feat/apk-snapshots 2026-10-30 15:27:57 +01:00
Simon Chrzanowski
8e760ca26d Merge remote-tracking branch 'origin/main' into feat/npm-stream-rewrite
# Conflicts:
#	internal/handler/handler.go
2026-10-30 15:25:21 +01:00
Simon Chrzanowski
8c9e87f15f Stage fetched packuments, fall back on storage errors, stream version lookups
A fetched packument is now stored under a staging path and checked before
it replaces the cached copy, so an abbreviated one no longer overwrites a
full copy; the full copy is served as when upstream fails. A failure to
store falls back to the in-memory path, as caching is best effort there.

Requests for a single version or dist-tag and the tarball download's
cooldown and integrity lookup read the stored packument as a stream too,
keeping only the one version entry they need.
2026-10-30 15:24:18 +01:00
simon chrzanowski
cb566d5df6
Expire cooldown rewrites when a withheld version becomes available (#638)
A cached rewrite made with cooldown on stays right until a version it held
back leaves cooldown, so it now expires then instead of after a fixed
time. Handlers ask cooldown through Proxy.cooldown, which reports each
withheld version to the rewrites running at that moment. A rewrite that
held nothing back is kept for the shortest cooldown, at most a day.
2026-10-30 14:06:42 +00:00
simon chrzanowski
ce9ab47eac
Add --latest to mirror only the newest version (#631)
* Add --latest to mirror only the newest version

An unversioned PURL mirrors every version the upstream lists. With
--latest, or "latest": true in a mirror API job, only the newest is
mirrored: the highest by the ecosystem's version ordering, without
yanked or retracted versions and, unless there is nothing else,
pre-releases.

* Pick the latest version with registries.FetchLatestVersion

--latest now uses the shared policy from git-pkgs/registries: the version
the registry advertises as latest where it has one, otherwise the newest
active version by publish time. Deprecated versions are left out too, and
newestVersion and the direct vers dependency go away.
2026-10-30 13:59:52 +00:00
Simon Chrzanowski
5b57994c09 Stream npm packuments through storage when rewriting them
Closes #525. With metadata caching and the rewrite cache on, a packument
is streamed from upstream into storage and rewritten from there in two
passes: the first collects the time map, dist-tags and version names, the
second copies each kept version and rewrites its tarball URL. Neither the
packument nor its rewrite is held in memory uncompressed, so
metadata_max_size no longer limits packuments.

Both passes check the stored bytes against the digest in the cache row, so
a document replaced in between is not rewritten from mixed bytes. Documents
the stream can't handle (abbreviated, no versions object) and rewrite
errors fall back to the in-memory rewrite.
2026-10-30 14:14:10 +01:00
Simon Chrzanowski
1205fa759e Show versions held back by cooldown on the package page and in the API
Part of #617. The package page marks versions in cooldown with when they
become available, and lists a version only seen in metadata (no artifact
row) only while it is held back. /api/package returns the package's
cooldown and available_at on a held-back version.

FillVersionPublishedAt stores a publish time without overwriting one, for
the cooldown filters to call once they record the versions they hold back.
2026-10-30 13:54:24 +01:00
Simon Chrzanowski
77525b0d78 Store each snapshot recording at a path of its own
Two requests recording the same index version in the same millisecond
stored to one path, and the one whose row was not added deleted the
blob the other's row points at. The path now ends in a random suffix.

Also trims comments that restated the PR, notes in the docs that turning
snapshots off leaves them in place, and moves the git cache setup out of
serve, which lint found too long after the merge.
2026-10-30 10:26:21 +01:00
Simon Chrzanowski
77e07d4be9 Merge remote-tracking branch 'origin/main' into feat/apk-snapshots
# Conflicts:
#	internal/config/config_test.go
2026-10-30 10:23:29 +01:00
Andrew Nesbitt
0b1ca01e2c
Merge pull request #627 from git-pkgs/docs/docker-builds
Document using proxy in Docker builds
2026-10-30 09:11:59 +00:00
Andrew Nesbitt
a06b20fd00
Address Docker guide review points 2026-10-30 09:10:44 +00:00
Simon Chrzanowski
c4615ff561 Read change feeds through git-pkgs/registries
The feed readers move to registries' changes package. The proxy keeps the
cursor and moves it past the changes only once their metadata is expired,
so a failed expiry reads them again.
2026-10-30 10:09:21 +01:00
Simon Chrzanowski
fc23498c77 Merge remote-tracking branch 'origin/main' into feat/change-feeds 2026-10-30 10:06:41 +01:00
Andrew Nesbitt
cc1b8ac870
Merge pull request #608 from simonchrz/feat/mirror-cran
Mirror CRAN source packages
2026-10-30 08:59:07 +00:00
Andrew Nesbitt
63a9d9aac2
Merge remote-tracking branch 'origin/main' into feat/composer-advisories 2026-10-30 08:51:44 +00:00
Andrew Nesbitt
9babab7380
Describe archived CRAN versions as fetched unchecked 2026-10-30 08:51:35 +00:00
Andrew Nesbitt
88f22cc440
Merge pull request #615 from simonchrz/ci/monthly-minor-on-breaking
Release a new minor version when breaking changes were merged
2026-10-30 08:48:34 +00:00
Andrew Nesbitt
e09844e3d7
Merge pull request #610 from simonchrz/feat/mirror-brew
Mirror Homebrew bottles
2026-10-30 08:47:36 +00:00
Andrew Nesbitt
54ad028652
Merge pull request #629 from simonchrz/fix/cooldown-unsupported-ecosystems
Show cooldown only for ecosystems that apply it
2026-10-30 08:43:36 +00:00
Andrew Nesbitt
37ecc3d8ce
Trim BottleImage doc comment and rejoin the brew docs list 2026-10-30 08:40:35 +00:00
Andrew Nesbitt
2928b5c27f
Detect Helm's cooldown check in the handler coverage test 2026-10-30 08:36:39 +00:00
Andrew Nesbitt
195d9d31f4
Merge pull request #623 from simonchrz/feat/npm-attestations
Serve npm attestations through the proxy
2026-10-30 08:36:37 +00:00
Simon Chrzanowski
39d178f629 Expire cooldown rewrites when a withheld version becomes available
A cached rewrite made with cooldown on stays right until a version it held
back leaves cooldown, so it now expires then instead of after a fixed
time. Handlers ask cooldown through Proxy.cooldown, which reports each
withheld version to the rewrites running at that moment. A rewrite that
held nothing back is kept for the shortest cooldown, at most a day.
2026-10-30 09:33:56 +01:00
Andrew Nesbitt
e0e212942f
Trim npm attestations doc comments 2026-10-30 08:29:33 +00:00