Compare commits

...

10 commits

Author SHA1 Message Date
081c30287d WIP 2026-04-19 07:16:43 -04:00
Andrew Nesbitt
f58e3552d3
Merge pull request #88 from git-pkgs/dependabot/github_actions/docker/login-action-4.1.0
Bump docker/login-action from 4.0.0 to 4.1.0
2026-04-18 20:39:56 +01:00
Andrew Nesbitt
cbec55cba4
Merge pull request #89 from git-pkgs/dependabot/github_actions/docker/build-push-action-7.1.0
Bump docker/build-push-action from 7.0.0 to 7.1.0
2026-04-18 20:39:43 +01:00
Andrew Nesbitt
da517ad8f5
Merge pull request #90 from git-pkgs/dependabot/go_modules/modernc.org/sqlite-1.48.2
Bump modernc.org/sqlite from 1.48.0 to 1.48.2
2026-04-18 20:39:32 +01:00
Andrew Nesbitt
2571b0aed5
Merge pull request #91 from git-pkgs/dependabot/go_modules/github.com/lib/pq-1.12.3
Bump github.com/lib/pq from 1.12.2 to 1.12.3
2026-04-18 20:39:20 +01:00
Andrew Nesbitt
57eb063464
Merge pull request #92 from kpfleming/apply-go-fmt
Apply 'go fmt' as suggested in CONTRIBUTING.md.
2026-04-18 20:38:05 +01:00
dependabot[bot]
59a510f3f5
Bump github.com/lib/pq from 1.12.2 to 1.12.3
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.12.2 to 1.12.3.
- [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.2...v1.12.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 15:16:53 +00:00
dependabot[bot]
35f26f4645
Bump modernc.org/sqlite from 1.48.0 to 1.48.2
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.48.0 to 1.48.2.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.48.0...v1.48.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 15:16:42 +00:00
dependabot[bot]
a1d028696d
Bump docker/build-push-action from 7.0.0 to 7.1.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](d08e5c354a...bcafcacb16)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 15:16:37 +00:00
dependabot[bot]
78325b6bf1
Bump docker/login-action from 4.0.0 to 4.1.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](b45d80f862...4907a6ddec)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 15:16:24 +00:00
15 changed files with 379 additions and 28 deletions

View file

@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Log in to the Container registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121
with:
registry: ghcr.io
username: ${{ github.actor }}
@ -38,7 +38,7 @@ jobs:
images: ghcr.io/${{ github.repository }}
- name: Build and push Docker image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f
with:
context: .
push: true

View file

@ -49,6 +49,145 @@ log:
# Log format: "text" or "json"
format: "text"
# Ecosystem support - routes and upstream repositories
#
# This section is optional, since 'include_default' in each section
# defaults to 'true' and the route map will be populated with all of
# the default routes if no configuration is provided.
ecosystem:
cargo:
include_default: true
# the default route for crates.io
# route:
# - path: /cargo
# upstream:
# - name: crates.io
# index: https://index.crates.io
# crates: https://static.crates.io/crates
composer:
include_default: true
# the default route for packagist.org
# route:
# - name: composer
# upstream:
# - name: packagist.org
# upstream: https://packagist.org
# repository: https://repo.packagist.org
conan:
include_default: true
# the default route for conan.io
# route:
# - name: conan
# upstream:
# - name: conan.io
# upstream: https://center.conan.io
conda:
include_default: true
# the default route for anaconda.org
# route:
# - name: conda
# upstream:
# - name: anaconda.org
# upstream: https://conda.anaconda.org
cran:
include_default: true
# the default route for r-project.org
# route:
# - name: cran
# upstream:
# - name: r-project.org
# upstream: https://cloud.r-project.org
debian:
include_default: true
# the default route for debian.org
# route:
# - name: debian
# upstream:
# - name: debian.org
# upstream: http://deb.debian.org/debian
gem:
include_default: true
# the default route for rubygems.org
# route:
# - name: gem
# upstream:
# - name: rubygems.org
# upstream: https://rubygems.org
go:
include_default: true
# the default route for golang.org
# route:
# - name: go
# upstream:
# - name: golang.org
# upstream: https://proxy.golang.org
hex:
include_default: true
# the default route for hex.pm
# route:
# - name: hex
# upstream:
# - name: hex.pm
# upstream: https://repo.hex.pm
maven:
include_default: true
# the default route for maven.org
# route:
# - name: maven
# upstream:
# - name: maven.org
# upstream: https://repo1.maven.org/maven2
npm:
include_default: true
# the default route for npmjs.org
# route:
# - name: npm
# upstream:
# - name: npmjs.org
# upstream: https://registry.npmjs.org
nuget:
include_default: true
# the default route for nuget.org
# route:
# - name: nuget
# upstream:
# - name: nuget.org
# upstream: https://api.nuget.org
oci:
include_default: true
# the default route for docker.io
# route:
# - name: v2
# upstream:
# - name: docker.io
# registry: https://registry-1.docker.io
# auth: https://auth.docker.io
pub:
include_default: true
# the default route for pub.dev
# route:
# - name: pub
# upstream:
# - name: pub.dev
# upstream: https://pub.dev
pypi:
include_default: true
# the default route for pypi.org
# route:
# - name: pypi
# upstream:
# - name: pypi.org
# index: https://pypi.org
# files_host: files.pythonhosted.org
rpm:
include_default: true
# the default route for fedoraproject.org
# route:
# - name: rpm
# upstream:
# - name: fedoraproject.org
# upstream: https://dl.fedoraproject.org/pub/fedora/linux
# Upstream registry URLs and authentication
upstream:
# npm registry URL

4
go.mod
View file

@ -13,7 +13,7 @@ require (
github.com/git-pkgs/vulns v0.1.4
github.com/go-chi/chi/v5 v5.2.5
github.com/jmoiron/sqlx v1.4.0
github.com/lib/pq v1.12.2
github.com/lib/pq v1.12.3
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
github.com/spdx/tools-golang v0.5.7
@ -22,7 +22,7 @@ require (
golang.org/x/sync v0.20.0
google.golang.org/protobuf v1.36.11
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.48.0
modernc.org/sqlite v1.48.2
)
require (

8
go.sum
View file

@ -432,8 +432,8 @@ github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.12.2 h1:ajJNv84limnK3aPbDIhLtcjrUbqAw/5XNdkuI6KNe/Q=
github.com/lib/pq v1.12.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE=
@ -873,8 +873,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.48.0 h1:ElZyLop3Q2mHYk5IFPPXADejZrlHu7APbpB0sF78bq4=
modernc.org/sqlite v1.48.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c=
modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

View file

@ -0,0 +1,78 @@
package cargo
import (
"fmt"
"net/url"
)
// Config configures routes
type Config struct {
IncludeDefault bool `json:"include_default" yaml:"include_default"`
Route []RouteConfig `json:"route" yaml:"route"`
}
// RouteConfig configures a route
type RouteConfig struct {
Path string `json:"path" yaml:"path"`
Upstream []UpstreamConfig `json:"upstream" yaml:"upstream"`
}
// UpstreamConfig configures an upstream (source)
type UpstreamConfig struct {
Name string `json:"name" yaml:"name"`
Index string `json:"index" yaml:"index"`
Crates string `json:"crates" yaml:"crates"`
}
// RouteDefault is the default route
var RouteDefault = RouteConfig{
Path: "/cargo",
Upstream: []UpstreamConfig{
{
Name: "crates.io",
Index: "https://index.crates.io",
Crates: "https://static.crates.io/crates",
},
},
}
func (c *Config) Validate() error {
for _, route := range c.Route {
if err := route.Validate(); err != nil {
return err
}
}
return nil
}
func (r *RouteConfig) Validate() error {
// TODO: validate Path
if len(r.Upstream) == 0 {
return fmt.Errorf("cargo route %q does not have any upstreams", r.Path)
}
if len(r.Upstream) > 1 {
return fmt.Errorf("cargo route %q has multiple upstreams; this is not yet supported", r.Path)
}
for _, upstream := range r.Upstream {
if err := upstream.Validate(); err != nil {
return err
}
}
return nil
}
func (u *UpstreamConfig) Validate() error {
if _, err := url.Parse(u.Index); err != nil {
return fmt.Errorf("cargo upstream index %q is not a valid URL", u.Index)
}
if _, err := url.Parse(u.Crates); err != nil {
return fmt.Errorf("cargo upstream crates %q is not a valid URL", u.Crates)
}
return nil
}

View file

@ -57,6 +57,8 @@ import (
"strings"
"time"
"github.com/git-pkgs/proxy/internal/config/cargo"
"github.com/git-pkgs/proxy/internal/config/debian"
"gopkg.in/yaml.v3"
)
@ -82,6 +84,9 @@ type Config struct {
// Upstream configures upstream registry URLs (optional overrides).
Upstream UpstreamConfig `json:"upstream" yaml:"upstream"`
// Ecosystem configures ecosystem routes and upstreams
Ecosystem EcosystemConfig `json:"ecosystem" yaml:"ecosystem"`
// Cooldown configures version age filtering to mitigate supply chain attacks.
Cooldown CooldownConfig `json:"cooldown" yaml:"cooldown"`
@ -239,6 +244,14 @@ func Default() *Config {
Level: "info",
Format: "text",
},
Ecosystem: EcosystemConfig{
Cargo: cargo.Config{
IncludeDefault: true,
},
Debian: debian.Config{
IncludeDefault: true,
},
},
Upstream: UpstreamConfig{
NPM: "https://registry.npmjs.org",
Cargo: "https://index.crates.io",
@ -334,6 +347,14 @@ func (c *Config) LoadFromEnv() {
// Validate checks the configuration for errors.
func (c *Config) Validate() error {
// finalize the configuration by injecting default routes if requested
if c.Ecosystem.Cargo.IncludeDefault {
c.Ecosystem.Cargo.Route = append(c.Ecosystem.Cargo.Route, cargo.RouteDefault)
}
if c.Ecosystem.Debian.IncludeDefault {
c.Ecosystem.Debian.Route = append(c.Ecosystem.Debian.Route, debian.RouteDefault)
}
if c.Listen == "" {
return fmt.Errorf("listen address is required")
}
@ -386,6 +407,13 @@ func (c *Config) Validate() error {
}
}
if err := c.Ecosystem.Cargo.Validate(); err != nil {
return err
}
if err := c.Ecosystem.Debian.Validate(); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,72 @@
package debian
import (
"fmt"
"net/url"
)
// Config configures routes
type Config struct {
IncludeDefault bool `json:"include_default" yaml:"include_default"`
Route []RouteConfig `json:"route" yaml:"route"`
}
// RouteConfig configures a route
type RouteConfig struct {
Path string `json:"path" yaml:"path"`
Upstream []UpstreamConfig `json:"upstream" yaml:"upstream"`
}
// UpstreamConfig configures an upstream (source)
type UpstreamConfig struct {
Name string `json:"name" yaml:"name"`
Upstream string `json:"upstream" yaml:"upstream"`
}
// RouteDefault is the default route
var RouteDefault = RouteConfig{
Path: "/debian",
Upstream: []UpstreamConfig{
{
Name: "debian.org",
Upstream: "http://deb.debian.org/debian",
},
},
}
func (c *Config) Validate() error {
for _, route := range c.Route {
if err := route.Validate(); err != nil {
return err
}
}
return nil
}
func (r *RouteConfig) Validate() error {
// TODO: validate Path
if len(r.Upstream) == 0 {
return fmt.Errorf("debian route %q does not have any upstreams", r.Path)
}
if len(r.Upstream) > 1 {
return fmt.Errorf("debian route %q has multiple upstreams; this is not yet supported", r.Path)
}
for _, upstream := range r.Upstream {
if err := upstream.Validate(); err != nil {
return err
}
}
return nil
}
func (u *UpstreamConfig) Validate() error {
if _, err := url.Parse(u.Upstream); err != nil {
return fmt.Errorf("debian upstream upstream %q is not a valid URL", u.Upstream)
}
return nil
}

View file

@ -0,0 +1,12 @@
package config
import (
"github.com/git-pkgs/proxy/internal/config/cargo"
"github.com/git-pkgs/proxy/internal/config/debian"
)
// Ecosystem configuration (routes and upstreams)
type EcosystemConfig struct {
Cargo cargo.Config `json:"cargo" yaml:"cargo"`
Debian debian.Config `json:"debian" yaml:"debian"`
}

View file

@ -9,13 +9,11 @@ import (
"strings"
"time"
"github.com/git-pkgs/proxy/internal/config/cargo"
"github.com/git-pkgs/purl"
)
const (
cargoUpstream = "https://index.crates.io"
cargoDownloadBase = "https://static.crates.io/crates"
cargoIndexLen1 = 1
cargoIndexLen2 = 2
cargoIndexLen3 = 3
@ -24,21 +22,27 @@ const (
// CargoHandler handles cargo registry protocol requests.
type CargoHandler struct {
proxy *Proxy
path string
indexURL string
downloadURL string
proxyURL string
}
// NewCargoHandler creates a new cargo protocol handler.
func NewCargoHandler(proxy *Proxy, proxyURL string) *CargoHandler {
func NewCargoHandler(proxy *Proxy, proxyURL string, cfg cargo.RouteConfig) *CargoHandler {
return &CargoHandler{
proxy: proxy,
indexURL: cargoUpstream,
downloadURL: cargoDownloadBase,
path: cfg.Path,
indexURL: cfg.Upstream[0].Index,
downloadURL: cfg.Upstream[0].Crates,
proxyURL: strings.TrimSuffix(proxyURL, "/"),
}
}
func (h *CargoHandler) Path() string {
return h.path
}
// Routes returns the HTTP handler for cargo requests.
// Mount this at /cargo on your router.
func (h *CargoHandler) Routes() http.Handler {
@ -71,7 +75,7 @@ type CargoConfig struct {
// handleConfig returns the registry configuration.
func (h *CargoHandler) handleConfig(w http.ResponseWriter, r *http.Request) {
config := CargoConfig{
DL: h.proxyURL + "/cargo/crates/{crate}/{version}/download",
DL: h.proxyURL + h.path + "/crates/{crate}/{version}/download",
}
w.Header().Set("Content-Type", "application/json")

View file

@ -48,6 +48,7 @@ func TestCargoBuildIndexPath(t *testing.T) {
func TestCargoConfigEndpoint(t *testing.T) {
h := &CargoHandler{
proxyURL: "http://localhost:8080",
path: "/xyzzy",
}
req := httptest.NewRequest(http.MethodGet, "/config.json", nil)
@ -64,7 +65,7 @@ func TestCargoConfigEndpoint(t *testing.T) {
t.Fatalf("failed to parse config: %v", err)
}
expectedDL := "http://localhost:8080/cargo/crates/{crate}/{version}/download"
expectedDL := "http://localhost:8080/xyzzy/crates/{crate}/{version}/download"
if config.DL != expectedDL {
t.Errorf("DL = %q, want %q", config.DL, expectedDL)
}

View file

@ -2,33 +2,39 @@ package handler
import (
"fmt"
"github.com/git-pkgs/proxy/internal/config/debian"
"net/http"
"regexp"
"strings"
)
const (
debianUpstream = "http://deb.debian.org/debian"
debMatchCount = 4 // full match + name + version + arch
debMatchCount = 4 // full match + name + version + arch
)
// DebianHandler handles APT/Debian repository protocol requests.
// It proxies requests to upstream Debian/Ubuntu repositories and caches .deb packages.
type DebianHandler struct {
proxy *Proxy
path string
upstreamURL string
proxyURL string
}
// NewDebianHandler creates a new Debian/APT protocol handler.
func NewDebianHandler(proxy *Proxy, proxyURL string) *DebianHandler {
func NewDebianHandler(proxy *Proxy, proxyURL string, cfg debian.RouteConfig) *DebianHandler {
return &DebianHandler{
proxy: proxy,
upstreamURL: debianUpstream,
path: cfg.Path,
upstreamURL: cfg.Upstream[0].Upstream,
proxyURL: strings.TrimSuffix(proxyURL, "/"),
}
}
func (h *DebianHandler) Path() string {
return h.path
}
// Routes returns the HTTP handler for Debian requests.
// Mount this at /debian on your router.
func (h *DebianHandler) Routes() http.Handler {

View file

@ -2,6 +2,7 @@ package handler
import (
"testing"
"github.com/git-pkgs/proxy/internal/config/debian"
)
func TestDebianHandler_parsePoolPath(t *testing.T) {
@ -18,6 +19,6 @@ func TestDebianHandler_parsePoolPath(t *testing.T) {
}
func TestDebianHandler_Routes(t *testing.T) {
h := NewDebianHandler(nil, "http://localhost:8080")
h := NewDebianHandler(nil, "http://localhost:8080", debian.RouteDefault)
assertRoutesBasics(t, h.Routes(), "/dists/stable/Release", "/pool/../../../etc/passwd")
}

View file

@ -10,6 +10,7 @@ import (
"testing"
"time"
"github.com/git-pkgs/proxy/internal/config/debian"
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/proxy/internal/storage"
"github.com/git-pkgs/purl"
@ -897,7 +898,7 @@ func TestDebianHandler_DownloadCacheMiss(t *testing.T) {
ContentType: "application/vnd.debian.binary-package",
}
h := NewDebianHandler(proxy, "http://localhost")
h := NewDebianHandler(proxy, "http://localhost", debian.RouteDefault)
srv := httptest.NewServer(h.Routes())
defer srv.Close()

View file

@ -170,7 +170,6 @@ func (s *Server) Start() error {
// Mount protocol handlers
npmHandler := handler.NewNPMHandler(proxy, s.cfg.BaseURL)
cargoHandler := handler.NewCargoHandler(proxy, s.cfg.BaseURL)
gemHandler := handler.NewGemHandler(proxy, s.cfg.BaseURL)
goHandler := handler.NewGoHandler(proxy, s.cfg.BaseURL)
hexHandler := handler.NewHexHandler(proxy, s.cfg.BaseURL)
@ -183,11 +182,21 @@ func (s *Server) Start() error {
condaHandler := handler.NewCondaHandler(proxy, s.cfg.BaseURL)
cranHandler := handler.NewCRANHandler(proxy, s.cfg.BaseURL)
containerHandler := handler.NewContainerHandler(proxy, s.cfg.BaseURL)
debianHandler := handler.NewDebianHandler(proxy, s.cfg.BaseURL)
rpmHandler := handler.NewRPMHandler(proxy, s.cfg.BaseURL)
for _, route := range s.cfg.Ecosystem.Cargo.Route {
routeHandler := handler.NewCargoHandler(proxy, s.cfg.BaseURL, route)
r.Mount(routeHandler.Path(), http.StripPrefix(routeHandler.Path(), routeHandler.Routes()))
s.logger.Info("mounted handler", "ecosystem", "cargo", "path", routeHandler.Path())
}
for _, route := range s.cfg.Ecosystem.Debian.Route {
routeHandler := handler.NewDebianHandler(proxy, s.cfg.BaseURL, route)
r.Mount(routeHandler.Path(), http.StripPrefix(routeHandler.Path(), routeHandler.Routes()))
s.logger.Info("mounted handler", "ecosystem", "debian", "path", routeHandler.Path())
}
r.Mount("/npm", http.StripPrefix("/npm", npmHandler.Routes()))
r.Mount("/cargo", http.StripPrefix("/cargo", cargoHandler.Routes()))
r.Mount("/gem", http.StripPrefix("/gem", gemHandler.Routes()))
r.Mount("/go", http.StripPrefix("/go", goHandler.Routes()))
r.Mount("/hex", http.StripPrefix("/hex", hexHandler.Routes()))
@ -200,7 +209,6 @@ func (s *Server) Start() error {
r.Mount("/conda", http.StripPrefix("/conda", condaHandler.Routes()))
r.Mount("/cran", http.StripPrefix("/cran", cranHandler.Routes()))
r.Mount("/v2", http.StripPrefix("/v2", containerHandler.Routes()))
r.Mount("/debian", http.StripPrefix("/debian", debianHandler.Routes()))
r.Mount("/rpm", http.StripPrefix("/rpm", rpmHandler.Routes()))
// Health, stats, and static endpoints

View file

@ -15,6 +15,7 @@ import (
"time"
"github.com/git-pkgs/proxy/internal/config"
"github.com/git-pkgs/proxy/internal/config/cargo"
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/proxy/internal/handler"
"github.com/git-pkgs/proxy/internal/storage"
@ -68,13 +69,13 @@ func newTestServer(t *testing.T) *testServer {
// Mount handlers
npmHandler := handler.NewNPMHandler(proxy, cfg.BaseURL)
cargoHandler := handler.NewCargoHandler(proxy, cfg.BaseURL)
cargoHandler := handler.NewCargoHandler(proxy, cfg.BaseURL, cargo.RouteDefault)
gemHandler := handler.NewGemHandler(proxy, cfg.BaseURL)
goHandler := handler.NewGoHandler(proxy, cfg.BaseURL)
pypiHandler := handler.NewPyPIHandler(proxy, cfg.BaseURL)
r.Mount("/npm", http.StripPrefix("/npm", npmHandler.Routes()))
r.Mount("/cargo", http.StripPrefix("/cargo", cargoHandler.Routes()))
r.Mount(cargoHandler.Path(), http.StripPrefix(cargoHandler.Path(), cargoHandler.Routes()))
r.Mount("/gem", http.StripPrefix("/gem", gemHandler.Routes()))
r.Mount("/go", http.StripPrefix("/go", goHandler.Routes()))
r.Mount("/pypi", http.StripPrefix("/pypi", pypiHandler.Routes()))