From 4f8f63f35412367d729e9d0f6fc470cbcd3a71cd Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Wed, 4 Mar 2026 19:00:31 +0000 Subject: [PATCH 001/131] Add version cooldown to filter recently published packages Hides package versions published too recently from metadata responses, giving the community time to spot malicious releases. Configurable per-ecosystem and per-package with duration overrides. Supported for npm, PyPI, pub.dev, and Composer. --- README.md | 4 + config.example.yaml | 18 +++ docs/configuration.md | 27 +++++ internal/config/config.go | 19 ++++ internal/config/config_test.go | 56 ++++++++++ internal/cooldown/cooldown.go | 123 +++++++++++++++++++++ internal/cooldown/cooldown_test.go | 133 +++++++++++++++++++++++ internal/handler/composer.go | 28 ++++- internal/handler/composer_test.go | 104 ++++++++++++++++++ internal/handler/handler.go | 2 + internal/handler/npm.go | 77 +++++++++++++ internal/handler/npm_test.go | 113 +++++++++++++++++++ internal/handler/pub.go | 45 ++++++++ internal/handler/pub_test.go | 94 ++++++++++++++++ internal/handler/pypi.go | 169 ++++++++++++++++++++++++++--- internal/handler/pypi_test.go | 52 +++++++++ internal/server/server.go | 7 ++ 17 files changed, 1055 insertions(+), 16 deletions(-) create mode 100644 internal/cooldown/cooldown.go create mode 100644 internal/cooldown/cooldown_test.go create mode 100644 internal/handler/composer_test.go create mode 100644 internal/handler/pub_test.go diff --git a/README.md b/README.md index 7869b9b..94ab322 100644 --- a/README.md +++ b/README.md @@ -353,6 +353,10 @@ log: upstream: npm: "https://registry.npmjs.org" cargo: "https://index.crates.io" + +# Optional: hide recently published versions +cooldown: + default: "3d" ``` Run with config file: diff --git a/config.example.yaml b/config.example.yaml index 3d53483..ea17d15 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -90,3 +90,21 @@ upstream: # type: header # header_name: "X-Auth-Token" # header_value: "${MAVEN_TOKEN}" + +# Version cooldown configuration +# Hides package versions published too recently, giving the community time +# to spot malicious releases before they're pulled into projects. +# Supported durations: "7d" (days), "48h" (hours), "30m" (minutes), "0" (disabled) +cooldown: + # Global default cooldown for all ecosystems + # default: "3d" + + # Per-ecosystem overrides + # ecosystems: + # npm: "7d" + # cargo: "0" + + # Per-package overrides (keyed by PURL) + # packages: + # "pkg:npm/lodash": "0" + # "pkg:npm/@babel/core": "14d" diff --git a/docs/configuration.md b/docs/configuration.md index 8c79deb..44e1d08 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -184,6 +184,33 @@ upstream: token: "${PRIVATE_TOKEN}" ``` +## Cooldown + +The cooldown feature hides package versions published too recently, giving the community time to spot malicious releases before they reach your projects. When a version is within its cooldown period, it's stripped from metadata responses so package managers won't install it. + +```yaml +cooldown: + default: "3d" + ecosystems: + npm: "7d" + cargo: "0" + packages: + "pkg:npm/lodash": "0" + "pkg:npm/@babel/core": "14d" +``` + +| Config | Environment | Description | +|--------|-------------|-------------| +| `cooldown.default` | `PROXY_COOLDOWN_DEFAULT` | Global default cooldown | +| `cooldown.ecosystems` | - | Per-ecosystem overrides | +| `cooldown.packages` | - | Per-package overrides (keyed by PURL) | + +Durations support days (`7d`), hours (`48h`), and minutes (`30m`). Set to `0` to disable. + +Resolution order: package override, then ecosystem override, then global default. This lets you set a conservative default while exempting trusted packages. + +Currently supported for npm, PyPI, pub.dev, and Composer. These ecosystems include publish timestamps in their metadata. Other ecosystems (Go, Cargo, RubyGems) would require extra API calls and are not yet supported. + ## Docker ### SQLite with Local Storage diff --git a/internal/config/config.go b/internal/config/config.go index d5bef56..76067ae 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -80,6 +80,22 @@ type Config struct { // Upstream configures upstream registry URLs (optional overrides). Upstream UpstreamConfig `json:"upstream" yaml:"upstream"` + + // Cooldown configures version age filtering to mitigate supply chain attacks. + Cooldown CooldownConfig `json:"cooldown" yaml:"cooldown"` +} + +// CooldownConfig configures version cooldown periods. +// Versions published more recently than the cooldown are hidden from metadata responses. +type CooldownConfig struct { + // Default is the global default cooldown (e.g., "3d", "48h", "0" to disable). + Default string `json:"default" yaml:"default"` + + // Ecosystems overrides the default for specific ecosystems. + Ecosystems map[string]string `json:"ecosystems" yaml:"ecosystems"` + + // Packages overrides the cooldown for specific packages (keyed by PURL). + Packages map[string]string `json:"packages" yaml:"packages"` } // StorageConfig configures artifact storage. @@ -286,6 +302,9 @@ func (c *Config) LoadFromEnv() { if v := os.Getenv("PROXY_LOG_FORMAT"); v != "" { c.Log.Format = v } + if v := os.Getenv("PROXY_COOLDOWN_DEFAULT"); v != "" { + c.Cooldown.Default = v + } } // Validate checks the configuration for errors. diff --git a/internal/config/config_test.go b/internal/config/config_test.go index b167b53..47bacf0 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -233,6 +233,62 @@ func TestLoadFromEnv(t *testing.T) { } } +func TestLoadCooldownConfig(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "config.yaml") + + content := ` +listen: ":8080" +base_url: "http://localhost:8080" +storage: + path: "/data/cache" +database: + path: "/data/proxy.db" +cooldown: + default: "3d" + ecosystems: + npm: "7d" + cargo: "0" + packages: + "pkg:npm/lodash": "0" + "pkg:npm/@babel/core": "14d" +` + if err := os.WriteFile(path, []byte(content), 0644); err != nil { + t.Fatalf("writing config file: %v", err) + } + + cfg, err := Load(path) + if err != nil { + t.Fatalf("Load failed: %v", err) + } + + if cfg.Cooldown.Default != "3d" { + t.Errorf("Cooldown.Default = %q, want %q", cfg.Cooldown.Default, "3d") + } + if cfg.Cooldown.Ecosystems["npm"] != "7d" { + t.Errorf("Cooldown.Ecosystems[npm] = %q, want %q", cfg.Cooldown.Ecosystems["npm"], "7d") + } + if cfg.Cooldown.Ecosystems["cargo"] != "0" { + t.Errorf("Cooldown.Ecosystems[cargo] = %q, want %q", cfg.Cooldown.Ecosystems["cargo"], "0") + } + if cfg.Cooldown.Packages["pkg:npm/lodash"] != "0" { + t.Errorf("Cooldown.Packages[lodash] = %q, want %q", cfg.Cooldown.Packages["pkg:npm/lodash"], "0") + } + if cfg.Cooldown.Packages["pkg:npm/@babel/core"] != "14d" { + t.Errorf("Cooldown.Packages[@babel/core] = %q, want %q", cfg.Cooldown.Packages["pkg:npm/@babel/core"], "14d") + } +} + +func TestLoadCooldownFromEnv(t *testing.T) { + cfg := Default() + t.Setenv("PROXY_COOLDOWN_DEFAULT", "5d") + cfg.LoadFromEnv() + + if cfg.Cooldown.Default != "5d" { + t.Errorf("Cooldown.Default = %q, want %q", cfg.Cooldown.Default, "5d") + } +} + func TestLoadFileNotFound(t *testing.T) { _, err := Load("/nonexistent/config.yaml") if err == nil { diff --git a/internal/cooldown/cooldown.go b/internal/cooldown/cooldown.go new file mode 100644 index 0000000..2bb4fc6 --- /dev/null +++ b/internal/cooldown/cooldown.go @@ -0,0 +1,123 @@ +package cooldown + +import ( + "fmt" + "strconv" + "strings" + "time" +) + +// Config holds cooldown settings for version filtering. +// Cooldown hides package versions published too recently, giving the community +// time to spot malicious releases before they're pulled into projects. +type Config struct { + // Default is the global default cooldown duration (e.g., "3d", "48h"). + Default string `json:"default" yaml:"default"` + + // Ecosystems overrides the default for specific ecosystems. + // Keys are ecosystem names (e.g., "npm", "pypi"). + Ecosystems map[string]string `json:"ecosystems" yaml:"ecosystems"` + + // Packages overrides the cooldown for specific packages. + // Keys are PURLs (e.g., "pkg:npm/lodash", "pkg:npm/@babel/core"). + Packages map[string]string `json:"packages" yaml:"packages"` + + defaultDuration time.Duration + ecosystemDurations map[string]time.Duration + packageDurations map[string]time.Duration + parsed bool +} + +// parse resolves all string durations into time.Duration values. +// Called lazily on first use. +func (c *Config) parse() { + if c.parsed { + return + } + c.parsed = true + + c.defaultDuration, _ = ParseDuration(c.Default) + + c.ecosystemDurations = make(map[string]time.Duration, len(c.Ecosystems)) + for k, v := range c.Ecosystems { + d, _ := ParseDuration(v) + c.ecosystemDurations[k] = d + } + + c.packageDurations = make(map[string]time.Duration, len(c.Packages)) + for k, v := range c.Packages { + d, _ := ParseDuration(v) + c.packageDurations[k] = d + } +} + +// For returns the effective cooldown duration for a given ecosystem and package PURL. +// Resolution order: package override > ecosystem override > global default. +func (c *Config) For(ecosystem, packagePURL string) time.Duration { + c.parse() + + if d, ok := c.packageDurations[packagePURL]; ok { + return d + } + if d, ok := c.ecosystemDurations[ecosystem]; ok { + return d + } + return c.defaultDuration +} + +// IsAllowed returns true if a version with the given publish time has passed +// the cooldown period for this ecosystem/package. +func (c *Config) IsAllowed(ecosystem, packagePURL string, publishedAt time.Time) bool { + d := c.For(ecosystem, packagePURL) + if d == 0 { + return true + } + if publishedAt.IsZero() { + return true + } + return time.Since(publishedAt) >= d +} + +// Enabled returns true if any cooldown is configured. +func (c *Config) Enabled() bool { + c.parse() + if c.defaultDuration > 0 { + return true + } + for _, d := range c.ecosystemDurations { + if d > 0 { + return true + } + } + for _, d := range c.packageDurations { + if d > 0 { + return true + } + } + return false +} + +// ParseDuration parses a duration string supporting days (e.g., "3d"), +// in addition to Go's standard time.ParseDuration formats ("48h", "30m"). +// "0" means disabled (returns 0). +func ParseDuration(s string) (time.Duration, error) { + s = strings.TrimSpace(s) + if s == "" || s == "0" { + return 0, nil + } + + // Handle day suffix + if numStr, ok := strings.CutSuffix(s, "d"); ok { + days, err := strconv.ParseFloat(numStr, 64) + if err != nil { + return 0, fmt.Errorf("invalid duration %q: %w", s, err) + } + return time.Duration(days * float64(24*time.Hour)), nil + } + + d, err := time.ParseDuration(s) + if err != nil { + return 0, fmt.Errorf("invalid duration %q: %w", s, err) + } + return d, nil +} diff --git a/internal/cooldown/cooldown_test.go b/internal/cooldown/cooldown_test.go new file mode 100644 index 0000000..c366077 --- /dev/null +++ b/internal/cooldown/cooldown_test.go @@ -0,0 +1,133 @@ +package cooldown + +import ( + "testing" + "time" +) + +func TestParseDuration(t *testing.T) { + tests := []struct { + input string + want time.Duration + wantErr bool + }{ + {"", 0, false}, + {"0", 0, false}, + {"3d", 3 * 24 * time.Hour, false}, + {"7d", 7 * 24 * time.Hour, false}, + {"14d", 14 * 24 * time.Hour, false}, + {"1.5d", 36 * time.Hour, false}, + {"48h", 48 * time.Hour, false}, + {"30m", 30 * time.Minute, false}, + {"1h30m", 90 * time.Minute, false}, + {"invalid", 0, true}, + {"d", 0, true}, + {"xd", 0, true}, + } + + for _, tt := range tests { + got, err := ParseDuration(tt.input) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDuration(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr) + continue + } + if got != tt.want { + t.Errorf("ParseDuration(%q) = %v, want %v", tt.input, got, tt.want) + } + } +} + +func TestConfigFor(t *testing.T) { + c := &Config{ + Default: "3d", + Ecosystems: map[string]string{ + "npm": "7d", + "cargo": "0", + }, + Packages: map[string]string{ + "pkg:npm/lodash": "0", + "pkg:npm/@babel/core": "14d", + }, + } + + tests := []struct { + ecosystem string + packagePURL string + want time.Duration + }{ + // Package override takes priority + {"npm", "pkg:npm/lodash", 0}, + {"npm", "pkg:npm/@babel/core", 14 * 24 * time.Hour}, + // Ecosystem override + {"npm", "pkg:npm/express", 7 * 24 * time.Hour}, + {"cargo", "pkg:cargo/serde", 0}, + // Global default + {"pypi", "pkg:pypi/requests", 3 * 24 * time.Hour}, + {"pub", "pkg:pub/flutter", 3 * 24 * time.Hour}, + } + + for _, tt := range tests { + got := c.For(tt.ecosystem, tt.packagePURL) + if got != tt.want { + t.Errorf("For(%q, %q) = %v, want %v", tt.ecosystem, tt.packagePURL, got, tt.want) + } + } +} + +func TestConfigIsAllowed(t *testing.T) { + c := &Config{ + Default: "3d", + Packages: map[string]string{ + "pkg:npm/lodash": "0", + }, + } + + now := time.Now() + + tests := []struct { + name string + ecosystem string + packagePURL string + publishedAt time.Time + want bool + }{ + {"old enough", "npm", "pkg:npm/express", now.Add(-4 * 24 * time.Hour), true}, + {"too recent", "npm", "pkg:npm/express", now.Add(-1 * 24 * time.Hour), false}, + {"exactly at boundary", "npm", "pkg:npm/express", now.Add(-3 * 24 * time.Hour), true}, + {"exempt package", "npm", "pkg:npm/lodash", now.Add(-1 * time.Minute), true}, + {"zero time", "npm", "pkg:npm/express", time.Time{}, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := c.IsAllowed(tt.ecosystem, tt.packagePURL, tt.publishedAt) + if got != tt.want { + t.Errorf("IsAllowed(%q, %q, %v) = %v, want %v", + tt.ecosystem, tt.packagePURL, tt.publishedAt, got, tt.want) + } + }) + } +} + +func TestConfigEnabled(t *testing.T) { + tests := []struct { + name string + cfg Config + want bool + }{ + {"empty config", Config{}, false}, + {"default only", Config{Default: "3d"}, true}, + {"ecosystem only", Config{Ecosystems: map[string]string{"npm": "7d"}}, true}, + {"package only", Config{Packages: map[string]string{"pkg:npm/x": "1d"}}, true}, + {"all zero", Config{Default: "0", Ecosystems: map[string]string{"npm": "0"}}, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.cfg.Enabled() + if got != tt.want { + t.Errorf("Enabled() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/handler/composer.go b/internal/handler/composer.go index dd314fd..bdeceae 100644 --- a/internal/handler/composer.go +++ b/internal/handler/composer.go @@ -6,6 +6,9 @@ import ( "io" "net/http" "strings" + "time" + + "github.com/git-pkgs/purl" ) const ( @@ -124,6 +127,7 @@ func (h *ComposerHandler) handlePackageMetadata(w http.ResponseWriter, r *http.R } // rewriteMetadata rewrites dist URLs in Composer metadata to point at this proxy. +// If cooldown is enabled, versions published too recently are filtered out. func (h *ComposerHandler) rewriteMetadata(body []byte) ([]byte, error) { var metadata map[string]any if err := json.Unmarshal(body, &metadata); err != nil { @@ -141,6 +145,9 @@ func (h *ComposerHandler) rewriteMetadata(body []byte) ([]byte, error) { continue } + packagePURL := purl.MakePURLString("composer", packageName, "") + + filtered := versionList[:0] for _, v := range versionList { vmap, ok := v.(map[string]any) if !ok { @@ -148,20 +155,33 @@ func (h *ComposerHandler) rewriteMetadata(body []byte) ([]byte, error) { } version, _ := vmap["version"].(string) + + // Apply cooldown filtering + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() { + if timeStr, ok := vmap["time"].(string); ok { + if publishedAt, err := time.Parse(time.RFC3339, timeStr); err == nil { + if !h.proxy.Cooldown.IsAllowed("composer", packagePURL, publishedAt) { + h.proxy.Logger.Info("cooldown: filtering composer version", + "package", packageName, "version", version) + continue + } + } + } + } + dist, ok := vmap["dist"].(map[string]any) if !ok { + filtered = append(filtered, v) continue } // Rewrite the dist URL if url, ok := dist["url"].(string); ok && url != "" { - // Extract filename from URL filename := "package.zip" if idx := strings.LastIndex(url, "/"); idx >= 0 { filename = url[idx+1:] } - // Build new URL through our proxy parts := strings.SplitN(packageName, "/", 2) if len(parts) == 2 { newURL := fmt.Sprintf("%s/composer/files/%s/%s/%s/%s", @@ -169,7 +189,11 @@ func (h *ComposerHandler) rewriteMetadata(body []byte) ([]byte, error) { dist["url"] = newURL } } + + filtered = append(filtered, v) } + + packages[packageName] = filtered } return json.Marshal(metadata) diff --git a/internal/handler/composer_test.go b/internal/handler/composer_test.go new file mode 100644 index 0000000..567515b --- /dev/null +++ b/internal/handler/composer_test.go @@ -0,0 +1,104 @@ +package handler + +import ( + "encoding/json" + "log/slog" + "testing" + "time" + + "github.com/git-pkgs/proxy/internal/cooldown" +) + +func TestComposerRewriteMetadata(t *testing.T) { + h := &ComposerHandler{ + proxy: testProxy(), + proxyURL: "http://localhost:8080", + } + + input := `{ + "packages": { + "symfony/console": [ + { + "version": "6.0.0", + "dist": { + "url": "https://repo.packagist.org/files/symfony/console/6.0.0/abc123.zip", + "type": "zip" + } + } + ] + } + }` + + output, err := h.rewriteMetadata([]byte(input)) + if err != nil { + t.Fatalf("rewriteMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + packages := result["packages"].(map[string]any) + versions := packages["symfony/console"].([]any) + v := versions[0].(map[string]any) + dist := v["dist"].(map[string]any) + + expected := "http://localhost:8080/composer/files/symfony/console/6.0.0/abc123.zip" + if dist["url"] != expected { + t.Errorf("dist url = %q, want %q", dist["url"], expected) + } +} + +func TestComposerRewriteMetadataCooldown(t *testing.T) { + now := time.Now() + old := now.Add(-10 * 24 * time.Hour).Format(time.RFC3339) + recent := now.Add(-1 * time.Hour).Format(time.RFC3339) + + proxy := &Proxy{Logger: slog.Default()} + proxy.Cooldown = &cooldown.Config{Default: "3d"} + + h := &ComposerHandler{ + proxy: proxy, + proxyURL: "http://localhost:8080", + } + + input := `{ + "packages": { + "symfony/console": [ + { + "version": "5.0.0", + "time": "` + old + `", + "dist": {"url": "https://repo.packagist.org/5.0.0.zip", "type": "zip"} + }, + { + "version": "6.0.0", + "time": "` + recent + `", + "dist": {"url": "https://repo.packagist.org/6.0.0.zip", "type": "zip"} + } + ] + } + }` + + output, err := h.rewriteMetadata([]byte(input)) + if err != nil { + t.Fatalf("rewriteMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + packages := result["packages"].(map[string]any) + versions := packages["symfony/console"].([]any) + + if len(versions) != 1 { + t.Fatalf("expected 1 version after cooldown, got %d", len(versions)) + } + + v := versions[0].(map[string]any) + if v["version"] != "5.0.0" { + t.Errorf("expected version 5.0.0, got %v", v["version"]) + } +} diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 2d305ea..9e906b9 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -10,6 +10,7 @@ import ( "net/http" "time" + "github.com/git-pkgs/proxy/internal/cooldown" "github.com/git-pkgs/proxy/internal/database" "github.com/git-pkgs/proxy/internal/metrics" "github.com/git-pkgs/proxy/internal/storage" @@ -24,6 +25,7 @@ type Proxy struct { Fetcher fetch.FetcherInterface Resolver *fetch.Resolver Logger *slog.Logger + Cooldown *cooldown.Config } // NewProxy creates a new Proxy with the given dependencies. diff --git a/internal/handler/npm.go b/internal/handler/npm.go index b2625f1..4468d1b 100644 --- a/internal/handler/npm.go +++ b/internal/handler/npm.go @@ -6,7 +6,11 @@ import ( "io" "net/http" "net/url" + "sort" "strings" + "time" + + "github.com/git-pkgs/purl" ) const ( @@ -111,6 +115,7 @@ func (h *NPMHandler) handlePackageMetadata(w http.ResponseWriter, r *http.Reques } // rewriteMetadata rewrites tarball URLs in npm package metadata to point at this proxy. +// If cooldown is enabled, versions published too recently are filtered out. func (h *NPMHandler) rewriteMetadata(packageName string, body []byte) ([]byte, error) { var metadata map[string]any if err := json.Unmarshal(body, &metadata); err != nil { @@ -123,6 +128,46 @@ func (h *NPMHandler) rewriteMetadata(packageName string, body []byte) ([]byte, e return body, nil // No versions to rewrite } + // Apply cooldown filtering + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() { + timeMap, _ := metadata["time"].(map[string]any) + packagePURL := purl.MakePURLString("npm", packageName, "") + + for version := range versions { + if timeMap == nil { + continue + } + publishedStr, ok := timeMap[version].(string) + if !ok { + continue + } + publishedAt, err := time.Parse(time.RFC3339, publishedStr) + if err != nil { + continue + } + if !h.proxy.Cooldown.IsAllowed("npm", packagePURL, publishedAt) { + h.proxy.Logger.Info("cooldown: filtering npm version", + "package", packageName, "version", version, + "published", publishedStr) + delete(versions, version) + delete(timeMap, version) + } + } + + // Update dist-tags.latest if it was filtered + if distTags, ok := metadata["dist-tags"].(map[string]any); ok { + if latest, ok := distTags["latest"].(string); ok { + if _, exists := versions[latest]; !exists { + // Find newest remaining version from the time map + newLatest := h.findNewestVersion(versions, timeMap) + if newLatest != "" { + distTags["latest"] = newLatest + } + } + } + } + } + for version, vdata := range versions { vmap, ok := vdata.(map[string]any) if !ok { @@ -155,6 +200,38 @@ func (h *NPMHandler) rewriteMetadata(packageName string, body []byte) ([]byte, e return json.Marshal(metadata) } +// findNewestVersion returns the version string with the most recent timestamp +// from the remaining versions, using the time map. +func (h *NPMHandler) findNewestVersion(versions map[string]any, timeMap map[string]any) string { + if timeMap == nil { + return "" + } + + type versionTime struct { + version string + t time.Time + } + + var vts []versionTime + for v := range versions { + if ts, ok := timeMap[v].(string); ok { + if t, err := time.Parse(time.RFC3339, ts); err == nil { + vts = append(vts, versionTime{v, t}) + } + } + } + + if len(vts) == 0 { + return "" + } + + sort.Slice(vts, func(i, j int) bool { + return vts[i].t.After(vts[j].t) + }) + + return vts[0].version +} + // handleDownload serves a package tarball, fetching and caching from upstream if needed. func (h *NPMHandler) handleDownload(w http.ResponseWriter, r *http.Request) { packageName, filename := h.parseDownloadPath(r.URL.Path) diff --git a/internal/handler/npm_test.go b/internal/handler/npm_test.go index 7d2db00..5012f53 100644 --- a/internal/handler/npm_test.go +++ b/internal/handler/npm_test.go @@ -6,6 +6,9 @@ import ( "net/http" "net/http/httptest" "testing" + "time" + + "github.com/git-pkgs/proxy/internal/cooldown" ) func testProxy() *Proxy { @@ -177,6 +180,116 @@ func TestNPMHandlerMetadataProxy(t *testing.T) { } } +func TestNPMRewriteMetadataCooldown(t *testing.T) { + now := time.Now() + old := now.Add(-10 * 24 * time.Hour).Format(time.RFC3339) + recent := now.Add(-1 * time.Hour).Format(time.RFC3339) + + proxy := testProxy() + proxy.Cooldown = &cooldown.Config{Default: "3d"} + + h := &NPMHandler{ + proxy: proxy, + proxyURL: "http://localhost:8080", + } + + input := `{ + "name": "testpkg", + "dist-tags": {"latest": "2.0.0"}, + "time": { + "1.0.0": "` + old + `", + "2.0.0": "` + recent + `" + }, + "versions": { + "1.0.0": { + "name": "testpkg", + "version": "1.0.0", + "dist": { + "tarball": "https://registry.npmjs.org/testpkg/-/testpkg-1.0.0.tgz" + } + }, + "2.0.0": { + "name": "testpkg", + "version": "2.0.0", + "dist": { + "tarball": "https://registry.npmjs.org/testpkg/-/testpkg-2.0.0.tgz" + } + } + } + }` + + output, err := h.rewriteMetadata("testpkg", []byte(input)) + if err != nil { + t.Fatalf("rewriteMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + versions := result["versions"].(map[string]any) + + // Old version should remain + if _, ok := versions["1.0.0"]; !ok { + t.Error("version 1.0.0 should not be filtered") + } + + // Recent version should be filtered + if _, ok := versions["2.0.0"]; ok { + t.Error("version 2.0.0 should be filtered by cooldown") + } + + // dist-tags.latest should be updated to 1.0.0 + distTags := result["dist-tags"].(map[string]any) + if distTags["latest"] != "1.0.0" { + t.Errorf("dist-tags.latest = %q, want %q", distTags["latest"], "1.0.0") + } +} + +func TestNPMRewriteMetadataCooldownExemptPackage(t *testing.T) { + now := time.Now() + recent := now.Add(-1 * time.Hour).Format(time.RFC3339) + + proxy := testProxy() + proxy.Cooldown = &cooldown.Config{ + Default: "3d", + Packages: map[string]string{"pkg:npm/testpkg": "0"}, + } + + h := &NPMHandler{ + proxy: proxy, + proxyURL: "http://localhost:8080", + } + + input := `{ + "name": "testpkg", + "time": {"1.0.0": "` + recent + `"}, + "versions": { + "1.0.0": { + "name": "testpkg", + "version": "1.0.0", + "dist": {"tarball": "https://registry.npmjs.org/testpkg/-/testpkg-1.0.0.tgz"} + } + } + }` + + output, err := h.rewriteMetadata("testpkg", []byte(input)) + if err != nil { + t.Fatalf("rewriteMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + versions := result["versions"].(map[string]any) + if _, ok := versions["1.0.0"]; !ok { + t.Error("exempt package version should not be filtered") + } +} + func TestNPMHandlerMetadataNotFound(t *testing.T) { upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) diff --git a/internal/handler/pub.go b/internal/handler/pub.go index 154dc45..9ae0b70 100644 --- a/internal/handler/pub.go +++ b/internal/handler/pub.go @@ -6,6 +6,9 @@ import ( "io" "net/http" "strings" + "time" + + "github.com/git-pkgs/purl" ) const ( @@ -127,6 +130,7 @@ func (h *PubHandler) handlePackageMetadata(w http.ResponseWriter, r *http.Reques } // rewriteMetadata rewrites archive_url fields to point at this proxy. +// If cooldown is enabled, versions published too recently are filtered out. func (h *PubHandler) rewriteMetadata(name string, body []byte) ([]byte, error) { var metadata map[string]any if err := json.Unmarshal(body, &metadata); err != nil { @@ -139,6 +143,10 @@ func (h *PubHandler) rewriteMetadata(name string, body []byte) ([]byte, error) { return body, nil } + packagePURL := purl.MakePURLString("pub", name, "") + + // Filter and rewrite versions + filtered := versions[:0] for _, vdata := range versions { vmap, ok := vdata.(map[string]any) if !ok { @@ -150,13 +158,50 @@ func (h *PubHandler) rewriteMetadata(name string, body []byte) ([]byte, error) { continue } + // Apply cooldown filtering + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() { + if publishedStr, ok := vmap["published"].(string); ok { + if publishedAt, err := time.Parse(time.RFC3339, publishedStr); err == nil { + if !h.proxy.Cooldown.IsAllowed("pub", packagePURL, publishedAt) { + h.proxy.Logger.Info("cooldown: filtering pub version", + "package", name, "version", version) + continue + } + } + } + } + // Rewrite archive_url newURL := fmt.Sprintf("%s/pub/packages/%s/versions/%s.tar.gz", h.proxyURL, name, version) vmap["archive_url"] = newURL + filtered = append(filtered, vdata) h.proxy.Logger.Debug("rewrote archive URL", "package", name, "version", version, "new", newURL) } + metadata["versions"] = filtered + + // Update latest if it points to a filtered version + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() { + if latest, ok := metadata["latest"].(map[string]any); ok { + if latestVer, ok := latest["version"].(string); ok { + found := false + for _, vdata := range filtered { + if vmap, ok := vdata.(map[string]any); ok { + if vmap["version"] == latestVer { + found = true + break + } + } + } + if !found && len(filtered) > 0 { + // Use the last entry (most recent remaining) + metadata["latest"] = filtered[len(filtered)-1] + } + } + } + } + return json.Marshal(metadata) } diff --git a/internal/handler/pub_test.go b/internal/handler/pub_test.go new file mode 100644 index 0000000..2788714 --- /dev/null +++ b/internal/handler/pub_test.go @@ -0,0 +1,94 @@ +package handler + +import ( + "encoding/json" + "log/slog" + "testing" + "time" + + "github.com/git-pkgs/proxy/internal/cooldown" +) + +func TestPubRewriteMetadata(t *testing.T) { + h := &PubHandler{ + proxy: testProxy(), + proxyURL: "http://localhost:8080", + } + + input := `{ + "name": "flutter_bloc", + "versions": [ + {"version": "1.0.0", "archive_url": "https://pub.dev/packages/flutter_bloc/versions/1.0.0.tar.gz"}, + {"version": "2.0.0", "archive_url": "https://pub.dev/packages/flutter_bloc/versions/2.0.0.tar.gz"} + ] + }` + + output, err := h.rewriteMetadata("flutter_bloc", []byte(input)) + if err != nil { + t.Fatalf("rewriteMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + versions := result["versions"].([]any) + if len(versions) != 2 { + t.Fatalf("expected 2 versions, got %d", len(versions)) + } + + v1 := versions[0].(map[string]any) + if v1["archive_url"] != "http://localhost:8080/pub/packages/flutter_bloc/versions/1.0.0.tar.gz" { + t.Errorf("unexpected archive_url: %s", v1["archive_url"]) + } +} + +func TestPubRewriteMetadataCooldown(t *testing.T) { + now := time.Now() + old := now.Add(-10 * 24 * time.Hour).Format(time.RFC3339) + recent := now.Add(-1 * time.Hour).Format(time.RFC3339) + + proxy := &Proxy{Logger: slog.Default()} + proxy.Cooldown = &cooldown.Config{Default: "3d"} + + h := &PubHandler{ + proxy: proxy, + proxyURL: "http://localhost:8080", + } + + input := `{ + "name": "flutter_bloc", + "latest": {"version": "2.0.0"}, + "versions": [ + {"version": "1.0.0", "published": "` + old + `", "archive_url": "https://pub.dev/1.0.0.tar.gz"}, + {"version": "2.0.0", "published": "` + recent + `", "archive_url": "https://pub.dev/2.0.0.tar.gz"} + ] + }` + + output, err := h.rewriteMetadata("flutter_bloc", []byte(input)) + if err != nil { + t.Fatalf("rewriteMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + versions := result["versions"].([]any) + if len(versions) != 1 { + t.Fatalf("expected 1 version after cooldown, got %d", len(versions)) + } + + v := versions[0].(map[string]any) + if v["version"] != "1.0.0" { + t.Errorf("expected version 1.0.0, got %v", v["version"]) + } + + // latest should be updated + latest := result["latest"].(map[string]any) + if latest["version"] != "1.0.0" { + t.Errorf("latest version = %v, want 1.0.0", latest["version"]) + } +} diff --git a/internal/handler/pypi.go b/internal/handler/pypi.go index cafbb52..f1ec582 100644 --- a/internal/handler/pypi.go +++ b/internal/handler/pypi.go @@ -10,6 +10,9 @@ import ( "net/url" "regexp" "strings" + "time" + + "github.com/git-pkgs/purl" ) const ( @@ -95,21 +98,97 @@ func (h *PyPIHandler) handleSimplePackage(w http.ResponseWriter, r *http.Request return } - rewritten := h.rewriteSimpleHTML(body) + // When cooldown is enabled, fetch JSON metadata to get version timestamps + var filteredVersions map[string]bool + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() { + filteredVersions = h.fetchFilteredVersions(r, name) + } + + rewritten := h.rewriteSimpleHTML(body, filteredVersions) w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) _, _ = w.Write(rewritten) } +// fetchFilteredVersions fetches JSON metadata and returns a set of version strings +// that should be filtered out due to cooldown. +func (h *PyPIHandler) fetchFilteredVersions(r *http.Request, name string) map[string]bool { + jsonURL := fmt.Sprintf("%s/pypi/%s/json", h.upstreamURL, name) + req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, jsonURL, nil) + if err != nil { + return nil + } + req.Header.Set("Accept", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return nil + } + + var metadata map[string]any + if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil { + return nil + } + + releases, ok := metadata["releases"].(map[string]any) + if !ok { + return nil + } + + packagePURL := purl.MakePURLString("pypi", name, "") + filtered := make(map[string]bool) + + for version, files := range releases { + filesArr, ok := files.([]any) + if !ok { + continue + } + publishedAt := h.newestUploadTime(filesArr) + if !publishedAt.IsZero() && !h.proxy.Cooldown.IsAllowed("pypi", packagePURL, publishedAt) { + filtered[version] = true + } + } + + if len(filtered) == 0 { + return nil + } + return filtered +} + // rewriteSimpleHTML rewrites package URLs in simple API HTML to point at this proxy. -func (h *PyPIHandler) rewriteSimpleHTML(body []byte) []byte { +// If filteredVersions is non-nil, links for those versions are removed entirely. +func (h *PyPIHandler) rewriteSimpleHTML(body []byte, filteredVersions map[string]bool) []byte { + // If cooldown filtering is active, remove entire tags for filtered versions + if len(filteredVersions) > 0 { + // Match full anchor tags: filename + linkRe := regexp.MustCompile(`]+href="[^"]*"[^>]*>[^<]+`) + body = linkRe.ReplaceAllFunc(body, func(match []byte) []byte { + // Extract filename from between tags + innerRe := regexp.MustCompile(`>([^<]+)`) + innerMatch := innerRe.FindSubmatch(match) + if len(innerMatch) < 2 { + return match + } + filename := string(innerMatch[1]) + _, version := h.parseFilename(strings.TrimSpace(filename)) + if version != "" && filteredVersions[version] { + return nil + } + return match + }) + } + // Match href attributes pointing to packages // PyPI URLs look like: https://files.pythonhosted.org/packages/... re := regexp.MustCompile(`href="(https://files\.pythonhosted\.org/packages/[^"]+)"`) return re.ReplaceAllFunc(body, func(match []byte) []byte { - // Extract the URL submatch := re.FindSubmatch(match) if len(submatch) < 2 { return match @@ -117,13 +196,11 @@ func (h *PyPIHandler) rewriteSimpleHTML(body []byte) []byte { origURL := string(submatch[1]) - // Parse the URL to get the path u, err := url.Parse(origURL) if err != nil { return match } - // Rewrite to our proxy newURL := fmt.Sprintf("%s/pypi/packages%s", h.proxyURL, u.Path) return []byte(fmt.Sprintf(`href="%s"`, newURL)) }) @@ -201,24 +278,36 @@ func (h *PyPIHandler) proxyAndRewriteJSON(w http.ResponseWriter, r *http.Request } // rewriteJSONMetadata rewrites download URLs in PyPI JSON metadata. +// If cooldown is enabled, versions published too recently are filtered out. func (h *PyPIHandler) rewriteJSONMetadata(body []byte) ([]byte, error) { var metadata map[string]any if err := json.Unmarshal(body, &metadata); err != nil { return nil, err } - // Rewrite URLs in urls array - if urls, ok := metadata["urls"].([]any); ok { - for _, u := range urls { - if umap, ok := u.(map[string]any); ok { - h.rewriteURLEntry(umap) - } - } + // Determine package name for cooldown lookup + packageName, _ := extractPyPIName(metadata) + packagePURL := "" + if packageName != "" { + packagePURL = purl.MakePURLString("pypi", packageName, "") } - // Rewrite URLs in releases map + // Filter and rewrite URLs in releases map if releases, ok := metadata["releases"].(map[string]any); ok { - for _, files := range releases { + for version, files := range releases { + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() && packagePURL != "" { + if filesArr, ok := files.([]any); ok { + if publishedAt := h.newestUploadTime(filesArr); !publishedAt.IsZero() { + if !h.proxy.Cooldown.IsAllowed("pypi", packagePURL, publishedAt) { + h.proxy.Logger.Info("cooldown: filtering pypi version", + "package", packageName, "version", version) + delete(releases, version) + continue + } + } + } + } + if filesArr, ok := files.([]any); ok { for _, f := range filesArr { if fmap, ok := f.(map[string]any); ok { @@ -229,9 +318,61 @@ func (h *PyPIHandler) rewriteJSONMetadata(body []byte) ([]byte, error) { } } + // Filter and rewrite URLs in urls array (current version files) + if urls, ok := metadata["urls"].([]any); ok { + if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() && packagePURL != "" { + if publishedAt := h.newestUploadTime(urls); !publishedAt.IsZero() { + if !h.proxy.Cooldown.IsAllowed("pypi", packagePURL, publishedAt) { + metadata["urls"] = []any{} + } + } + } + + if urls, ok := metadata["urls"].([]any); ok { + for _, u := range urls { + if umap, ok := u.(map[string]any); ok { + h.rewriteURLEntry(umap) + } + } + } + } + return json.Marshal(metadata) } +// extractPyPIName extracts the package name from PyPI JSON metadata. +func extractPyPIName(metadata map[string]any) (string, bool) { + info, ok := metadata["info"].(map[string]any) + if !ok { + return "", false + } + name, ok := info["name"].(string) + return name, ok +} + +// newestUploadTime returns the most recent upload_time_iso_8601 from a list of file entries. +func (h *PyPIHandler) newestUploadTime(files []any) time.Time { + var newest time.Time + for _, f := range files { + fmap, ok := f.(map[string]any) + if !ok { + continue + } + ts, ok := fmap["upload_time_iso_8601"].(string) + if !ok { + continue + } + t, err := time.Parse(time.RFC3339, ts) + if err != nil { + continue + } + if t.After(newest) { + newest = t + } + } + return newest +} + // rewriteURLEntry rewrites a single URL entry in PyPI metadata. func (h *PyPIHandler) rewriteURLEntry(entry map[string]any) { urlStr, ok := entry["url"].(string) diff --git a/internal/handler/pypi_test.go b/internal/handler/pypi_test.go index 70a8266..18d2637 100644 --- a/internal/handler/pypi_test.go +++ b/internal/handler/pypi_test.go @@ -1,8 +1,12 @@ package handler import ( + "encoding/json" "log/slog" "testing" + "time" + + "github.com/git-pkgs/proxy/internal/cooldown" ) func TestPyPIParseFilename(t *testing.T) { @@ -37,6 +41,54 @@ func TestPyPIParseFilename(t *testing.T) { } } +func TestPyPIRewriteJSONMetadataCooldown(t *testing.T) { + now := time.Now() + old := now.Add(-10 * 24 * time.Hour).Format(time.RFC3339) + recent := now.Add(-1 * time.Hour).Format(time.RFC3339) + + proxy := &Proxy{Logger: slog.Default()} + proxy.Cooldown = &cooldown.Config{Default: "3d"} + + h := &PyPIHandler{ + proxy: proxy, + proxyURL: "http://localhost:8080", + } + + input := `{ + "info": {"name": "requests"}, + "releases": { + "2.30.0": [{"url": "https://files.pythonhosted.org/packages/ab/cd/requests-2.30.0.tar.gz", "upload_time_iso_8601": "` + old + `"}], + "2.31.0": [{"url": "https://files.pythonhosted.org/packages/ab/cd/requests-2.31.0.tar.gz", "upload_time_iso_8601": "` + recent + `"}] + }, + "urls": [{"url": "https://files.pythonhosted.org/packages/ab/cd/requests-2.31.0.tar.gz", "upload_time_iso_8601": "` + recent + `"}] + }` + + output, err := h.rewriteJSONMetadata([]byte(input)) + if err != nil { + t.Fatalf("rewriteJSONMetadata failed: %v", err) + } + + var result map[string]any + if err := json.Unmarshal(output, &result); err != nil { + t.Fatalf("failed to parse output: %v", err) + } + + releases := result["releases"].(map[string]any) + + if _, ok := releases["2.30.0"]; !ok { + t.Error("version 2.30.0 should not be filtered") + } + if _, ok := releases["2.31.0"]; ok { + t.Error("version 2.31.0 should be filtered by cooldown") + } + + // urls array should be empty since the current version is filtered + urls := result["urls"].([]any) + if len(urls) != 0 { + t.Errorf("urls should be empty, got %d entries", len(urls)) + } +} + func TestIsPythonTag(t *testing.T) { tests := []struct { tag string diff --git a/internal/server/server.go b/internal/server/server.go index 957b1d1..4054c4d 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -45,6 +45,7 @@ import ( "time" "github.com/git-pkgs/proxy/internal/config" + "github.com/git-pkgs/proxy/internal/cooldown" "github.com/git-pkgs/proxy/internal/database" "github.com/git-pkgs/proxy/internal/enrichment" "github.com/git-pkgs/proxy/internal/handler" @@ -123,7 +124,13 @@ func (s *Server) Start() error { baseFetcher := fetch.NewFetcher(fetch.WithAuthFunc(s.authForURL)) fetcher := fetch.NewCircuitBreakerFetcher(baseFetcher) resolver := fetch.NewResolver() + cd := &cooldown.Config{ + Default: s.cfg.Cooldown.Default, + Ecosystems: s.cfg.Cooldown.Ecosystems, + Packages: s.cfg.Cooldown.Packages, + } proxy := handler.NewProxy(s.db, s.storage, fetcher, resolver, s.logger) + proxy.Cooldown = cd // Create router with Chi r := chi.NewRouter() From dd4595ddc5eb320b5a33cddeceaffaf44f7f9f31 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Wed, 4 Mar 2026 19:07:53 +0000 Subject: [PATCH 002/131] Add version cooldown section to README Explains the motivation (supply chain attacks rely on speed), shows a concrete config example, and walks through what happens when a new version is published. --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94ab322..31b086e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,26 @@ A caching proxy for package registries. Speeds up package downloads by caching artifacts locally, reducing bandwidth usage and improving reliability. +## Version Cooldown + +Most supply chain attacks rely on speed: a malicious version gets published and consumed by automated pipelines within minutes, before anyone notices. The cooldown feature adds a quarantine period to newly published versions. When enabled, the proxy strips versions from metadata responses until they've aged past a configurable threshold. + +```yaml +cooldown: + default: "3d" # hide versions published less than 3 days ago + ecosystems: + npm: "7d" # npm gets a longer window + cargo: "0" # disable for cargo + packages: + "pkg:npm/lodash": "0" # exempt trusted packages +``` + +A 3-day cooldown means that when `lodash` publishes version `4.18.0`, your builds keep using `4.17.21` until 3 days have passed. If the new release turns out to be compromised, you were never exposed. + +Resolution order: package override, then ecosystem override, then global default. This lets you set a conservative default and carve out exceptions for packages where you need faster updates. + +Currently works with npm, PyPI, pub.dev, and Composer, which all include publish timestamps in their metadata. See [docs/configuration.md](docs/configuration.md) for the full config reference. + ## Supported Registries | Registry | Language/Platform | URL Resolution | Handler | Completed | @@ -354,7 +374,7 @@ upstream: npm: "https://registry.npmjs.org" cargo: "https://index.crates.io" -# Optional: hide recently published versions +# Optional: version cooldown (see above) cooldown: default: "3d" ``` From bd99f3dd826e0aba3e0626df30063c9150ee57ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:27:53 +0000 Subject: [PATCH 003/131] Bump actions/setup-go from 6.2.0 to 6.3.0 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5...4b73464bb391d4059bd26b0524d20df3927bd417) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d9423c..e67fc10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: persist-credentials: false - name: Set up Go - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version: ${{ matrix.go-version }} @@ -40,7 +40,7 @@ jobs: persist-credentials: false - name: Set up Go - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version: '1.25' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5e9d3f6..e34e687 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: persist-credentials: false - name: Set up Go - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod cache: false From fe32236a57726a9bb6d24ed46a8e9365a80e8fe7 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Wed, 11 Mar 2026 17:25:47 +0000 Subject: [PATCH 004/131] Remove hard-coded ecosystems from templates --- internal/server/dashboard.go | 71 +++++++++++++++++++ internal/server/server_test.go | 16 ++++- internal/server/templates.go | 7 +- .../templates/components/ecosystem_badge.html | 2 +- internal/server/templates/layout/footer.html | 9 +-- internal/server/templates/layout/styles.html | 21 ------ .../server/templates/pages/packages_list.html | 16 +---- internal/server/templates/pages/search.html | 16 +---- 8 files changed, 100 insertions(+), 58 deletions(-) diff --git a/internal/server/dashboard.go b/internal/server/dashboard.go index d6550bd..7d13d91 100644 --- a/internal/server/dashboard.go +++ b/internal/server/dashboard.go @@ -113,6 +113,77 @@ type PackagesListPageData struct { TotalPages int } +func supportedEcosystems() []string { + return []string{ + "npm", + "cargo", + "gem", + "go", + "hex", + "pub", + "pypi", + "maven", + "nuget", + "composer", + "conan", + "conda", + "cran", + "oci", + "deb", + "rpm", + } +} + +func ecosystemBadgeLabel(ecosystem string) string { + switch ecosystem { + case "oci": + return "container" + case "deb": + return "debian" + default: + return ecosystem + } +} + +func ecosystemBadgeClasses(ecosystem string) string { + base := "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium" + + switch ecosystem { + case "npm", "maven": + return base + " bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300" + case "cargo": + return base + " bg-orange-100 text-orange-700 dark:bg-orange-900/50 dark:text-orange-300" + case "gem": + return base + " bg-pink-100 text-pink-700 dark:bg-pink-900/50 dark:text-pink-300" + case "go": + return base + " bg-cyan-100 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300" + case "hex": + return base + " bg-purple-100 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300" + case "pub": + return base + " bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300" + case "pypi": + return base + " bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300" + case "nuget": + return base + " bg-indigo-100 text-indigo-700 dark:bg-indigo-900/50 dark:text-indigo-300" + case "composer": + return base + " bg-violet-100 text-violet-700 dark:bg-violet-900/50 dark:text-violet-300" + case "conan": + return base + " bg-teal-100 text-teal-700 dark:bg-teal-900/50 dark:text-teal-300" + case "conda": + return base + " bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300" + case "cran": + return base + " bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300" + case "oci": + return base + " bg-sky-100 text-sky-700 dark:bg-sky-900/50 dark:text-sky-300" + case "deb": + return base + " bg-red-100 text-red-800 dark:bg-red-900/50 dark:text-red-300" + case "rpm": + return base + " bg-amber-100 text-amber-800 dark:bg-amber-900/50 dark:text-amber-300" + default: + return base + " bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300" + } +} + func getRegistryConfigs(baseURL string) []RegistryConfig { return []RegistryConfig{ { diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 44498f9..7e432ed 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -57,8 +57,8 @@ func newTestServer(t *testing.T) *testServer { proxy := handler.NewProxy(db, store, fetcher, resolver, logger) cfg := &config.Config{ - BaseURL: "http://localhost:8080", - Storage: config.StorageConfig{Path: storagePath}, + BaseURL: "http://localhost:8080", + Storage: config.StorageConfig{Path: storagePath}, Database: config.DatabaseConfig{Path: dbPath}, } @@ -196,6 +196,18 @@ func TestDashboard(t *testing.T) { if !strings.Contains(body, "Popular Packages") { t.Error("dashboard should contain popular packages section") } + if !strings.Contains(body, ">composer<") { + t.Error("dashboard should show composer in supported ecosystems") + } + if !strings.Contains(body, ">conan<") { + t.Error("dashboard should show conan in supported ecosystems") + } + if !strings.Contains(body, ">container<") { + t.Error("dashboard should show container in supported ecosystems") + } + if !strings.Contains(body, ">debian<") { + t.Error("dashboard should show debian in supported ecosystems") + } } func min(a, b int) int { diff --git a/internal/server/templates.go b/internal/server/templates.go index c49c480..2d261a3 100644 --- a/internal/server/templates.go +++ b/internal/server/templates.go @@ -21,8 +21,11 @@ func NewTemplates() (*Templates, error) { // Define custom template functions funcMap := template.FuncMap{ - "add": func(a, b int) int { return a + b }, - "sub": func(a, b int) int { return a - b }, + "add": func(a, b int) int { return a + b }, + "sub": func(a, b int) int { return a - b }, + "supportedEcosystems": supportedEcosystems, + "ecosystemBadgeClass": ecosystemBadgeClasses, + "ecosystemBadgeLabel": ecosystemBadgeLabel, } // Get all page files diff --git a/internal/server/templates/components/ecosystem_badge.html b/internal/server/templates/components/ecosystem_badge.html index ba1c286..4c7e882 100644 --- a/internal/server/templates/components/ecosystem_badge.html +++ b/internal/server/templates/components/ecosystem_badge.html @@ -1,3 +1,3 @@ {{define "ecosystem_badge"}} -{{.}} +{{ecosystemBadgeLabel .}} {{end}} diff --git a/internal/server/templates/layout/footer.html b/internal/server/templates/layout/footer.html index 2c963f0..8b88416 100644 --- a/internal/server/templates/layout/footer.html +++ b/internal/server/templates/layout/footer.html @@ -19,12 +19,9 @@

Supported Ecosystems

- npm - cargo - gem - go - pypi - maven + {{range supportedEcosystems}} + {{template "ecosystem_badge" .}} + {{end}}
diff --git a/internal/server/templates/layout/styles.html b/internal/server/templates/layout/styles.html index 1d21184..7fecaff 100644 --- a/internal/server/templates/layout/styles.html +++ b/internal/server/templates/layout/styles.html @@ -1,25 +1,4 @@ {{define "styles"}} - - + + + {{block "head" .}}{{end}} - + {{template "header" .}} -
+
{{block "content" .}}{{end}}
diff --git a/internal/server/templates/layout/footer.html b/internal/server/templates/layout/footer.html index 6d6d6b6..5aa970d 100644 --- a/internal/server/templates/layout/footer.html +++ b/internal/server/templates/layout/footer.html @@ -5,7 +5,12 @@

About

- git-pkgs proxy is a caching proxy for package registries supporting 16+ ecosystems. + git-pkgs proxy is a caching proxy for package registries supporting 17+ ecosystems. +

+

+ + github.com/git-pkgs/proxy +

@@ -26,11 +31,6 @@
-
-

- Powered by git-pkgs -

-
{{end}} diff --git a/internal/server/templates/layout/header.html b/internal/server/templates/layout/header.html index c17ccbb..b3103f1 100644 --- a/internal/server/templates/layout/header.html +++ b/internal/server/templates/layout/header.html @@ -1,31 +1,21 @@ {{define "header"}}
-
-
+
+ - git-pkgs proxy + git-pkgs proxy + + -
-
- - - - -
-
-
+
+
{{end}} + +{{define "search_form"}} +
+ + + + +
+{{end}} + +{{define "nav_links"}} +Install +Health +API +{{end}} diff --git a/internal/server/templates/layout/styles.html b/internal/server/templates/layout/styles.html index 7fecaff..76e9d9e 100644 --- a/internal/server/templates/layout/styles.html +++ b/internal/server/templates/layout/styles.html @@ -9,5 +9,18 @@ localStorage.theme = 'dark'; } }); + + (function() { + const toggle = document.getElementById('nav-toggle'); + const menu = document.getElementById('mobile-nav'); + if (!toggle || !menu) return; + toggle.addEventListener('click', function() { + const open = toggle.getAttribute('aria-expanded') === 'true'; + toggle.setAttribute('aria-expanded', String(!open)); + menu.classList.toggle('hidden'); + toggle.querySelector('.nav-icon-open').classList.toggle('hidden'); + toggle.querySelector('.nav-icon-close').classList.toggle('hidden'); + }); + })(); {{end}} diff --git a/internal/server/templates/pages/browse_source.html b/internal/server/templates/pages/browse_source.html index 3ba7a76..ca06652 100644 --- a/internal/server/templates/pages/browse_source.html +++ b/internal/server/templates/pages/browse_source.html @@ -100,35 +100,38 @@ function renderFileTree(files, basePath) { if (basePath) { const parentPath = basePath.split('/').slice(0, -2).join('/'); html += ` -
- 📁 .. + ..
`; } // Render files and directories for (const file of files) { - const icon = file.is_dir ? '📁' : '📄'; - const classes = 'px-2 py-1 hover:bg-gray-100 dark:hover:bg-gray-800 rounded cursor-pointer text-sm truncate'; + const iconName = file.is_dir ? 'folder' : 'file'; + const iconClass = file.is_dir ? 'text-amber-500 dark:text-amber-400' : 'text-gray-500 dark:text-gray-400'; + const classes = 'px-2 py-1 hover:bg-gray-100 dark:hover:bg-gray-800 rounded cursor-pointer text-sm flex items-center gap-2'; + const iconHTML = ``; if (file.is_dir) { html += `
- ${icon} ${escapeHTML(file.name)} + ${iconHTML}${escapeHTML(file.name)}
`; } else { html += `
- ${icon} ${escapeHTML(file.name)} - ${formatSize(file.size)} + ${iconHTML}${escapeHTML(file.name)} + ${formatSize(file.size)}
`; } } container.innerHTML = html; + if (window.lucide) lucide.createIcons({ attrs: { 'aria-hidden': 'true', focusable: 'false' } }); } // Load and display file content From cb18df5bac6a94ea9eff45c07b4892854d7ce74f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:26:10 +0100 Subject: [PATCH 117/131] Bump actions/checkout from 6.0.2 to 6.0.3 (#163) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/swagger.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 784d851..9712038 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false @@ -35,7 +35,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index add8d32..4844dde 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,7 +20,7 @@ jobs: contents: read steps: - name: Check out the repo - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 with: persist-credentials: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c23de56..dc15164 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 6bc3514..d18ba0f 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -12,7 +12,7 @@ jobs: swagger: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index f621254..1c212f7 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -21,7 +21,7 @@ jobs: security-events: write steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false From 50ea557ce87931b37aa68e18f083a74ae22c2c90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:26:21 +0100 Subject: [PATCH 118/131] Bump gocloud.dev from 0.45.0 to 0.46.0 (#164) Bumps [gocloud.dev](https://github.com/google/go-cloud) from 0.45.0 to 0.46.0. - [Release notes](https://github.com/google/go-cloud/releases) - [Commits](https://github.com/google/go-cloud/compare/v0.45.0...v0.46.0) --- updated-dependencies: - dependency-name: gocloud.dev dependency-version: 0.46.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 43 ++++++++++---------- go.sum | 122 +++++++++++++++++++++++++++------------------------------ 2 files changed, 78 insertions(+), 87 deletions(-) diff --git a/go.mod b/go.mod index 6c7a7e4..e31bf56 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/prometheus/client_model v0.6.2 github.com/spdx/tools-golang v0.5.7 github.com/swaggo/swag v1.16.6 - gocloud.dev v0.45.0 + gocloud.dev v0.46.0 golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 @@ -44,13 +44,11 @@ require ( github.com/Antonboom/errname v1.1.1 // indirect github.com/Antonboom/nilnil v1.1.1 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 // indirect - github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest/to v0.4.1 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect @@ -71,23 +69,22 @@ require ( github.com/ashanbrown/makezero/v2 v2.1.0 // indirect github.com/aws/aws-sdk-go-v2 v1.41.9 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.11 // indirect - github.com/aws/aws-sdk-go-v2/config v1.32.11 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.11 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.5 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.20 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.19 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.25 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.3 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.25 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.26 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.10 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.18 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.25 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.25 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.102.2 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.19 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.3 // indirect github.com/aws/smithy-go v1.26.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -149,7 +146,7 @@ require ( github.com/gobwas/glob v0.2.3 // indirect github.com/godoc-lint/godoc-lint v0.11.2 // indirect github.com/gofrs/flock v0.13.0 // indirect - github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golangci/asciicheck v0.5.0 // indirect github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect @@ -165,8 +162,8 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/google/wire v0.7.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.12 // indirect - github.com/googleapis/gax-go/v2 v2.17.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect + github.com/googleapis/gax-go/v2 v2.19.0 // indirect github.com/gordonklaus/ineffassign v0.2.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.5.0 // indirect @@ -294,18 +291,18 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.48.0 // indirect + golang.org/x/crypto v0.49.0 // indirect golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.51.0 // indirect + golang.org/x/net v0.52.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.34.0 // indirect + golang.org/x/text v0.35.0 // indirect golang.org/x/tools v0.42.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.269.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect + google.golang.org/api v0.272.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect google.golang.org/grpc v1.81.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 903b317..e6a426f 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI= -cloud.google.com/go/storage v1.57.2 h1:sVlym3cHGYhrp6XZKkKb+92I1V42ks2qKKpB0CF5Mb4= -cloud.google.com/go/storage v1.57.2/go.mod h1:n5ijg4yiRXXpCu0sJTD6k+eMf7GRrJmPyr9YxLXGHOk= +cloud.google.com/go/storage v1.61.3 h1:VS//ZfBuPGDvakfD9xyPW1RGF1Vy3BWUoVZXgW1KMOg= +cloud.google.com/go/storage v1.61.3/go.mod h1:JtqK8BBB7TWv0HVGHubtUdzYYrakOQIsMLffZ2Z/HWk= codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= codeberg.org/polyfloyd/go-errorlint v1.9.0 h1:VkdEEmA1VBpH6ecQoMR4LdphVI3fA4RrCh2an7YmodI= @@ -27,8 +27,8 @@ dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88 dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= -filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= @@ -43,8 +43,8 @@ github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksuf github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= @@ -53,16 +53,12 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDo github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 h1:ZJJNFaQ86GVKQ9ehwqyAFE6pIfyicpuJ8IkVaPBc6/4= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3/go.mod h1:URuDvhmATVKqHBH9/0nOiNKk0+YcwfQ3WkK5PqHKxc8= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest/to v0.4.1 h1:CxNHBqdzTr7rLtdrtb5CMjJcDut+WNGCVv7OmS5+lTc= -github.com/Azure/go-autorest/autorest/to v0.4.1/go.mod h1:EtaofgU4zmtvn1zT2ARsjRFdq9vXx0YWtmElwL+GZ9M= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 h1:jWQK1GI+LeGGUKBADtcH2rRqPxYB1Ljwms5gFA2LqrM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4/go.mod h1:8mwH4klAm9DUgR2EEHyEEAQlRDvLPyg5fQry3y+cDew= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= -github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0 h1:4iB+IesclUXdP0ICgAabvq2FYLXrJWKx1fJQ+GxSo3Y= +github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= @@ -72,10 +68,10 @@ github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= @@ -119,20 +115,18 @@ github.com/aws/aws-sdk-go-v2 v1.41.9 h1:/rYeyO2+HrMztAmxAq9++XJtFMqSIpSsNA0yDGAL github.com/aws/aws-sdk-go-v2 v1.41.9/go.mod h1:+HsoOEX80qAVUitj1A2DhCNTjmb3edVyuDypb6LNEeo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.11 h1:h5+3VT69KUBK24grGuuA5saDJTj2IIjLb9au668Fo5I= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.11/go.mod h1:dnakxebH6UwFvcvujL0LVggYQ8nEvBGjU4G/V79Nv94= -github.com/aws/aws-sdk-go-v2/config v1.32.11 h1:ftxI5sgz8jZkckuUHXfC/wMUc8u3fG1vQS0plr2F2Zs= -github.com/aws/aws-sdk-go-v2/config v1.32.11/go.mod h1:twF11+6ps9aNRKEDimksp923o44w/Thk9+8YIlzWMmo= -github.com/aws/aws-sdk-go-v2/credentials v1.19.11 h1:NdV8cwCcAXrCWyxArt58BrvZJ9pZ9Fhf9w6Uh5W3Uyc= -github.com/aws/aws-sdk-go-v2/credentials v1.19.11/go.mod h1:30yY2zqkMPdrvxBqzI9xQCM+WrlrZKSOpSJEsylVU+8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 h1:INUvJxmhdEbVulJYHI061k4TVuS3jzzthNvjqvVvTKM= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19/go.mod h1:FpZN2QISLdEBWkayloda+sZjVJL+e9Gl0k1SyTgcswU= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.5 h1:4nC6vsVBU6vClZxxF6XLEozLUY/PgUCXYlGGB/VaC8M= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.5/go.mod h1:N5c+La/yy7H4YnF9rFgUqwgbfw+MloWoCHQ0RJH2EBE= +github.com/aws/aws-sdk-go-v2/config v1.32.20 h1:8VMDnWc/kEzxsI/1ngGM9mG81a8IGmIHD8KLcYGwagc= +github.com/aws/aws-sdk-go-v2/config v1.32.20/go.mod h1:PuwEpciweIXGULWeOeSTXtSbH4CW9mWdWrhdCKQI1sM= +github.com/aws/aws-sdk-go-v2/credentials v1.19.19 h1:yuFzSV1U0aRNYCQGVaTY2zW2M/L93pYHnXnrJUphYhU= +github.com/aws/aws-sdk-go-v2/credentials v1.19.19/go.mod h1:7y63L1kGzeoDlJaQ3Z578KrnmfBut96JjvJUzGwR+YE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.25 h1:0w6dCiO8iez+YKwRhRBlL1CH/E3GTfdkuzrwj1by8vo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.25/go.mod h1:9FDWUothyr5RCRAHc45XOiVCzUR8n/IhCYX+uVqw6vk= +github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.3 h1:w5OoDiMN6x53ROmiIImGzmVcxXv2q1GXY+aKV4WAJYM= +github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.3/go.mod h1:dAhgYp776bX3LuWvnSCFwQEjNs6fuFg7YXIy5PXcP3Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.25 h1:Uii3frf9ztec/ABM2/FSH9/z7PLzxfpG8h4RpkUFflQ= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.25/go.mod h1:G6kntsA2GorAxDPbap6xgB2F+amSLUF8GJTi7PUoX44= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.25 h1:r1+/l6m+WaUJF9HISEsNOLHSNj5EXYQxK8VX6Cz9NlA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.25/go.mod h1:cKf+D+NMDK1LndD7BowHbBZPgR9V0/5HubH0PFWvA+c= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.26 h1:A1PmWU2zfkIm9EyFlJncFXL4W4phML+h8KjltUsCvNQ= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.26/go.mod h1:dY4MRzXEizrD4hqtpKvWVGPX7QleSGGVY+EBolo1RmM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.10 h1:d5/908OJ4bXg8lyjeMPvXetEKqoDoLi5Owy1zNue3yg= @@ -145,14 +139,14 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.25 h1:2pQEbwf+/6EDb github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.25/go.mod h1:KvT6NCcQ0EZ+ZkVRrlBMt04Po3ok23YELEp7WimhLhM= github.com/aws/aws-sdk-go-v2/service/s3 v1.102.2 h1:ie4ElCmUKS26pzrZcIk/lmt4yWjAqLLcawstyQCh298= github.com/aws/aws-sdk-go-v2/service/s3 v1.102.2/go.mod h1:zjsomFeX5duj+4PlMB+o4JoWTIx+G0XMyzjYrUbQkN0= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.12/go.mod h1:fEWYKTRGoZNl8tZ77i61/ccwOMJdGxwOhWCkp6TXAr0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 h1:EnUdUqRP1CNzt2DkV67tJx6XDN4xlfBFm+bzeNOQVb0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16/go.mod h1:Jic/xv0Rq/pFNCh3WwpH4BEqdbSAl+IyHro8LbibHD8= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 h1:XQTQTF75vnug2TXS8m7CVJfC2nniYPZnO1D4Np761Oo= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.8/go.mod h1:Xgx+PR1NUOjNmQY+tRMnouRp83JRM8pRMw/vCaVhPkI= +github.com/aws/aws-sdk-go-v2/service/signin v1.1.1 h1:1VwbP3qMNfxUDEXWki4rCE5iA+44VA1lokTz9HasGzw= +github.com/aws/aws-sdk-go-v2/service/signin v1.1.1/go.mod h1:vUtyoSj0OPji3kjIVSc/GlKuWEiL33f/WFxl6dmpy/A= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.19 h1:N6pIsdFOW1Kd9S4KyFKXdGRBojPPxkP32+uHFWLv4Hc= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.19/go.mod h1:3gt5WJArFooNmyLONS+h/R4J+o86II8du38IgCwj9dE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.2 h1:hc+lBYiiTr8Zk4MTzIsQ92MeDWCIDvWGmzKUWOaBcOg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.2/go.mod h1:hU6fqB3OJA6/ePheD47LQnxvjYk6br6PtQxs+Q9ojvk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.3 h1:ErklX/7uhSbkAAeyQD/Y1OoQ9hO3SJXQNEgksORW3Js= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.3/go.mod h1:ULe4HCzfKPiR6R3HEurE3b1upEkuk8AkMrOKtaOxKO8= github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s= github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -329,8 +323,8 @@ github.com/godoc-lint/godoc-lint v0.11.2 h1:Bp0FkJWoSdNsBikdNgIcgtaoo+xz6I/Y9s5W github.com/godoc-lint/godoc-lint v0.11.2/go.mod h1:iVpGdL1JCikNH2gGeAn3Hh+AgN5Gx/I/cxV+91L41jo= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= @@ -374,10 +368,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= -github.com/googleapis/enterprise-certificate-proxy v0.3.12 h1:Fg+zsqzYEs1ZnvmcztTYxhgCBsx3eEhEwQ1W/lHq/sQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.12/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= -github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= -github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= +github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8= +github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.19.0 h1:fYQaUOiGwll0cGj7jmHT/0nPlcrZDFPrZRhTsoCr8hE= +github.com/googleapis/gax-go/v2 v2.19.0/go.mod h1:w2ROXVdfGEVFXzmlciUU4EdjHgWvB5h2n6x/8XSTTJA= github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= @@ -708,10 +702,10 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/detectors/gcp v1.42.0 h1:kpt2PEJuOuqYkPcktfJqWWDjTEd/FNgrxcniL7kQrXQ= go.opentelemetry.io/contrib/detectors/gcp v1.42.0/go.mod h1:W9zQ439utxymRrXsUOzZbFX4JhLxXU4+ZnCt8GG7yA8= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= @@ -734,16 +728,16 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -gocloud.dev v0.45.0 h1:WknIK8IbRdmynDvara3Q7G6wQhmEiOGwpgJufbM39sY= -gocloud.dev v0.45.0/go.mod h1:0kXKmkCLG6d31N7NyLZWzt7jDSQura9zD/mWgiB6THI= +gocloud.dev v0.46.0 h1:niIuZwSjMtBx8K+ITB2s5kZullB13PGOS2ZoQPZxQ4Q= +gocloud.dev v0.46.0/go.mod h1:ACQe+2qO+hEO+pdcvvsM+RB63r8TyGD1W3ESCLFyzvM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -775,8 +769,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= -golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -827,10 +821,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= @@ -857,14 +851,14 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.269.0 h1:qDrTOxKUQ/P0MveH6a7vZ+DNHxJQjtGm/uvdbdGXCQg= -google.golang.org/api v0.269.0/go.mod h1:N8Wpcu23Tlccl0zSHEkcAZQKDLdquxK+l9r2LkwAauE= -google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= -google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= -google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4= -google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA= +google.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA= +google.golang.org/genproto v0.0.0-20260316180232-0b37fe3546d5 h1:JNfk58HZ8lfmXbYK2vx/UvsqIL59TzByCxPIX4TDmsE= +google.golang.org/genproto v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:x5julN69+ED4PcFk/XWayw35O0lf/nGa4aNgODCmNmw= +google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 h1:CogIeEXn4qWYzzQU0QqvYBM8yDF9cFYzDq9ojSpv0Js= +google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= From fc245fd975d323b6b2dc2cf018361d26910712e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:26:29 +0100 Subject: [PATCH 119/131] Bump github.com/git-pkgs/enrichment from 0.2.3 to 0.3.0 (#165) Bumps [github.com/git-pkgs/enrichment](https://github.com/git-pkgs/enrichment) from 0.2.3 to 0.3.0. - [Commits](https://github.com/git-pkgs/enrichment/compare/v0.2.3...v0.3.0) --- updated-dependencies: - dependency-name: github.com/git-pkgs/enrichment dependency-version: 0.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e31bf56..df472a0 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/CycloneDX/cyclonedx-go v0.11.0 github.com/git-pkgs/archives v0.3.0 github.com/git-pkgs/cooldown v0.1.1 - github.com/git-pkgs/enrichment v0.2.3 + github.com/git-pkgs/enrichment v0.3.0 github.com/git-pkgs/purl v0.1.12 github.com/git-pkgs/registries v0.6.1 github.com/git-pkgs/spdx v0.1.4 diff --git a/go.sum b/go.sum index e6a426f..3519f38 100644 --- a/go.sum +++ b/go.sum @@ -248,8 +248,8 @@ github.com/git-pkgs/archives v0.3.0 h1:iXKyO83jEFub1PGEDlHmk2tQ7XeV5LySTc0sEkH3x github.com/git-pkgs/archives v0.3.0/go.mod h1:LTJ1iQVFA7otizWMOyiI82NYVmyBWAPRzwu/e30rcXU= github.com/git-pkgs/cooldown v0.1.1 h1:9OqqzCB8gANz/y44SmqGD0Jp8Qtu81D1sCbKl6Ehg7w= github.com/git-pkgs/cooldown v0.1.1/go.mod h1:v7APuK/UouTiu8mWQZbdDmj7DfxxkGUeuhjaRB5gv9E= -github.com/git-pkgs/enrichment v0.2.3 h1:42mqoUhQZNGhlEO671pboI/Cu6F+DoffJoFbVhb2jlw= -github.com/git-pkgs/enrichment v0.2.3/go.mod h1:MBv5nhHzjwLxeSgx2+7waCcpReUjhCD+9B0bvufpMO0= +github.com/git-pkgs/enrichment v0.3.0 h1:tsATMAwR/qcSIw4JV37uH2TBgTv415RfJC7w3nzWfD4= +github.com/git-pkgs/enrichment v0.3.0/go.mod h1:MBv5nhHzjwLxeSgx2+7waCcpReUjhCD+9B0bvufpMO0= github.com/git-pkgs/packageurl-go v0.3.1 h1:WM3RBABQZLaRBxgKyYughc3cVBE8KyQxbSC6Jt5ak7M= github.com/git-pkgs/packageurl-go v0.3.1/go.mod h1:rcIxiG37BlQLB6FZfgdj9Fm7yjhRQd3l+5o7J0QPAk4= github.com/git-pkgs/pom v0.1.4 h1:C6st+XSbF75eKuwfdkDZZtYHoTcaWRIEQYar5VtszUo= From d968f4ad4792e06e3ff899decb3886e779b3886f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:26:36 +0100 Subject: [PATCH 120/131] Bump alpine from 3.23.4 to 3.24.0 (#166) Bumps alpine from 3.23.4 to 3.24.0. --- updated-dependencies: - dependency-name: alpine dependency-version: 3.24.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a4e22f4..f31cd05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ COPY . . # Build the binary RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /proxy ./cmd/proxy -FROM alpine:3.23.4 +FROM alpine:3.24.0 RUN apk add --no-cache ca-certificates From 22c9df637400f8f5f4ba259939f7392cafd8e8a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:57:21 +0100 Subject: [PATCH 121/131] Bump alpine from 3.24.0 to 3.24.1 (#172) Bumps alpine from 3.24.0 to 3.24.1. --- updated-dependencies: - dependency-name: alpine dependency-version: 3.24.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f31cd05..7b2795c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ COPY . . # Build the binary RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /proxy ./cmd/proxy -FROM alpine:3.24.0 +FROM alpine:3.24.1 RUN apk add --no-cache ca-certificates From 8aa6d758a8640a919c520bfee9108c7f1c9291f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:57:32 +0100 Subject: [PATCH 122/131] Bump modernc.org/sqlite from 1.51.0 to 1.52.0 (#171) Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.51.0 to 1.52.0. - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.51.0...v1.52.0) --- updated-dependencies: - dependency-name: modernc.org/sqlite dependency-version: 1.52.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index df472a0..ecd3207 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,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.51.0 + modernc.org/sqlite v1.52.0 ) require ( diff --git a/go.sum b/go.sum index 3519f38..1e5f917 100644 --- a/go.sum +++ b/go.sum @@ -902,8 +902,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0/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.51.0 h1:aH/MMSoayAIhozZ7uJbVTT9QO/VhzBf0J9tymmmuC/U= -modernc.org/sqlite v1.51.0/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= +modernc.org/sqlite v1.52.0 h1:p4dhYh2tXZCiyaqHwRVJDjIGKWyXayiQpThxgDzJaxo= +modernc.org/sqlite v1.52.0/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= 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= From e289faed06df9114fa56cda87057e1c2bea151fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:57:42 +0100 Subject: [PATCH 123/131] Bump golang.org/x/sync from 0.20.0 to 0.21.0 (#170) Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.20.0 to 0.21.0. - [Commits](https://github.com/golang/sync/compare/v0.20.0...v0.21.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-version: 0.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ecd3207..a1b22d6 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spdx/tools-golang v0.5.7 github.com/swaggo/swag v1.16.6 gocloud.dev v0.46.0 - golang.org/x/sync v0.20.0 + golang.org/x/sync v0.21.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.52.0 diff --git a/go.sum b/go.sum index 1e5f917..c1a5bb8 100644 --- a/go.sum +++ b/go.sum @@ -782,8 +782,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 795edb4f916cdd18966ba5341c4e4700ba9fe5b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:28:18 -0400 Subject: [PATCH 124/131] Bump actions/checkout from 6.0.3 to 7.0.0 (#175) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/swagger.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9712038..c1a2abb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false @@ -35,7 +35,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4844dde..93b0a1e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,7 +20,7 @@ jobs: contents: read steps: - name: Check out the repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: persist-credentials: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dc15164..a7d8ae5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index d18ba0f..b6e086a 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -12,7 +12,7 @@ jobs: swagger: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 1c212f7..b404599 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -21,7 +21,7 @@ jobs: security-events: write steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false From b2011c0a546331f0f853f5de5fa1fb025da2a896 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Fri, 26 Jun 2026 07:42:30 -0400 Subject: [PATCH 125/131] Log actual database config instead of sqlite path (#176) The startup log and /stats endpoint always reported Database.Path, which is the sqlite default even when PROXY_DATABASE_DRIVER=postgres is set and a postgres URL is in use. Add DatabaseConfig.String() that returns the sqlite path or the postgres URL with the password redacted, and use it in both places. Fixes #173 --- internal/config/config.go | 15 +++++++++++++++ internal/config/config_test.go | 21 +++++++++++++++++++++ internal/server/server.go | 4 ++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index e84e887..16928dc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -219,6 +219,21 @@ type DatabaseConfig struct { URL string `json:"url" yaml:"url"` } +// String returns a human-readable description of the configured database +// suitable for logging. For postgres the password in the connection URL is +// redacted; if the URL cannot be parsed only the driver name is returned to +// avoid leaking credentials. +func (d DatabaseConfig) String() string { + if d.Driver == "postgres" { + u, err := url.Parse(d.URL) + if err != nil || u.Host == "" { + return "postgres" + } + return u.Redacted() + } + return d.Path +} + // LogConfig configures logging. type LogConfig struct { // Level is the minimum log level: "debug", "info", "warn", "error". diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 2f4fdd2..bb3ec74 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -676,3 +676,24 @@ func TestValidateDirectServeBaseURL(t *testing.T) { t.Errorf("unexpected error for valid direct_serve_base_url: %v", err) } } + +func TestDatabaseConfigString(t *testing.T) { + tests := []struct { + name string + cfg DatabaseConfig + want string + }{ + {"sqlite", DatabaseConfig{Driver: "sqlite", Path: "./cache/proxy.db"}, "./cache/proxy.db"}, + {"default driver", DatabaseConfig{Path: "/var/lib/proxy.db"}, "/var/lib/proxy.db"}, + {"postgres no password", DatabaseConfig{Driver: "postgres", URL: "postgres://user@localhost:5432/proxy"}, "postgres://user@localhost:5432/proxy"}, + {"postgres redacts password", DatabaseConfig{Driver: "postgres", URL: "postgres://user:secret@localhost:5432/proxy?sslmode=disable"}, "postgres://user:xxxxx@localhost:5432/proxy?sslmode=disable"}, + {"postgres unparseable url", DatabaseConfig{Driver: "postgres", URL: "host=localhost user=foo password=bar"}, "postgres"}, + {"postgres ignores sqlite path", DatabaseConfig{Driver: "postgres", URL: "postgres://localhost/db", Path: "./cache/proxy.db"}, "postgres://localhost/db"}, + } + + for _, tt := range tests { + if got := tt.cfg.String(); got != tt.want { + t.Errorf("%s: String() = %q, want %q", tt.name, got, tt.want) + } + } +} diff --git a/internal/server/server.go b/internal/server/server.go index cb99648..0a46a37 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -302,7 +302,7 @@ func (s *Server) Start() error { "base_url", s.cfg.BaseURL, "ui_url", s.cfg.UIBaseURL, "storage", s.storage.URL(), - "database", s.cfg.Database.Path) + "database", s.cfg.Database.String()) go s.updateCacheStatsMetrics() go s.startEvictionLoop(bgCtx) @@ -927,7 +927,7 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) { TotalSize: size, TotalSizeHuman: formatSize(size), StorageURL: s.storage.URL(), - DatabasePath: s.cfg.Database.Path, + DatabasePath: s.cfg.Database.String(), } w.Header().Set("Content-Type", "application/json") From ca2514991d335739b77dc6d7976b48b3b38a696c Mon Sep 17 00:00:00 2001 From: wickedOne Date: Fri, 26 Jun 2026 13:51:08 +0200 Subject: [PATCH 126/131] fix(composer): resolve *-dev versions from the ~dev metadata file (#174) --- internal/handler/composer.go | 98 ++++++++++++++++++++++--------- internal/handler/composer_test.go | 97 ++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 28 deletions(-) diff --git a/internal/handler/composer.go b/internal/handler/composer.go index 065ddf9..e4dec41 100644 --- a/internal/handler/composer.go +++ b/internal/handler/composer.go @@ -1,6 +1,7 @@ package handler import ( + "context" "encoding/json" "errors" "fmt" @@ -307,37 +308,28 @@ func (h *ComposerHandler) handleDownload(w http.ResponseWriter, r *http.Request) h.proxy.Logger.Info("composer download request", "package", packageName, "version", version, "filename", filename) - // We need to fetch the metadata to get the actual download URL - // since Packagist URLs include a hash - metaURL := fmt.Sprintf("%s/p2/%s/%s.json", h.repoURL, vendor, pkg) + // We need to fetch the metadata to get the actual download URL since + // Packagist URLs include a hash. Packagist serves dev versions (e.g. + // "3.x-dev", "dev-master") from a separate "~dev" metadata file, while + // tagged releases live in the regular file. Try the file most likely to + // contain this version first, then fall back to the other so that both + // stable and dev versions resolve correctly. + metaURLs := h.metadataURLsForVersion(vendor, pkg, version) - req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, metaURL, nil) - if err != nil { - http.Error(w, "failed to create request", http.StatusInternalServerError) - return + var downloadURL string + for _, metaURL := range metaURLs { + url, err := h.findDownloadURLFromMetadata(r.Context(), metaURL, packageName, version) + if err != nil { + h.proxy.Logger.Error("failed to fetch metadata", "error", err, "url", metaURL) + http.Error(w, "failed to fetch metadata", http.StatusBadGateway) + return + } + if url != "" { + downloadURL = url + break + } } - resp, err := h.proxy.HTTPClient.Do(req) - if err != nil { - h.proxy.Logger.Error("failed to fetch metadata", "error", err) - http.Error(w, "failed to fetch metadata", http.StatusBadGateway) - return - } - defer func() { _ = resp.Body.Close() }() - - if resp.StatusCode != http.StatusOK { - http.Error(w, "package not found", http.StatusNotFound) - return - } - - var metadata map[string]any - if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil { - http.Error(w, "failed to parse metadata", http.StatusInternalServerError) - return - } - - // Find the download URL for this version - downloadURL := h.findDownloadURL(metadata, packageName, version) if downloadURL == "" { http.Error(w, "version not found", http.StatusNotFound) return @@ -353,6 +345,56 @@ func (h *ComposerHandler) handleDownload(w http.ResponseWriter, r *http.Request) ServeArtifact(w, result) } +// isDevVersion reports whether a Composer version string refers to a +// development (unstable, branch) version rather than a tagged release. +// Composer formats these as either "dev-" (e.g. "dev-master") or +// "-dev" (e.g. "3.x-dev"). +func isDevVersion(version string) bool { + return strings.HasPrefix(version, "dev-") || strings.HasSuffix(version, "-dev") +} + +// metadataURLsForVersion returns the upstream metadata URLs to consult for a +// given version, in priority order. Dev versions are served from the "~dev" +// file, tagged releases from the regular file; the other file is included as a +// fallback so an unexpected classification still resolves. +func (h *ComposerHandler) metadataURLsForVersion(vendor, pkg, version string) []string { + stable := fmt.Sprintf("%s/p2/%s/%s.json", h.repoURL, vendor, pkg) + dev := fmt.Sprintf("%s/p2/%s/%s~dev.json", h.repoURL, vendor, pkg) + + if isDevVersion(version) { + return []string{dev, stable} + } + return []string{stable, dev} +} + +// findDownloadURLFromMetadata fetches a metadata document and returns the dist +// URL for the given version, or an empty string if the version is not present. +// An error is returned only on transport failure; a missing document (non-200) +// or a missing version both yield an empty string so the caller can fall back. +func (h *ComposerHandler) findDownloadURLFromMetadata(ctx context.Context, metaURL, packageName, version string) (string, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, metaURL, nil) + if err != nil { + return "", err + } + + resp, err := h.proxy.HTTPClient.Do(req) + if err != nil { + return "", err + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return "", nil + } + + var metadata map[string]any + if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil { + return "", err + } + + return h.findDownloadURL(metadata, packageName, version), nil +} + // findDownloadURL finds the dist URL for a specific version in metadata. func (h *ComposerHandler) findDownloadURL(metadata map[string]any, packageName, version string) string { packages, ok := metadata["packages"].(map[string]any) diff --git a/internal/handler/composer_test.go b/internal/handler/composer_test.go index baf13b6..9898664 100644 --- a/internal/handler/composer_test.go +++ b/internal/handler/composer_test.go @@ -1,8 +1,11 @@ package handler import ( + "context" "encoding/json" "log/slog" + "net/http" + "net/http/httptest" "strings" "testing" "time" @@ -465,6 +468,100 @@ func TestComposerExpandMinifiedSharedDistReferences(t *testing.T) { } } +// TestComposerDownloadDevVersionUsesDevMetadata is a regression test for the +// bug that made it impossible to install a *-dev dependency from dist. +// +// Packagist serves development versions (e.g. "3.x-dev", "dev-master") from a +// separate "{package}~dev.json" metadata file; the regular "{package}.json" +// file contains only tagged releases. The download handler used to fetch only +// the regular file, so it could never find the dist URL for a dev version and +// returned 404 — causing Composer to silently fall back to a git clone. +// +// This test serves both files from a mock upstream and asserts that: +// - the OLD behavior (regular file only) cannot resolve the dev version, and +// - the FIXED behavior (consulting the ~dev file) does. +func TestComposerDownloadDevVersionUsesDevMetadata(t *testing.T) { + const ( + pkg = "phpmd/phpmd" + vendor = "phpmd" + name = "phpmd" + version = "3.x-dev" + distURL = "https://api.github.com/repos/phpmd/phpmd/zipball/2a9217f60aaf27bf6ddad9188f254d020ab70745" + ) + + // Regular metadata: tagged releases only — no dev versions. + stableBody := `{ + "packages": { + "phpmd/phpmd": [ + {"version": "2.15.0", "dist": {"url": "https://example.com/2.15.0.zip", "type": "zip"}} + ] + } + }` + + // ~dev metadata: where the 3.x-dev version actually lives. + devBody := `{ + "packages": { + "phpmd/phpmd": [ + {"version": "3.x-dev", "dist": {"url": "` + distURL + `", "type": "zip"}} + ] + } + }` + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/p2/phpmd/phpmd.json": + _, _ = w.Write([]byte(stableBody)) + case "/p2/phpmd/phpmd~dev.json": + _, _ = w.Write([]byte(devBody)) + default: + http.NotFound(w, r) + } + })) + defer srv.Close() + + h := &ComposerHandler{ + proxy: testProxy(), + repoURL: srv.URL, + proxyURL: "http://localhost:8080", + } + + ctx := context.Background() + + // OLD behavior: fetching only the regular file fails to resolve the dev + // version, which is what produced the 404 before the fix. + stableURL := srv.URL + "/p2/phpmd/phpmd.json" + got, err := h.findDownloadURLFromMetadata(ctx, stableURL, pkg, version) + if err != nil { + t.Fatalf("unexpected error fetching regular metadata: %v", err) + } + if got != "" { + t.Fatalf("regular metadata unexpectedly contained dev version %q (got %q); "+ + "the test no longer reproduces the original bug", version, got) + } + + // FIXED behavior: the handler consults the ~dev file (it is first in the + // candidate list for dev versions) and resolves the dist URL. + urls := h.metadataURLsForVersion(vendor, name, version) + if len(urls) == 0 || !strings.HasSuffix(urls[0], "/p2/phpmd/phpmd~dev.json") { + t.Fatalf("dev version should consult the ~dev metadata file first, got %v", urls) + } + + var resolved string + for _, u := range urls { + resolved, err = h.findDownloadURLFromMetadata(ctx, u, pkg, version) + if err != nil { + t.Fatalf("unexpected error fetching metadata %q: %v", u, err) + } + if resolved != "" { + break + } + } + + if resolved != distURL { + t.Errorf("dev version dist URL = %q, want %q", resolved, distURL) + } +} + func TestComposerRewriteMetadataCooldown(t *testing.T) { now := time.Now() old := now.Add(-10 * 24 * time.Hour).Format(time.RFC3339) From f4a8c5606a003f737e687552da44943885579813 Mon Sep 17 00:00:00 2001 From: Bruno Clermont Date: Fri, 26 Jun 2026 07:54:00 -0400 Subject: [PATCH 127/131] Fix package redirection to '/ui/packages' (#169) cause I get 404 every time --- internal/server/templates/pages/packages_list.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/server/templates/pages/packages_list.html b/internal/server/templates/pages/packages_list.html index 5ef42c7..95897db 100644 --- a/internal/server/templates/pages/packages_list.html +++ b/internal/server/templates/pages/packages_list.html @@ -100,7 +100,7 @@ document.getElementById('ecosystem-filter').addEventListener('change', function( const params = new URLSearchParams(); if (ecosystem) params.set('ecosystem', ecosystem); if (sortBy) params.set('sort', sortBy); - window.location.href = '/packages?' + params.toString(); + window.location.href = '/ui/packages?' + params.toString(); }); document.getElementById('sort-by').addEventListener('change', function(e) { @@ -109,7 +109,7 @@ document.getElementById('sort-by').addEventListener('change', function(e) { const params = new URLSearchParams(); if (ecosystem) params.set('ecosystem', ecosystem); if (sortBy) params.set('sort', sortBy); - window.location.href = '/packages?' + params.toString(); + window.location.href = '/ui/packages?' + params.toString(); }); {{end}} From bb214bb7b2c771c8c8d36213027456491f47b648 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Mon, 29 Jun 2026 14:43:49 +0100 Subject: [PATCH 128/131] Bump git-pkgs and third-party dependencies (#177) --- go.mod | 28 +++++++++++------------ go.sum | 70 ++++++++++++++++++++++++++++++---------------------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/go.mod b/go.mod index a1b22d6..471ab53 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,12 @@ require ( github.com/CycloneDX/cyclonedx-go v0.11.0 github.com/git-pkgs/archives v0.3.0 github.com/git-pkgs/cooldown v0.1.1 - github.com/git-pkgs/enrichment v0.3.0 - github.com/git-pkgs/purl v0.1.12 - github.com/git-pkgs/registries v0.6.1 + github.com/git-pkgs/enrichment v0.4.1 + github.com/git-pkgs/purl v0.1.13 + github.com/git-pkgs/registries v0.6.2 github.com/git-pkgs/spdx v0.1.4 github.com/git-pkgs/vers v0.2.6 - github.com/git-pkgs/vulns v0.1.5 + github.com/git-pkgs/vulns v0.1.6 github.com/go-chi/chi/v5 v5.3.0 github.com/jmoiron/sqlx v1.4.0 github.com/lib/pq v1.12.3 @@ -24,7 +24,7 @@ require ( golang.org/x/sync v0.21.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.52.0 + modernc.org/sqlite v1.53.0 ) require ( @@ -115,7 +115,7 @@ require ( github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ecosyste-ms/ecosystems-go v0.1.1 // indirect + github.com/ecosyste-ms/ecosystems-go v0.2.0 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect github.com/fatih/color v1.18.0 // indirect @@ -125,7 +125,7 @@ require ( github.com/fzipp/gocyclo v0.6.0 // indirect github.com/ghostiam/protogetter v0.3.20 // indirect github.com/git-pkgs/packageurl-go v0.3.1 // indirect - github.com/git-pkgs/pom v0.1.4 // indirect + github.com/git-pkgs/pom v0.1.5 // indirect github.com/github/go-spdx/v2 v2.7.0 // indirect github.com/go-critic/go-critic v0.14.3 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -217,7 +217,7 @@ require ( github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/nunnatsa/ginkgolinter v0.23.0 // indirect - github.com/oapi-codegen/runtime v1.2.0 // indirect + github.com/oapi-codegen/runtime v1.4.1 // indirect github.com/package-url/packageurl-go v0.1.6 // indirect github.com/pandatix/go-cvss v0.6.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -291,15 +291,15 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.49.0 // indirect + golang.org/x/crypto v0.51.0 // indirect golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.52.0 // indirect + golang.org/x/mod v0.36.0 // indirect + golang.org/x/net v0.54.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.35.0 // indirect - golang.org/x/tools v0.42.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/tools v0.45.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.272.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect @@ -307,7 +307,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect honnef.co/go/tools v0.7.0 // indirect - modernc.org/libc v1.72.3 // indirect + modernc.org/libc v1.73.4 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect mvdan.cc/gofumpt v0.9.2 // indirect diff --git a/go.sum b/go.sum index c1a5bb8..8d8c96d 100644 --- a/go.sum +++ b/go.sum @@ -217,8 +217,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ecosyste-ms/ecosystems-go v0.1.1 h1:YYiBK9TCCTeE+BtmpN2FssaRFcmF+T0v4LrupIOjehQ= -github.com/ecosyste-ms/ecosystems-go v0.1.1/go.mod h1:VczXs1CO9nL8XbL1NwvgmwIaqzMsAxcsXnTpRtwi9gU= +github.com/ecosyste-ms/ecosystems-go v0.2.0 h1:Nhpg54C+St8Sd/mf8bNJmQqx35ZgHw33TfFoxaXMQI8= +github.com/ecosyste-ms/ecosystems-go v0.2.0/go.mod h1:CCdzT1iAZirbEZAbFSnWpK88eKKaIWex7gjtZ0UudXA= github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= @@ -248,22 +248,22 @@ github.com/git-pkgs/archives v0.3.0 h1:iXKyO83jEFub1PGEDlHmk2tQ7XeV5LySTc0sEkH3x github.com/git-pkgs/archives v0.3.0/go.mod h1:LTJ1iQVFA7otizWMOyiI82NYVmyBWAPRzwu/e30rcXU= github.com/git-pkgs/cooldown v0.1.1 h1:9OqqzCB8gANz/y44SmqGD0Jp8Qtu81D1sCbKl6Ehg7w= github.com/git-pkgs/cooldown v0.1.1/go.mod h1:v7APuK/UouTiu8mWQZbdDmj7DfxxkGUeuhjaRB5gv9E= -github.com/git-pkgs/enrichment v0.3.0 h1:tsATMAwR/qcSIw4JV37uH2TBgTv415RfJC7w3nzWfD4= -github.com/git-pkgs/enrichment v0.3.0/go.mod h1:MBv5nhHzjwLxeSgx2+7waCcpReUjhCD+9B0bvufpMO0= +github.com/git-pkgs/enrichment v0.4.1 h1:A8BKs0XwvpF1sF5qviZy4fkJAe18qB9OgpbRnmwnT34= +github.com/git-pkgs/enrichment v0.4.1/go.mod h1:stHqZUitV9ZkwACqHzBysLMSe6T4QZn81hxTdSroNhM= github.com/git-pkgs/packageurl-go v0.3.1 h1:WM3RBABQZLaRBxgKyYughc3cVBE8KyQxbSC6Jt5ak7M= github.com/git-pkgs/packageurl-go v0.3.1/go.mod h1:rcIxiG37BlQLB6FZfgdj9Fm7yjhRQd3l+5o7J0QPAk4= -github.com/git-pkgs/pom v0.1.4 h1:C6st+XSbF75eKuwfdkDZZtYHoTcaWRIEQYar5VtszUo= -github.com/git-pkgs/pom v0.1.4/go.mod h1:ufdMBe1lKzqOeP9IUb9NPZ458xKV8E8NvuyBMxOfwIk= -github.com/git-pkgs/purl v0.1.12 h1:qCskrEU1LWQhCkIVZd992W5++Bsxazvx2Cx1/65qCvU= -github.com/git-pkgs/purl v0.1.12/go.mod h1:ofp4mHsR0cUeVONQaf33n6Wxg2QTEvtUdRfCedI8ouA= -github.com/git-pkgs/registries v0.6.1 h1:xZfVZQmffIfdeJthn5o2EozbVJ6gBeImYwKQnfdKUfU= -github.com/git-pkgs/registries v0.6.1/go.mod h1:a3BP/56VW3O/CFRqiJCtSy+OqRrSH25wF1PWHP76ka0= +github.com/git-pkgs/pom v0.1.5 h1:TGT8Az2OMxGWsXnSagtUMGzZm7Oax8HrSCteA+mi0qY= +github.com/git-pkgs/pom v0.1.5/go.mod h1:ufdMBe1lKzqOeP9IUb9NPZ458xKV8E8NvuyBMxOfwIk= +github.com/git-pkgs/purl v0.1.13 h1:at8BU6vnP5oonHFHAPA064BzgRqij+SZcOUDgNT2DC8= +github.com/git-pkgs/purl v0.1.13/go.mod h1:8oCcdcYZA/e1B33e7Ylju6azboTKjdqf3ybcbQj6I/o= +github.com/git-pkgs/registries v0.6.2 h1:26G5zW6Q7x1CSfNkaEqEjRMJiA4JwfdKOCJ7Qm+u0a8= +github.com/git-pkgs/registries v0.6.2/go.mod h1:GR0Bu6nC3NQe6f7lfDoEVqAnoQkMocf4M98B12a7B3E= github.com/git-pkgs/spdx v0.1.4 h1:eQ0waEV3uUeItpWAOvdN1K1rL9hTgsU7fF74r1mDXMs= github.com/git-pkgs/spdx v0.1.4/go.mod h1:cqRoZcvl530s/W+oGNvwjt4ODN8T1W6D/20MUZEFdto= github.com/git-pkgs/vers v0.2.6 h1:IelZd7BP/JhzTloUTDY67nehUgoYva3g9viqAMCHJg8= github.com/git-pkgs/vers v0.2.6/go.mod h1:biTbSQK1qdbrsxDEKnqe3Jzclxz8vW6uDcwKjfUGcOo= -github.com/git-pkgs/vulns v0.1.5 h1:mtX88/27toFl+B95kaH5QbAdOCQ3YIDGjJrlrrnqQTE= -github.com/git-pkgs/vulns v0.1.5/go.mod h1:bZFikfrR/5gC0ZMwXh7qcEu2gpKfXMBhVsy4kF12Ae0= +github.com/git-pkgs/vulns v0.1.6 h1:8RRSgdlxp4JMU0Zykr63XTOMo5CyZKwt/PwaQxrx9Yg= +github.com/git-pkgs/vulns v0.1.6/go.mod h1:TsZC4MjoCkKJslgmbcmRCnytwnFcjESC2N8b0a2xDWc= github.com/github/go-spdx/v2 v2.7.0 h1:GzfXx4wFdlilARxmFRXW/mgUy3A4vSqZocCMFV6XFdQ= github.com/github/go-spdx/v2 v2.7.0/go.mod h1:Ftc45YYG1WzpzwEPKRVm9Jv8vDqOrN4gWoCkK+bHer0= github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM= @@ -510,8 +510,10 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8= github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4= -github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +github.com/oapi-codegen/nullable v1.1.0 h1:eAh8JVc5430VtYVnq00Hrbpag9PFRGWLjxR1/3KntMs= +github.com/oapi-codegen/nullable v1.1.0/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY= +github.com/oapi-codegen/runtime v1.4.1 h1:9nwLoI+KrWxzbBcp0jO/R8uXqbik/HUyCvPeU68Y/qo= +github.com/oapi-codegen/runtime v1.4.1/go.mod h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU= github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= @@ -736,8 +738,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -753,8 +755,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -769,8 +771,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -821,8 +823,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -837,8 +839,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -880,20 +882,20 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU= honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc= -modernc.org/cc/v4 v4.28.2 h1:3tQ0lf2ADtoby2EtSP+J7IE2SHwEJdP8ioR59wx7XpY= -modernc.org/cc/v4 v4.28.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= -modernc.org/ccgo/v4 v4.34.0 h1:yRLPFZieg532OT4rp4JFNIVcquwalMX26G95WQDqwCQ= -modernc.org/ccgo/v4 v4.34.0/go.mod h1:AS5WYMyBakQ+fhsHhtP8mWB82KTGPkNNJDGfGQCe0/A= +modernc.org/cc/v4 v4.28.4 h1:Hd/4Es+MBj+/7hSdZaisNyu6bv3V0Dp2MdllyfqaH+c= +modernc.org/cc/v4 v4.28.4/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= +modernc.org/ccgo/v4 v4.34.4 h1:OVnSOWQjVKOYkFxoHYB+qQmSHK5gqMqARM+K9DpR/Ws= +modernc.org/ccgo/v4 v4.34.4/go.mod h1:qdKqE8FNIYyysougB1RX9MxCzp5oJOcQXSobANJ4TuE= modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= -modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/gc/v3 v3.1.3 h1:6QAplYyVO+KdPW3pGnqmJDUxtkec8ooEWvks/hhU3lc= +modernc.org/gc/v3 v3.1.3/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.72.3 h1:ZnDF4tXn4NBXFutMMQC4vtbTFSXhhKzR73fv0beZEAU= -modernc.org/libc v1.72.3/go.mod h1:dn0dZNnnn1clLyvRxLxYExxiKRZIRENOfqQ8XEeg4Qs= +modernc.org/libc v1.73.4 h1:+ra4Ui8ngyt8HDcO1FTDPWlkAh6yOdaO2yAoh8MddQA= +modernc.org/libc v1.73.4/go.mod h1:DXZ3eO8qMCNn2SnmTNCiC71nJ9Rcq3PsnpU6Vc4rWK8= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -902,8 +904,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0/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.52.0 h1:p4dhYh2tXZCiyaqHwRVJDjIGKWyXayiQpThxgDzJaxo= -modernc.org/sqlite v1.52.0/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= +modernc.org/sqlite v1.53.0 h1:20WG8N9q4ji/dEqGk4uiI0c6OPjSeLTNYGFCc3+7c1M= +modernc.org/sqlite v1.53.0/go.mod h1:xoEpOIpGrgT48H5iiyt/YXPCZPEzlfmfFwtk8Lklw8s= 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= From 787b76dfe7d503e19de0dc0cfd9736ab471386ac Mon Sep 17 00:00:00 2001 From: Philipp Dieter Date: Tue, 30 Jun 2026 13:25:49 +0200 Subject: [PATCH 129/131] Fix Composer 404 on minified metadata and add debug logging - Expand minified Composer v2 metadata in findDownloadURLFromMetadata so versions that inherit dist from a previous entry resolve correctly - Add Debug()-level log statements in the download resolution path (handleDownload, findDownloadURLFromMetadata) so -log-level debug produces meaningful output --- internal/handler/composer.go | 39 +++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/internal/handler/composer.go b/internal/handler/composer.go index e4dec41..bc3bc1d 100644 --- a/internal/handler/composer.go +++ b/internal/handler/composer.go @@ -316,6 +316,10 @@ func (h *ComposerHandler) handleDownload(w http.ResponseWriter, r *http.Request) // stable and dev versions resolve correctly. metaURLs := h.metadataURLsForVersion(vendor, pkg, version) + h.proxy.Logger.Debug("resolving download URL", + "package", packageName, "version", version, + "metadata_urls", metaURLs) + var downloadURL string for _, metaURL := range metaURLs { url, err := h.findDownloadURLFromMetadata(r.Context(), metaURL, packageName, version) @@ -331,10 +335,17 @@ func (h *ComposerHandler) handleDownload(w http.ResponseWriter, r *http.Request) } if downloadURL == "" { + h.proxy.Logger.Debug("version not found in any metadata source", + "package", packageName, "version", version, + "tried_urls", metaURLs) http.Error(w, "version not found", http.StatusNotFound) return } + h.proxy.Logger.Debug("resolved download URL", + "package", packageName, "version", version, + "download_url", downloadURL) + result, err := h.proxy.GetOrFetchArtifactFromURL(r.Context(), "composer", packageName, version, filename, downloadURL) if err != nil { h.proxy.Logger.Error("failed to get artifact", "error", err) @@ -372,6 +383,9 @@ func (h *ComposerHandler) metadataURLsForVersion(vendor, pkg, version string) [] // An error is returned only on transport failure; a missing document (non-200) // or a missing version both yield an empty string so the caller can fall back. func (h *ComposerHandler) findDownloadURLFromMetadata(ctx context.Context, metaURL, packageName, version string) (string, error) { + h.proxy.Logger.Debug("fetching upstream metadata for download lookup", + "url", metaURL, "package", packageName, "version", version) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, metaURL, nil) if err != nil { return "", err @@ -383,6 +397,9 @@ func (h *ComposerHandler) findDownloadURLFromMetadata(ctx context.Context, metaU } defer func() { _ = resp.Body.Close() }() + h.proxy.Logger.Debug("upstream metadata response", + "url", metaURL, "status", resp.StatusCode) + if resp.StatusCode != http.StatusOK { return "", nil } @@ -392,7 +409,27 @@ func (h *ComposerHandler) findDownloadURLFromMetadata(ctx context.Context, metaU return "", err } - return h.findDownloadURL(metadata, packageName, version), nil + // Expand minified Composer v2 format so that inherited fields (including + // dist) are present on every version entry. Without this, versions that + // inherit dist from a previous entry will appear to have no download URL. + if metadata["minified"] == "composer/2.0" { + h.proxy.Logger.Debug("expanding minified metadata", "url", metaURL) + if packages, ok := metadata["packages"].(map[string]any); ok { + for pkgName, versions := range packages { + versionList, ok := versions.([]any) + if !ok { + continue + } + packages[pkgName] = expandMinifiedVersions(versionList) + } + } + } + + url := h.findDownloadURL(metadata, packageName, version) + h.proxy.Logger.Debug("download URL lookup result", + "url", metaURL, "package", packageName, "version", version, + "download_url", url) + return url, nil } // findDownloadURL finds the dist URL for a specific version in metadata. From 81d19b7632bbc0cbb5a24cdc29f1ad6534cc1e1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:13:19 +0000 Subject: [PATCH 130/131] Bump zizmorcore/zizmor-action from 0.5.6 to 0.5.7 Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.5.6 to 0.5.7. - [Release notes](https://github.com/zizmorcore/zizmor-action/releases) - [Commits](https://github.com/zizmorcore/zizmor-action/compare/5f14fd08f7cf1cb1609c1e344975f152c7ee938d...192e21d79ab29983730a13d1382995c2307fbcaa) --- updated-dependencies: - dependency-name: zizmorcore/zizmor-action dependency-version: 0.5.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/zizmor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index b404599..cce6e4f 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -26,4 +26,4 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 From a8c0562c97fe20619e75b5d0295889f36178055b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:13:48 +0000 Subject: [PATCH 131/131] Bump actions/setup-go from 6.4.0 to 6.5.0 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.4.0 to 6.5.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/4a3601121dd01d1626a1e23e37211e3254c1c06c...924ae3a1cded613372ab5595356fb5720e22ba16) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 6.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/swagger.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1a2abb..700f28e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: persist-credentials: false - name: Set up Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version: ${{ matrix.go-version }} @@ -40,7 +40,7 @@ jobs: persist-credentials: false - name: Set up Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version: '1.25' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7d8ae5..f7833fb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: Set up Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod cache: false diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index b6e086a..f947c7e 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -17,7 +17,7 @@ jobs: persist-credentials: false - name: Set up Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version: '1.25'