2026-01-20 21:52:44 +00:00
|
|
|
package database
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"database/sql"
|
2026-01-29 16:44:01 +00:00
|
|
|
"strings"
|
2026-01-20 21:52:44 +00:00
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2026-01-29 16:44:01 +00:00
|
|
|
// Package represents a package in the database.
|
|
|
|
|
// Schema is compatible with git-pkgs.
|
2026-01-20 21:52:44 +00:00
|
|
|
type Package struct {
|
2026-01-29 16:44:01 +00:00
|
|
|
ID int64 `db:"id" json:"id"`
|
|
|
|
|
PURL string `db:"purl" json:"purl"`
|
|
|
|
|
Ecosystem string `db:"ecosystem" json:"ecosystem"`
|
|
|
|
|
Name string `db:"name" json:"name"`
|
|
|
|
|
LatestVersion sql.NullString `db:"latest_version" json:"latest_version,omitempty"`
|
|
|
|
|
License sql.NullString `db:"license" json:"license,omitempty"`
|
|
|
|
|
Description sql.NullString `db:"description" json:"description,omitempty"`
|
|
|
|
|
Homepage sql.NullString `db:"homepage" json:"homepage,omitempty"`
|
|
|
|
|
RepositoryURL sql.NullString `db:"repository_url" json:"repository_url,omitempty"`
|
|
|
|
|
RegistryURL sql.NullString `db:"registry_url" json:"registry_url,omitempty"`
|
|
|
|
|
SupplierName sql.NullString `db:"supplier_name" json:"supplier_name,omitempty"`
|
|
|
|
|
SupplierType sql.NullString `db:"supplier_type" json:"supplier_type,omitempty"`
|
|
|
|
|
Source sql.NullString `db:"source" json:"source,omitempty"`
|
|
|
|
|
EnrichedAt sql.NullTime `db:"enriched_at" json:"enriched_at,omitempty"`
|
|
|
|
|
VulnsSyncedAt sql.NullTime `db:"vulns_synced_at" json:"vulns_synced_at,omitempty"`
|
|
|
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
|
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
2026-01-20 21:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 16:44:01 +00:00
|
|
|
// Version represents a package version in the database.
|
|
|
|
|
// Schema is compatible with git-pkgs.
|
2026-01-20 21:52:44 +00:00
|
|
|
type Version struct {
|
2026-01-29 16:44:01 +00:00
|
|
|
ID int64 `db:"id" json:"id"`
|
|
|
|
|
PURL string `db:"purl" json:"purl"`
|
|
|
|
|
PackagePURL string `db:"package_purl" json:"package_purl"`
|
|
|
|
|
License sql.NullString `db:"license" json:"license,omitempty"`
|
|
|
|
|
PublishedAt sql.NullTime `db:"published_at" json:"published_at,omitempty"`
|
|
|
|
|
Integrity sql.NullString `db:"integrity" json:"integrity,omitempty"`
|
|
|
|
|
Yanked bool `db:"yanked" json:"yanked"`
|
|
|
|
|
Source sql.NullString `db:"source" json:"source,omitempty"`
|
|
|
|
|
EnrichedAt sql.NullTime `db:"enriched_at" json:"enriched_at,omitempty"`
|
|
|
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
|
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
2026-01-20 21:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 16:44:01 +00:00
|
|
|
// Version extracts the version string from the PURL.
|
|
|
|
|
// e.g., "pkg:npm/lodash@4.17.21" -> "4.17.21"
|
|
|
|
|
func (v *Version) Version() string {
|
|
|
|
|
if idx := strings.LastIndex(v.PURL, "@"); idx >= 0 {
|
|
|
|
|
return v.PURL[idx+1:]
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Artifact represents a cached artifact in the database.
|
|
|
|
|
// This table is proxy-specific and not part of git-pkgs.
|
2026-01-20 21:52:44 +00:00
|
|
|
type Artifact struct {
|
2026-01-29 16:06:56 +00:00
|
|
|
ID int64 `db:"id" json:"id"`
|
2026-01-29 16:44:01 +00:00
|
|
|
VersionPURL string `db:"version_purl" json:"version_purl"`
|
2026-01-29 16:06:56 +00:00
|
|
|
Filename string `db:"filename" json:"filename"`
|
|
|
|
|
UpstreamURL string `db:"upstream_url" json:"upstream_url"`
|
|
|
|
|
StoragePath sql.NullString `db:"storage_path" json:"storage_path,omitempty"`
|
|
|
|
|
ContentHash sql.NullString `db:"content_hash" json:"content_hash,omitempty"`
|
|
|
|
|
Size sql.NullInt64 `db:"size" json:"size,omitempty"`
|
|
|
|
|
ContentType sql.NullString `db:"content_type" json:"content_type,omitempty"`
|
|
|
|
|
FetchedAt sql.NullTime `db:"fetched_at" json:"fetched_at,omitempty"`
|
|
|
|
|
HitCount int64 `db:"hit_count" json:"hit_count"`
|
|
|
|
|
LastAccessedAt sql.NullTime `db:"last_accessed_at" json:"last_accessed_at,omitempty"`
|
|
|
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
|
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
2026-01-20 21:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 16:44:01 +00:00
|
|
|
// IsCached returns true if the artifact has been fetched and stored locally.
|
2026-01-20 21:52:44 +00:00
|
|
|
func (a *Artifact) IsCached() bool {
|
|
|
|
|
return a.StoragePath.Valid && a.FetchedAt.Valid
|
|
|
|
|
}
|
2026-01-29 19:35:15 +00:00
|
|
|
|
2026-03-19 21:06:02 +00:00
|
|
|
// MetadataCacheEntry represents a cached metadata blob for offline serving.
|
|
|
|
|
type MetadataCacheEntry struct {
|
Fix metadata caching, 404 propagation, mirror progress, and registry stubs
- ProxyCached now stores upstream Last-Modified in the cache and uses it
(along with ETag) for conditional request handling, returning 304 when
client validators match. Adds Content-Length to cached responses.
- Handlers calling FetchOrCacheMetadata (pypi, composer, pub, nuget) now
check for ErrUpstreamNotFound and return 404 instead of 502, matching
the existing npm and cargo behavior.
- Mirror jobs report live progress via a periodic callback while running,
so API polls return real counts instead of zeroed progress.
- Registry mirroring removed from CLI flags, API acceptance, README, and
docs since every enumerator was a stub returning "not yet implemented".
- Added tests for the conditional metadata path (ETag/If-None-Match,
Last-Modified/If-Modified-Since, 304 responses, header omission).
2026-04-01 20:14:11 +01:00
|
|
|
ID int64 `db:"id" json:"id"`
|
|
|
|
|
Ecosystem string `db:"ecosystem" json:"ecosystem"`
|
|
|
|
|
Name string `db:"name" json:"name"`
|
|
|
|
|
StoragePath string `db:"storage_path" json:"storage_path"`
|
|
|
|
|
ETag sql.NullString `db:"etag" json:"etag,omitempty"`
|
|
|
|
|
ContentType sql.NullString `db:"content_type" json:"content_type,omitempty"`
|
|
|
|
|
Size sql.NullInt64 `db:"size" json:"size,omitempty"`
|
|
|
|
|
LastModified sql.NullTime `db:"last_modified" json:"last_modified,omitempty"`
|
|
|
|
|
FetchedAt sql.NullTime `db:"fetched_at" json:"fetched_at,omitempty"`
|
|
|
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
|
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
2026-03-19 21:06:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 19:35:15 +00:00
|
|
|
// Vulnerability represents a cached vulnerability record.
|
|
|
|
|
type Vulnerability struct {
|
2026-04-18 07:43:22 -04:00
|
|
|
ID int64 `db:"id" json:"id"`
|
|
|
|
|
VulnID string `db:"vuln_id" json:"vuln_id"`
|
|
|
|
|
Ecosystem string `db:"ecosystem" json:"ecosystem"`
|
|
|
|
|
PackageName string `db:"package_name" json:"package_name"`
|
|
|
|
|
Severity sql.NullString `db:"severity" json:"severity,omitempty"`
|
|
|
|
|
Summary sql.NullString `db:"summary" json:"summary,omitempty"`
|
|
|
|
|
FixedVersion sql.NullString `db:"fixed_version" json:"fixed_version,omitempty"`
|
2026-01-29 19:35:15 +00:00
|
|
|
CVSSScore sql.NullFloat64 `db:"cvss_score" json:"cvss_score,omitempty"`
|
2026-04-18 07:43:22 -04:00
|
|
|
References sql.NullString `db:"references" json:"references,omitempty"`
|
|
|
|
|
FetchedAt sql.NullTime `db:"fetched_at" json:"fetched_at,omitempty"`
|
|
|
|
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
|
|
|
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
2026-01-29 19:35:15 +00:00
|
|
|
}
|