diff --git a/internal/config/config.go b/internal/config/config.go index ec510d2..3dabc62 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -304,6 +304,11 @@ type UpstreamConfig struct { // Default: https://static.crates.io/crates CargoDownload string `json:"cargo_download" yaml:"cargo_download"` + // Debian is the upstream APT repository base URL. + // Example: http://archive.ubuntu.com/ubuntu would get Ubuntu. + // Default: http://deb.debian.org/debian + Debian string `json:"debian" yaml:"debian"` + // Auth configures authentication for upstream registries. // Keys are URL prefixes that are matched against request URLs. // Example: "https://npm.pkg.github.com" matches all requests to that host. @@ -378,6 +383,7 @@ func Default() *Config { GradlePluginPortal: "https://plugins.gradle.org/m2", Cargo: "https://index.crates.io", CargoDownload: "https://static.crates.io/crates", + Debian: "http://deb.debian.org/debian", }, Gradle: GradleConfig{ BuildCache: GradleBuildCacheConfig{ @@ -422,6 +428,21 @@ func Load(path string) (*Config, error) { return cfg, nil } +// setEnvString sets *dst from the named environment variable, leaving it +// untouched if the variable is unset or empty. +func setEnvString(dst *string, key string) { + if v := os.Getenv(key); v != "" { + *dst = v + } +} + +// setEnvBool is setEnvString for boolean fields, parsed via envBool. +func setEnvBool(dst *bool, key string) { + if v := os.Getenv(key); v != "" { + *dst = envBool(v) + } +} + // LoadFromEnv applies environment variable overrides to a Config. // Environment variables use the PROXY_ prefix: // - PROXY_LISTEN @@ -434,90 +455,35 @@ func Load(path string) (*Config, error) { // - PROXY_LOG_FORMAT // - PROXY_HEALTH_STORAGE_PROBE_INTERVAL func (c *Config) LoadFromEnv() { - if v := os.Getenv("PROXY_LISTEN"); v != "" { - c.Listen = v - } - if v := os.Getenv("PROXY_BASE_URL"); v != "" { - c.BaseURL = v - } - if v := os.Getenv("PROXY_UI_URL"); v != "" { - c.UIBaseURL = v - } - if v := os.Getenv("PROXY_STORAGE_URL"); v != "" { - c.Storage.URL = v - } - if v := os.Getenv("PROXY_STORAGE_PATH"); v != "" { - c.Storage.Path = v - } - if v := os.Getenv("PROXY_STORAGE_MAX_SIZE"); v != "" { - c.Storage.MaxSize = v - } - if v := os.Getenv("PROXY_STORAGE_DIRECT_SERVE"); v != "" { - c.Storage.DirectServe = envBool(v) - } - if v := os.Getenv("PROXY_STORAGE_DIRECT_SERVE_TTL"); v != "" { - c.Storage.DirectServeTTL = v - } - if v := os.Getenv("PROXY_STORAGE_DIRECT_SERVE_BASE_URL"); v != "" { - c.Storage.DirectServeBaseURL = v - } - if v := os.Getenv("PROXY_DATABASE_DRIVER"); v != "" { - c.Database.Driver = v - } - if v := os.Getenv("PROXY_DATABASE_PATH"); v != "" { - c.Database.Path = v - } - if v := os.Getenv("PROXY_DATABASE_URL"); v != "" { - c.Database.URL = v - } - if v := os.Getenv("PROXY_LOG_LEVEL"); v != "" { - c.Log.Level = v - } - if v := os.Getenv("PROXY_LOG_FORMAT"); v != "" { - c.Log.Format = v - } - if v := os.Getenv("PROXY_UPSTREAM_MAVEN"); v != "" { - c.Upstream.Maven = v - } - if v := os.Getenv("PROXY_UPSTREAM_GRADLE_PLUGIN_PORTAL"); v != "" { - c.Upstream.GradlePluginPortal = v - } - if v := os.Getenv("PROXY_COOLDOWN_DEFAULT"); v != "" { - c.Cooldown.Default = v - } - if v := os.Getenv("PROXY_CACHE_METADATA"); v != "" { - c.CacheMetadata = envBool(v) - } - if v := os.Getenv("PROXY_MIRROR_API"); v != "" { - c.MirrorAPI = envBool(v) - } - if v := os.Getenv("PROXY_METADATA_TTL"); v != "" { - c.MetadataTTL = v - } - if v := os.Getenv("PROXY_METADATA_MAX_SIZE"); v != "" { - c.MetadataMaxSize = v - } - if v := os.Getenv("PROXY_HTTP_TIMEOUT"); v != "" { - c.HTTPTimeout = v - } - if v := os.Getenv("PROXY_GRADLE_BUILD_CACHE_READ_ONLY"); v != "" { - c.Gradle.BuildCache.ReadOnly = v == "true" || v == "1" - } - if v := os.Getenv("PROXY_GRADLE_BUILD_CACHE_MAX_UPLOAD_SIZE"); v != "" { - c.Gradle.BuildCache.MaxUploadSize = v - } - if v := os.Getenv("PROXY_GRADLE_BUILD_CACHE_MAX_AGE"); v != "" { - c.Gradle.BuildCache.MaxAge = v - } - if v := os.Getenv("PROXY_GRADLE_BUILD_CACHE_MAX_SIZE"); v != "" { - c.Gradle.BuildCache.MaxSize = v - } - if v := os.Getenv("PROXY_GRADLE_BUILD_CACHE_SWEEP_INTERVAL"); v != "" { - c.Gradle.BuildCache.SweepInterval = v - } - if v := os.Getenv("PROXY_HEALTH_STORAGE_PROBE_INTERVAL"); v != "" { - c.Health.StorageProbeInterval = v - } + setEnvString(&c.Listen, "PROXY_LISTEN") + setEnvString(&c.BaseURL, "PROXY_BASE_URL") + setEnvString(&c.UIBaseURL, "PROXY_UI_URL") + setEnvString(&c.Storage.URL, "PROXY_STORAGE_URL") + setEnvString(&c.Storage.Path, "PROXY_STORAGE_PATH") + setEnvString(&c.Storage.MaxSize, "PROXY_STORAGE_MAX_SIZE") + setEnvBool(&c.Storage.DirectServe, "PROXY_STORAGE_DIRECT_SERVE") + setEnvString(&c.Storage.DirectServeTTL, "PROXY_STORAGE_DIRECT_SERVE_TTL") + setEnvString(&c.Storage.DirectServeBaseURL, "PROXY_STORAGE_DIRECT_SERVE_BASE_URL") + setEnvString(&c.Database.Driver, "PROXY_DATABASE_DRIVER") + setEnvString(&c.Database.Path, "PROXY_DATABASE_PATH") + setEnvString(&c.Database.URL, "PROXY_DATABASE_URL") + setEnvString(&c.Log.Level, "PROXY_LOG_LEVEL") + setEnvString(&c.Log.Format, "PROXY_LOG_FORMAT") + setEnvString(&c.Upstream.Maven, "PROXY_UPSTREAM_MAVEN") + setEnvString(&c.Upstream.GradlePluginPortal, "PROXY_UPSTREAM_GRADLE_PLUGIN_PORTAL") + setEnvString(&c.Upstream.Debian, "PROXY_UPSTREAM_DEBIAN") + setEnvString(&c.Cooldown.Default, "PROXY_COOLDOWN_DEFAULT") + setEnvBool(&c.CacheMetadata, "PROXY_CACHE_METADATA") + setEnvBool(&c.MirrorAPI, "PROXY_MIRROR_API") + setEnvString(&c.MetadataTTL, "PROXY_METADATA_TTL") + setEnvString(&c.MetadataMaxSize, "PROXY_METADATA_MAX_SIZE") + setEnvString(&c.HTTPTimeout, "PROXY_HTTP_TIMEOUT") + setEnvBool(&c.Gradle.BuildCache.ReadOnly, "PROXY_GRADLE_BUILD_CACHE_READ_ONLY") + setEnvString(&c.Gradle.BuildCache.MaxUploadSize, "PROXY_GRADLE_BUILD_CACHE_MAX_UPLOAD_SIZE") + setEnvString(&c.Gradle.BuildCache.MaxAge, "PROXY_GRADLE_BUILD_CACHE_MAX_AGE") + setEnvString(&c.Gradle.BuildCache.MaxSize, "PROXY_GRADLE_BUILD_CACHE_MAX_SIZE") + setEnvString(&c.Gradle.BuildCache.SweepInterval, "PROXY_GRADLE_BUILD_CACHE_SWEEP_INTERVAL") + setEnvString(&c.Health.StorageProbeInterval, "PROXY_HEALTH_STORAGE_PROBE_INTERVAL") } // validateAbsoluteURL returns an error if value is not a parseable URL with diff --git a/internal/config/config_test.go b/internal/config/config_test.go index decc18f..ef6ac90 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -37,6 +37,9 @@ func TestDefault(t *testing.T) { if cfg.Upstream.GradlePluginPortal != "https://plugins.gradle.org/m2" { t.Errorf("Upstream.GradlePluginPortal = %q, want %q", cfg.Upstream.GradlePluginPortal, "https://plugins.gradle.org/m2") } + if cfg.Upstream.Debian != "http://deb.debian.org/debian" { + t.Errorf("Upstream.Debian = %q, want %q", cfg.Upstream.Debian, "http://deb.debian.org/debian") + } } func TestValidate(t *testing.T) { @@ -273,6 +276,7 @@ func TestLoadFromEnv(t *testing.T) { t.Setenv("PROXY_LOG_LEVEL", testLevelDebug) t.Setenv("PROXY_UPSTREAM_MAVEN", "https://maven.example.com/repository/maven-public") t.Setenv("PROXY_UPSTREAM_GRADLE_PLUGIN_PORTAL", "https://plugins.example.com/m2") + t.Setenv("PROXY_UPSTREAM_DEBIAN", "http://archive.ubuntu.com/ubuntu") t.Setenv("PROXY_GRADLE_BUILD_CACHE_READ_ONLY", "true") t.Setenv("PROXY_GRADLE_BUILD_CACHE_MAX_UPLOAD_SIZE", "32MB") t.Setenv("PROXY_GRADLE_BUILD_CACHE_MAX_AGE", "12h") @@ -302,6 +306,9 @@ func TestLoadFromEnv(t *testing.T) { if cfg.Upstream.GradlePluginPortal != "https://plugins.example.com/m2" { t.Errorf("Upstream.GradlePluginPortal = %q, want %q", cfg.Upstream.GradlePluginPortal, "https://plugins.example.com/m2") } + if cfg.Upstream.Debian != "http://archive.ubuntu.com/ubuntu" { + t.Errorf("Upstream.Debian = %q, want %q", cfg.Upstream.Debian, "http://archive.ubuntu.com/ubuntu") + } if !cfg.Gradle.BuildCache.ReadOnly { t.Error("Gradle.BuildCache.ReadOnly = false, want true") } diff --git a/internal/handler/debian.go b/internal/handler/debian.go index 9a4aaab..b48f4fc 100644 --- a/internal/handler/debian.go +++ b/internal/handler/debian.go @@ -21,10 +21,13 @@ type DebianHandler struct { } // NewDebianHandler creates a new Debian/APT protocol handler. -func NewDebianHandler(proxy *Proxy, proxyURL string) *DebianHandler { +func NewDebianHandler(proxy *Proxy, proxyURL string, upstreamURL string) *DebianHandler { + if upstreamURL == "" { + upstreamURL = debianUpstream + } return &DebianHandler{ proxy: proxy, - upstreamURL: debianUpstream, + upstreamURL: strings.TrimSuffix(upstreamURL, "/"), proxyURL: strings.TrimSuffix(proxyURL, "/"), } } diff --git a/internal/handler/debian_test.go b/internal/handler/debian_test.go index dfdd326..60fa23a 100644 --- a/internal/handler/debian_test.go +++ b/internal/handler/debian_test.go @@ -18,6 +18,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", "") assertRoutesBasics(t, h.Routes(), "/dists/stable/Release", "/pool/../../../etc/passwd") } diff --git a/internal/handler/download_test.go b/internal/handler/download_test.go index 980e234..8192eeb 100644 --- a/internal/handler/download_test.go +++ b/internal/handler/download_test.go @@ -1165,7 +1165,7 @@ func TestDebianHandler_DownloadCacheMiss(t *testing.T) { ContentType: "application/vnd.debian.binary-package", } - h := NewDebianHandler(proxy, "http://localhost") + h := NewDebianHandler(proxy, "http://localhost", "") srv := httptest.NewServer(h.Routes()) defer srv.Close() diff --git a/internal/handler/notfound_ecosystems_test.go b/internal/handler/notfound_ecosystems_test.go index 3c2cecf..6f04113 100644 --- a/internal/handler/notfound_ecosystems_test.go +++ b/internal/handler/notfound_ecosystems_test.go @@ -17,7 +17,7 @@ func TestArtifactDownloadUpstreamNotFoundReturns404(t *testing.T) { handler func(p *Proxy) http.Handler }{ {"debian", "/pool/main/n/nginx/nginx_1.18.0-6_amd64.deb", - func(p *Proxy) http.Handler { return NewDebianHandler(p, "http://localhost").Routes() }}, + func(p *Proxy) http.Handler { return NewDebianHandler(p, "http://localhost", "").Routes() }}, {"rpm", "/releases/39/Everything/x86_64/os/Packages/n/nginx-1.24.0-1.fc39.x86_64.rpm", func(p *Proxy) http.Handler { return NewRPMHandler(p, "http://localhost").Routes() }}, {"nuget", "/v3-flatcontainer/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg", diff --git a/internal/server/server.go b/internal/server/server.go index 153a94c..856fe2d 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -223,7 +223,7 @@ func (s *Server) Start() error { cranHandler := handler.NewCRANHandler(proxy, s.cfg.BaseURL) juliaHandler := handler.NewJuliaHandler(proxy, s.cfg.BaseURL) containerHandler := handler.NewContainerHandler(proxy, s.cfg.BaseURL) - debianHandler := handler.NewDebianHandler(proxy, s.cfg.BaseURL) + debianHandler := handler.NewDebianHandler(proxy, s.cfg.BaseURL, s.cfg.Upstream.Debian) rpmHandler := handler.NewRPMHandler(proxy, s.cfg.BaseURL) r.Mount("/npm", http.StripPrefix("/npm", npmHandler.Routes()))