Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 8 additions & 31 deletions internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/proxy/internal/metrics"
"github.com/git-pkgs/proxy/internal/storage"
"github.com/git-pkgs/purl"
"github.com/git-pkgs/registries/fetch"
)

Expand Down Expand Up @@ -50,8 +51,8 @@ type CacheResult struct {

// GetOrFetchArtifact retrieves an artifact from cache or fetches from upstream.
func (p *Proxy) GetOrFetchArtifact(ctx context.Context, ecosystem, name, version, filename string) (*CacheResult, error) {
pkgPURL := fmt.Sprintf("pkg:%s/%s", ecosystem, name)
versionPURL := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, version)
pkgPURL := purl.MakePURLString(ecosystem, name, "")
versionPURL := purl.MakePURLString(ecosystem, name, version)

if cached, err := p.checkCache(ctx, pkgPURL, versionPURL, filename); err != nil {
return nil, err
Expand Down Expand Up @@ -101,8 +102,9 @@ func (p *Proxy) checkCache(ctx context.Context, pkgPURL, versionPURL, filename s
_ = p.DB.RecordArtifactHit(versionPURL, filename)

// Extract ecosystem from pkgPURL for metrics
ecosystem := extractEcosystem(pkgPURL)
metrics.RecordCacheHit(ecosystem)
if p, err := purl.Parse(pkgPURL); err == nil {
metrics.RecordCacheHit(purl.PURLTypeToEcosystem(p.Type))
}

return &CacheResult{
Reader: reader,
Expand Down Expand Up @@ -251,8 +253,8 @@ func JSONError(w http.ResponseWriter, status int, message string) {
// GetOrFetchArtifactFromURL retrieves an artifact from cache or fetches from a specific URL.
// This is useful for registries where download URLs are determined from metadata.
func (p *Proxy) GetOrFetchArtifactFromURL(ctx context.Context, ecosystem, name, version, filename, downloadURL string) (*CacheResult, error) {
pkgPURL := fmt.Sprintf("pkg:%s/%s", ecosystem, name)
versionPURL := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, version)
pkgPURL := purl.MakePURLString(ecosystem, name, "")
versionPURL := purl.MakePURLString(ecosystem, name, version)

if cached, err := p.checkCache(ctx, pkgPURL, versionPURL, filename); err != nil {
return nil, err
Expand Down Expand Up @@ -297,28 +299,3 @@ func (p *Proxy) fetchAndCacheFromURL(ctx context.Context, ecosystem, name, versi
}, nil
}

// extractEcosystem extracts the ecosystem from a package PURL.
// PURL format: pkg:ecosystem/name[@version]
func extractEcosystem(purl string) string {
if len(purl) < 5 || !startsWith(purl, "pkg:") {
return "unknown"
}
rest := purl[4:] // Skip "pkg:"
if idx := indexOf(rest, "/"); idx != -1 {
return rest[:idx]
}
return "unknown"
}

func startsWith(s, prefix string) bool {
return len(s) >= len(prefix) && s[:len(prefix)] == prefix
}

func indexOf(s, substr string) int {
for i := 0; i+len(substr) <= len(s); i++ {
if s[i:i+len(substr)] == substr {
return i
}
}
return -1
}
28 changes: 10 additions & 18 deletions internal/server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"strings"

shared "github.com/git-pkgs/enrichment"
"github.com/go-chi/chi/v5"
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/proxy/internal/enrichment"
"github.com/git-pkgs/purl"
"github.com/go-chi/chi/v5"
)

// APIHandler provides REST endpoints for package enrichment data.
Expand Down Expand Up @@ -357,24 +358,15 @@ func (h *APIHandler) HandleBulkLookup(w http.ResponseWriter, r *http.Request) {
} else {
// Fall back to individual lookups via registries
packages := make([]struct{ Ecosystem, Name string }, 0, len(req.PURLs))
purlMap := make(map[string]string) // map from "ecosystem/name" to original purl

for _, purl := range req.PURLs {
// Parse PURL to extract ecosystem and name
// Format: pkg:ecosystem/name@version
if strings.HasPrefix(purl, "pkg:") {
parts := strings.SplitN(purl[4:], "/", 2)
if len(parts) == 2 {
ecosystem := parts[0]
namePart := parts[1]
// Remove version if present
if idx := strings.Index(namePart, "@"); idx > 0 {
namePart = namePart[:idx]
}
packages = append(packages, struct{ Ecosystem, Name string }{ecosystem, namePart})
purlMap[ecosystem+"/"+namePart] = purl
}

for _, purlStr := range req.PURLs {
p, err := purl.Parse(purlStr)
if err != nil {
continue
}
ecosystem := purl.PURLTypeToEcosystem(p.Type)
name := p.FullName()
packages = append(packages, struct{ Ecosystem, Name string }{ecosystem, name})
}

results := h.enrichment.BulkEnrichPackages(r.Context(), packages)
Expand Down
15 changes: 8 additions & 7 deletions internal/server/browse.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (
"strings"

"github.com/git-pkgs/archives"
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/archives/diff"
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/purl"
"github.com/go-chi/chi/v5"
)

Expand Down Expand Up @@ -49,8 +50,8 @@ func (s *Server) handleBrowseList(w http.ResponseWriter, r *http.Request) {
dirPath := r.URL.Query().Get("path")

// Get the artifact for this version
purl := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, version)
artifacts, err := s.db.GetArtifactsByVersionPURL(purl)
versionPURL := purl.MakePURLString(ecosystem, name, version)
artifacts, err := s.db.GetArtifactsByVersionPURL(versionPURL)
if err != nil {
http.Error(w, "version not found", http.StatusNotFound)
return
Expand Down Expand Up @@ -137,8 +138,8 @@ func (s *Server) handleBrowseFile(w http.ResponseWriter, r *http.Request) {
}

// Get the artifact for this version
purl := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, version)
artifacts, err := s.db.GetArtifactsByVersionPURL(purl)
versionPURL := purl.MakePURLString(ecosystem, name, version)
artifacts, err := s.db.GetArtifactsByVersionPURL(versionPURL)
if err != nil {
http.Error(w, "version not found", http.StatusNotFound)
return
Expand Down Expand Up @@ -345,8 +346,8 @@ func (s *Server) handleCompareDiff(w http.ResponseWriter, r *http.Request) {
toVersion := chi.URLParam(r, "toVersion")

// Get artifacts for both versions
fromPURL := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, fromVersion)
toPURL := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, toVersion)
fromPURL := purl.MakePURLString(ecosystem, name, fromVersion)
toPURL := purl.MakePURLString(ecosystem, name, toVersion)

fromArtifacts, err := s.db.GetArtifactsByVersionPURL(fromPURL)
if err != nil || len(fromArtifacts) == 0 {
Expand Down
11 changes: 6 additions & 5 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,17 @@ import (
"strconv"
"time"

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/git-pkgs/proxy/internal/config"
"github.com/git-pkgs/proxy/internal/database"
"github.com/git-pkgs/proxy/internal/enrichment"
"github.com/git-pkgs/proxy/internal/handler"
"github.com/git-pkgs/proxy/internal/metrics"
"github.com/git-pkgs/proxy/internal/storage"
"github.com/git-pkgs/purl"
"github.com/git-pkgs/registries/fetch"
"github.com/git-pkgs/spdx"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)

// Server is the main proxy server.
Expand Down Expand Up @@ -613,15 +614,15 @@ func (s *Server) handleVersionShow(w http.ResponseWriter, r *http.Request) {
return
}

purl := fmt.Sprintf("pkg:%s/%s@%s", ecosystem, name, version)
ver, err := s.db.GetVersionByPURL(purl)
versionPURL := purl.MakePURLString(ecosystem, name, version)
ver, err := s.db.GetVersionByPURL(versionPURL)
if err != nil || ver == nil {
s.logger.Error("failed to get version", "error", err)
http.Error(w, "version not found", http.StatusNotFound)
return
}

artifacts, err := s.db.GetArtifactsByVersionPURL(purl)
artifacts, err := s.db.GetArtifactsByVersionPURL(versionPURL)
if err != nil {
s.logger.Error("failed to get artifacts", "error", err)
artifacts = []database.Artifact{}
Expand Down