Commit graph

132 commits

Author SHA1 Message Date
c655399a07 Apply 'go fmt' as suggested in CONTRIBUTING.md. 2026-04-18 07:43:22 -04:00
Andrew Nesbitt
e3cc5516b5
Merge pull request #85 from git-pkgs/homebrew-readme
Add Homebrew install instructions
2026-04-13 11:07:59 +01:00
Andrew Nesbitt
50772d8947
Add Homebrew install instructions 2026-04-13 11:03:59 +01:00
Andrew Nesbitt
2816ff2414
Add LICENSE 2026-04-13 10:36:34 +01:00
Andrew Nesbitt
d3d11445c6
Merge pull request #84 from git-pkgs/cosign-signing
Sign release checksums with cosign keyless
2026-04-13 09:22:29 +01:00
Andrew Nesbitt
0c02455dc9
Sign release checksums with cosign keyless 2026-04-13 09:14:33 +01:00
Andrew Nesbitt
9849ac9f16
Merge pull request #40 from git-pkgs/mirror-feature
Add mirror command and API for selective package mirroring
2026-04-13 09:07:43 +01:00
Andrew Nesbitt
7346008aa5
Add metadata TTL and stale-while-revalidate support
Cached metadata is now served directly within a configurable TTL window
(default 5m) without contacting upstream, reducing latency and upstream
load. When upstream is unreachable and the cache is past its TTL, stale
content is served with a Warning: 110 header per RFC 7234.

New config: `metadata_ttl` (YAML) / `PROXY_METADATA_TTL` (env).
Set to "0" to always revalidate with upstream.
2026-04-13 09:01:05 +01:00
Andrew Nesbitt
c01f0a5c05
Fix metadata caching, 404 propagation, mirror progress, and registry stubs
- ProxyCached now stores upstream Last-Modified in the cache and uses it
  (along with ETag) for conditional request handling, returning 304 when
  client validators match. Adds Content-Length to cached responses.

- Handlers calling FetchOrCacheMetadata (pypi, composer, pub, nuget) now
  check for ErrUpstreamNotFound and return 404 instead of 502, matching
  the existing npm and cargo behavior.

- Mirror jobs report live progress via a periodic callback while running,
  so API polls return real counts instead of zeroed progress.

- Registry mirroring removed from CLI flags, API acceptance, README, and
  docs since every enumerator was a stub returning "not yet implemented".

- Added tests for the conditional metadata path (ETag/If-None-Match,
  Last-Modified/If-Modified-Since, 304 responses, header omission).
2026-04-13 09:01:05 +01:00
Andrew Nesbitt
47681066b5
Fix review issues in mirror feature
- Fix race where runJob could overwrite canceled state set by Cancel()
- Fix Debian ecosystem name inconsistency ("deb" -> "debian")
- Stream metadata responses when caching is disabled to avoid buffering
- Add metadata_cache table to initial schema strings for consistency
- Gate mirror API behind mirror_api config flag (disabled by default)
- Fix goconst lint in metadata_cache_test.go
2026-04-13 09:01:04 +01:00
Andrew Nesbitt
02738651ab
Fix concurrency, resource, and reliability issues in mirror
- Wire job contexts to server shutdown context so jobs are canceled on
  server stop instead of running indefinitely
- Defer context cancel in runJob so completed jobs don't leak contexts
- Cap error accumulation in progressTracker to 1000 entries to prevent
  OOM on large mirror operations with many failures
- Add panic recovery in errgroup workers to prevent process crashes
- Use defer for db.Close() in runMirror CLI to ensure cleanup on all
  error paths
2026-04-13 09:01:04 +01:00
Andrew Nesbitt
d62c42b8d7
Add mirror command and API for selective package mirroring
Add a `proxy mirror` CLI command and `/api/mirror` API endpoints that
pre-populate the cache from various input sources: individual PURLs,
SBOM files (CycloneDX and SPDX), or full registry enumeration.

The mirror reuses the existing handler.Proxy.GetOrFetchArtifact()
pipeline so cached artifacts are identical to those fetched on demand.
A bounded worker pool controls download parallelism.

Metadata caching is opt-in via `cache_metadata: true` in config (or
PROXY_CACHE_METADATA=true). The mirror command always enables it. When
enabled, upstream metadata responses are stored for offline fallback
with ETag-based conditional revalidation.

New internal/mirror package with Source interface, PURLSource,
SBOMSource, RegistrySource, and async JobStore. New metadata_cache
database table for offline metadata serving.
2026-04-13 09:01:04 +01:00
Andrew Nesbitt
7985a28839
Merge pull request #79 from git-pkgs/fix-metadata-size-limit
Fix silent truncation of large npm metadata responses
2026-04-13 08:47:31 +01:00
Andrew Nesbitt
773fe55bd9
Merge pull request #80 from git-pkgs/dependabot/go_modules/github.com/git-pkgs/vulns-0.1.4
Bump github.com/git-pkgs/vulns from 0.1.3 to 0.1.4
2026-04-10 15:42:53 +01:00
Andrew Nesbitt
d919d9ce3e
Merge pull request #82 from git-pkgs/dependabot/go_modules/modernc.org/sqlite-1.48.0
Bump modernc.org/sqlite from 1.47.0 to 1.48.0
2026-04-10 10:54:00 +01:00
dependabot[bot]
73d78c28fb
Bump github.com/git-pkgs/vulns from 0.1.3 to 0.1.4
Bumps [github.com/git-pkgs/vulns](https://github.com/git-pkgs/vulns) from 0.1.3 to 0.1.4.
- [Commits](https://github.com/git-pkgs/vulns/compare/v0.1.3...v0.1.4)

---
updated-dependencies:
- dependency-name: github.com/git-pkgs/vulns
  dependency-version: 0.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 09:53:57 +00:00
Andrew Nesbitt
7d0ac94c6c
Merge pull request #81 from git-pkgs/dependabot/go_modules/github.com/git-pkgs/enrichment-0.2.2
Bump github.com/git-pkgs/enrichment from 0.2.1 to 0.2.2
2026-04-10 10:53:21 +01:00
Andrew Nesbitt
5c4f6f3b85
Merge pull request #83 from git-pkgs/dependabot/go_modules/github.com/lib/pq-1.12.2
Bump github.com/lib/pq from 1.12.0 to 1.12.2
2026-04-10 10:52:37 +01:00
dependabot[bot]
497afdf317
Bump github.com/lib/pq from 1.12.0 to 1.12.2
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.12.0 to 1.12.2.
- [Release notes](https://github.com/lib/pq/releases)
- [Changelog](https://github.com/lib/pq/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lib/pq/compare/v1.12.0...v1.12.2)

---
updated-dependencies:
- dependency-name: github.com/lib/pq
  dependency-version: 1.12.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-09 15:24:54 +00:00
dependabot[bot]
55db8f94fc
Bump modernc.org/sqlite from 1.47.0 to 1.48.0
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.47.0 to 1.48.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.47.0...v1.48.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-09 15:24:50 +00:00
dependabot[bot]
d64fcb5b98
Bump github.com/git-pkgs/enrichment from 0.2.1 to 0.2.2
Bumps [github.com/git-pkgs/enrichment](https://github.com/git-pkgs/enrichment) from 0.2.1 to 0.2.2.
- [Commits](https://github.com/git-pkgs/enrichment/compare/v0.2.1...v0.2.2)

---
updated-dependencies:
- dependency-name: github.com/git-pkgs/enrichment
  dependency-version: 0.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-09 15:24:42 +00:00
Andrew Nesbitt
01b4e7210d
Use abbreviated npm metadata when cooldown is disabled
Request application/vnd.npm.install-v1+json from the npm registry
when cooldown filtering is not enabled. This format strips READMEs
and other bulk data, reducing drizzle-orm metadata from 92MB to 4MB.

Fall back to full metadata when cooldown is enabled since the
abbreviated format lacks the time map needed for publish-date filtering.
2026-04-08 16:12:43 +01:00
Andrew Nesbitt
8b762ffb39
Fix silent truncation of large npm metadata responses
ReadMetadata used io.LimitReader which silently truncated responses at
the size limit. For packages like drizzle-orm (~92MB metadata), this
produced invalid JSON that was served to clients.

Now returns ErrMetadataTooLarge when the limit is exceeded, and bumps
the limit from 50MB to 100MB.

Fixes #78
2026-04-08 16:02:30 +01:00
Andrew Nesbitt
94f4a7dfa6
Merge pull request #77 from kpfleming/sort-ecosystems-for-ui
Sort the ecosystems list for presentation in the UI
2026-04-07 08:45:52 +01:00
a947a7546a Sort the ecosystems list for presentation in the UI
In the page footer and the 'select' list on the packages page, the
list of ecosystems should be sorted in a predictable order.
2026-04-06 18:06:16 -04:00
Andrew Nesbitt
e1d2331ff0
Merge pull request #71 from git-pkgs/fix-composer-dist-urls
Fix composer dist URL rewriting and browse source
2026-04-06 19:26:16 +01:00
Andrew Nesbitt
e36a92433e
Clean up review feedback: use path.Ext for extension checks, remove dead getStripPrefix, add openArchive tests 2026-04-06 19:06:48 +01:00
Andrew Nesbitt
941ed51f76
Auto-detect and strip single top-level directory prefix when browsing archives
GitHub zipballs wrap all files in a repo-hash/ directory. Instead of
hardcoding prefixes per ecosystem, open the archive once to check if all
files share a single root directory and strip it automatically. The npm
package/ prefix is still handled as a special case.
2026-04-06 17:14:15 +01:00
Andrew Nesbitt
b68184cbab
Fix composer dist URL rewriting and browse source for extensionless filenames
GitHub zipball URLs end in a bare commit hash with no file extension.
rewriteDistURL now appends .zip when the filename has no extension and
the dist type is zip. expandMinifiedVersions deep copies inherited
values so in-place URL rewriting no longer corrupts shared references.
browse.go infers .zip for extensionless filenames so existing cached
artifacts can still be opened.
2026-04-06 17:07:20 +01:00
Andrew Nesbitt
bcbb883d1b
Add failing tests for composer dist URL and shared reference bugs
GitHub zipball URLs produce filenames without .zip extension, breaking
browse source. Minified version expansion shares nested map references,
causing dist URL corruption when versions inherit unchanged dist fields.
2026-04-06 17:07:20 +01:00
Andrew Nesbitt
33d99e337b
Merge pull request #72 from git-pkgs/bump-archives-v0.2.2
Bump archives to v0.2.2
2026-04-06 17:06:58 +01:00
Andrew Nesbitt
81f505757f
Bump archives to v0.2.2
Fixes duplicate directory entries in browse source for archives with
explicit directory entries (e.g. GitHub zipballs).
2026-04-06 17:00:50 +01:00
Andrew Nesbitt
7a758b9450
Remove redundant cooldown ecosystem list from README
The supported registries table already shows which ecosystems have
cooldown support. The inline list kept getting out of sync.
2026-04-06 13:27:05 +01:00
Andrew Nesbitt
3bccc01776
Merge pull request #70 from git-pkgs/add-hex-cooldown
Add cooldown support for Hex
2026-04-06 13:21:20 +01:00
Andrew Nesbitt
43a164ed72
Add cooldown support for Hex
Decode the Hex registry protobuf format, filter releases by fetching
timestamps from the Hex HTTP API (hex.pm/api/packages/{name}), and
re-encode without the original signature.

The protobuf handling uses protowire for low-level encoding/decoding
of the Signed wrapper, Package, and Release messages. Timestamps come
from the inserted_at field in the JSON API response.

Since the proxy re-encodes the payload without the original signature,
users need to disable registry signature verification.
2026-04-06 13:18:57 +01:00
Andrew Nesbitt
9708fe31a8
Merge pull request #69 from git-pkgs/add-rubygems-cooldown
Add cooldown support for RubyGems
2026-04-06 13:18:43 +01:00
Andrew Nesbitt
cb9bbbc385
Add cooldown support for RubyGems
Filter versions from the compact index (/info/{name}) by fetching
timestamps from the versions API (/api/v1/versions/{name}.json).
Both requests run concurrently to minimize latency. If the versions
API is unavailable, the compact index is proxied unfiltered.

Handles platform-specific versions (e.g. 1.0.0-java) by matching
the compact index format.
2026-04-06 13:16:26 +01:00
Andrew Nesbitt
75ff85f2f0
Add cooldown support for Conda (#68)
* Add cooldown support for Conda

Filter entries from Conda repodata.json based on the timestamp field
(milliseconds since epoch). Filters both packages and packages.conda
sections. When cooldown is disabled, repodata requests are proxied
directly without parsing.

* Update README table to mark Conda cooldown support
2026-04-06 13:16:00 +01:00
Andrew Nesbitt
70fe686953
Add cooldown support for NuGet (#67)
* Add cooldown support for NuGet

Filter versions from NuGet registration pages based on the
catalogEntry.published timestamp. Handles both RFC3339 and NuGet's
fractional-second timestamp formats. When cooldown is disabled,
registration requests are proxied directly without parsing.

* Update README table to mark NuGet cooldown support
2026-04-06 13:12:18 +01:00
Andrew Nesbitt
24d5e77443
Fix cross-device link error when running in Docker with volumes (#66)
`fileblob` creates temp files in `os.TempDir()` (`/tmp`) by default,
then uses `os.Rename` to move them to the final path. When the storage
directory is on a different filesystem (e.g. a Docker volume mount at
`/data`), the rename fails with "invalid cross-device link".

Set `no_tmp_dir=true` on file:// bucket URLs so fileblob creates temp
files next to the final destination instead.

Fixes #65
2026-04-06 13:07:31 +01:00
Andrew Nesbitt
15c133f1fa
Fix Composer minified metadata expansion and namespaced package routing (#63)
* Fix Composer minified metadata expansion and namespaced package routing

Packagist serves metadata in a minified format where only the first version
entry has all fields and subsequent entries inherit from the previous one.
The proxy was passing this through without expanding it, which meant cooldown
filtering could break the inheritance chain (losing fields like `name`) and
`~dev` sentinel markers were silently dropped.

The proxy now expands the minified format before filtering and rewriting,
ensuring every version entry is self-contained.

Web UI and API routes used single-segment chi URL params for package names,
which broke for Composer's `vendor/name` format. `/package/composer/monolog/monolog`
would match the version show route instead of the package show route.

All `/package/` and related API routes now use wildcard paths with a
`resolvePackageName` helper that tries increasingly longer path prefixes as
package names via DB lookup, correctly handling namespaced packages across
all endpoints (show, version, browse, compare, vulns).

Fixes #61, fixes #62

* Add namespaced package routing tests for all affected ecosystems

Verifies the wildcard routing handles slashes in package names for
npm (@babel/core), Go modules (github.com/stretchr/testify),
OCI images (library/nginx), Conda (conda-forge/numpy), and
Conan (zlib/1.2.13@demo/stable).

* Regenerate swagger docs after route refactor

The swagger annotations for the old per-endpoint handlers were removed
during the wildcard routing refactor. Regenerate to match current state.
2026-04-06 13:07:02 +01:00
Andrew Nesbitt
e45706d808
Track applied migrations to skip column checks on startup (#60)
* Track applied migrations to skip column checks on startup

Add a migrations table that records which migrations have been applied.
On boot, load the set of applied names in one query and only run new ones.
A fully migrated database now does 1 query instead of ~12 HasColumn/HasTable
checks.

Fresh databases created via CreateSchema record all migrations as already
applied. Old databases get the migrations table on first MigrateSchema call
and each migration is recorded after it runs.

Closes #54

* Add benchmark for MigrateSchema on fully migrated database

* Optimize MigrateSchema to single query for fully migrated databases

Skip HasTable/HasColumn checks when the migrations table already exists.
A fully migrated database now does one SELECT instead of ~12 individual
column and table checks.

* Add migration docs and link from architecture

* Add test for upgrade from fully migrated database without migrations table
2026-04-06 13:06:45 +01:00
Andrew Nesbitt
34009bad98
Lazy-load HTML templates behind sync.Once (#59)
Templates are parsed on first Render call instead of at server startup.
API-only traffic never pays the ~780µs parsing cost.

Closes #53
2026-04-06 13:06:25 +01:00
Kevin P. Fleming
ec9c437498
Correct ecosystem name in UI for Go (golang). (#64) 2026-04-05 16:20:57 +01:00
Andrew Nesbitt
beddf8357a
Fix startup message and add connectivity check for S3 storage (#57)
* Fix startup message and add connectivity check for S3 storage

When S3 storage is configured, the startup log incorrectly showed the
default local path (./cache/artifacts) instead of the actual S3 URL.
This also adds a lightweight connectivity check at startup so bad
credentials or endpoints fail immediately rather than on first request.

Add URL() and Close() to the Storage interface so all backends report
their URL and can be cleaned up properly. Rename the stats JSON field
from storage_path to storage_url. Close storage in error paths and
during graceful shutdown.

Fixes #49

* Fix Windows test assertion for file:// URL format

OpenBucket normalizes Windows paths to file:///C:/path (three slashes)
but the test expected file://C:/path (two slashes).
2026-04-03 14:06:51 +01:00
dependabot[bot]
6def2e214d
Bump actions/setup-go from 6.3.0 to 6.4.0 (#58)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.3.0 to 6.4.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](4b73464bb3...4a3601121d)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 18:26:57 +01:00
Lily Young
922d44b34e
Add Cargo cooldown support (#48)
* Add Cargo cooldown support

- Added support for cooldowns for cargo
- Added a test to test cooldowns with cargo

* Update README.md

add cargo to registry's with support for cooldowns

* Apply suggestion from @andrew

Co-authored-by: Andrew Nesbitt <andrewnez@gmail.com>
2026-04-01 18:15:07 +01:00
Andrew Nesbitt
5e04182bbd
Add upstream URL tests for all ecosystem download handlers (#51)
Adds regression test for the PyPI double-packages bug fixed in #50,
and adds fetchedURL assertions to every ecosystem that constructs
upstream download URLs (Conda, CRAN, Maven, NuGet, Conan, Debian, RPM).
2026-04-01 15:22:52 +01:00
Andrew Nesbitt
bdc246dc10
Fix container blob caching by passing auth token to fetcher (#44)
* Fix container blob caching by passing auth token to fetcher

The container handler was calling GetOrFetchArtifactFromURL without
authentication headers, causing Docker Hub to return 401. The fallback
proxyBlobWithAuth path had auth but bypassed the cache entirely.

Now passes the Bearer token through GetOrFetchArtifactFromURLWithHeaders
so blobs are both authenticated and cached.

Fixes git-pkgs/proxy#43

* Update registries to v0.4.0

Replace pre-release pseudo-version with the released v0.4.0 now that
git-pkgs/registries#13 has been merged.
2026-04-01 15:22:39 +01:00
Kevin P. Fleming
03ddad10ec
Fix paths for files.pythonhosted.org (#50)
The URLs constructed for downloading package assets from PyPI had
'packages' twice, resulting in 404s.
2026-04-01 14:58:08 +01:00