package server import ( "html/template" "github.com/git-pkgs/proxy/internal/database" ) // DashboardData contains data for rendering the dashboard. type DashboardData struct { Stats DashboardStats EnrichmentStats EnrichmentStatsView RecentPackages []PackageInfo PopularPackages []PackageInfo } // DashboardStats contains cache statistics for the dashboard. type DashboardStats struct { CachedArtifacts int64 TotalSize string TotalPackages int64 TotalVersions int64 } // EnrichmentStatsView contains enrichment statistics for display. type EnrichmentStatsView struct { EnrichedPackages int64 VulnSyncedPackages int64 TotalVulnerabilities int64 CriticalVulns int64 HighVulns int64 MediumVulns int64 LowVulns int64 HasVulns bool } // PackageInfo contains information about a cached package. type PackageInfo struct { Ecosystem string Name string Version string Size string Hits int64 CachedAt string License string LicenseCategory string VulnCount int64 LatestVersion string IsOutdated bool } // RegistryConfig contains configuration instructions for a package registry. type RegistryConfig struct { ID string Name string Language string Endpoint string Instructions template.HTML } // PackageShowData contains data for rendering the package show page. type PackageShowData struct { Package *database.Package Versions []database.Version Vulnerabilities []database.Vulnerability LicenseCategory string } // VersionShowData contains data for rendering the version show page. type VersionShowData struct { Package *database.Package Version *database.Version Artifacts []database.Artifact Vulnerabilities []database.Vulnerability IsOutdated bool LicenseCategory string HasCachedArtifact bool } // SearchPageData contains data for rendering the search results page. type SearchPageData struct { Query string Ecosystem string Results []SearchResultItem Count int Page int PerPage int TotalPages int } // SearchResultItem represents a single search result for display. type SearchResultItem struct { Ecosystem string Name string LatestVersion string License string LicenseCategory string Hits int64 Size int64 SizeFormatted string CachedAt string VulnCount int64 } // PackagesListPageData contains data for rendering the packages list page. type PackagesListPageData struct { Ecosystem string SortBy string Results []SearchResultItem Count int Page int PerPage int TotalPages int } func supportedEcosystems() []string { // this list should be kept sorted in lexicographic order so // that the 'select' list in the UI will be in the expected // order return []string{ "cargo", "composer", "conan", "conda", "cran", "deb", "gem", "golang", "hex", "maven", "npm", "nuget", "oci", "pub", "pypi", "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{ { ID: "npm", Name: "npm", Language: "JavaScript", Endpoint: "/npm/", Instructions: template.HTML(`
Configure npm to use the proxy:
# In ~/.npmrc or project .npmrc
registry=` + baseURL + `/npm/
# Or via environment variable
npm_config_registry=` + baseURL + `/npm/ npm install`),
},
{
ID: "cargo",
Name: "Cargo",
Language: "Rust",
Endpoint: "/cargo/",
Instructions: template.HTML(`Configure Cargo to use the proxy (sparse index protocol):
# In ~/.cargo/config.toml or project .cargo/config.toml
[source.crates-io]
replace-with = "proxy"
[source.proxy]
registry = "sparse+` + baseURL + `/cargo/"`),
},
{
ID: "gem",
Name: "RubyGems",
Language: "Ruby",
Endpoint: "/gem/",
Instructions: template.HTML(`Configure Bundler/RubyGems to use the proxy:
# In Gemfile
source "` + baseURL + `/gem"
# Or configure globally
gem sources --add ` + baseURL + `/gem/
bundle config mirror.https://rubygems.org ` + baseURL + `/gem`),
},
{
ID: "go",
Name: "Go Modules",
Language: "Go",
Endpoint: "/go/",
Instructions: template.HTML(`Set the GOPROXY environment variable:
export GOPROXY=` + baseURL + `/go,direct
# Add to your shell profile for persistence`),
},
{
ID: "hex",
Name: "Hex",
Language: "Elixir",
Endpoint: "/hex/",
Instructions: template.HTML(`Configure Hex to use the proxy:
# In ~/.hex/hex.config
{default_url, <<"` + baseURL + `/hex">>}.
# Or via environment variable
export HEX_MIRROR=` + baseURL + `/hex`),
},
{
ID: "pub",
Name: "pub.dev",
Language: "Dart/Flutter",
Endpoint: "/pub/",
Instructions: template.HTML(`Set the PUB_HOSTED_URL environment variable:
export PUB_HOSTED_URL=` + baseURL + `/pub`),
},
{
ID: "pypi",
Name: "PyPI",
Language: "Python",
Endpoint: "/pypi/",
Instructions: template.HTML(`Configure pip to use the proxy:
# Via command line
pip install --index-url ` + baseURL + `/pypi/simple/ package_name
# In ~/.pip/pip.conf
[global]
index-url = ` + baseURL + `/pypi/simple/`),
},
{
ID: "maven",
Name: "Maven",
Language: "Java",
Endpoint: "/maven/",
Instructions: template.HTML(`Configure Maven to use the proxy:
<!-- In ~/.m2/settings.xml -->
<settings>
<mirrors>
<mirror>
<id>proxy</id>
<mirrorOf>central</mirrorOf>
<url>` + baseURL + `/maven/</url>
</mirror>
</mirrors>
</settings>`),
},
{
ID: "nuget",
Name: "NuGet",
Language: ".NET",
Endpoint: "/nuget/",
Instructions: template.HTML(`Configure NuGet to use the proxy:
<!-- In nuget.config -->
<configuration>
<packageSources>
<clear />
<add key="proxy" value="` + baseURL + `/nuget/v3/index.json" />
</packageSources>
</configuration>
# Or via CLI
dotnet nuget add source ` + baseURL + `/nuget/v3/index.json -n proxy`),
},
{
ID: "composer",
Name: "Composer",
Language: "PHP",
Endpoint: "/composer/",
Instructions: template.HTML(`Configure Composer to use the proxy:
// In composer.json
{
"repositories": [
{
"type": "composer",
"url": "` + baseURL + `/composer"
}
]
}
# Or globally
composer config -g repositories.proxy composer ` + baseURL + `/composer`),
},
{
ID: "conan",
Name: "Conan",
Language: "C/C++",
Endpoint: "/conan/",
Instructions: template.HTML(`Configure Conan to use the proxy:
conan remote add proxy ` + baseURL + `/conan
conan remote disable conancenter`),
},
{
ID: "conda",
Name: "Conda",
Language: "Python/R",
Endpoint: "/conda/",
Instructions: template.HTML(`Configure Conda to use the proxy:
# In ~/.condarc
channels:
- ` + baseURL + `/conda/main
- ` + baseURL + `/conda/conda-forge
default_channels:
- ` + baseURL + `/conda/main
# Or via command
conda config --add channels ` + baseURL + `/conda/main`),
},
{
ID: "cran",
Name: "CRAN",
Language: "R",
Endpoint: "/cran/",
Instructions: template.HTML(`Configure R to use the proxy:
# In R session
options(repos = c(CRAN = "` + baseURL + `/cran"))
# In ~/.Rprofile for persistence
local({
r <- getOption("repos")
r["CRAN"] <- "` + baseURL + `/cran"
options(repos = r)
})`),
},
{
ID: "oci",
Name: "Container Registry",
Language: "Docker/OCI",
Endpoint: "/v2/",
Instructions: template.HTML(`Configure Docker to use the proxy as a mirror:
# In /etc/docker/daemon.json
{
"registry-mirrors": ["` + baseURL + `"]
}
# Then restart Docker
sudo systemctl restart docker
# Or pull directly
docker pull ` + baseURL[8:] + `/library/nginx:latest`),
},
{
ID: "deb",
Name: "Debian/APT",
Language: "Debian/Ubuntu",
Endpoint: "/debian/",
Instructions: template.HTML(`Configure APT to use the proxy:
# In /etc/apt/sources.list or /etc/apt/sources.list.d/proxy.list
deb ` + baseURL + `/debian stable main contrib
# Replace your existing sources.list entries with the proxy URL
# Then run:
sudo apt update`),
},
{
ID: "rpm",
Name: "RPM/Yum",
Language: "Fedora/RHEL",
Endpoint: "/rpm/",
Instructions: template.HTML(`Configure yum/dnf to use the proxy:
# In /etc/yum.repos.d/proxy.repo
[proxy-fedora]
name=Fedora via Proxy
baseurl=` + baseURL + `/rpm/releases/$releasever/Everything/$basearch/os/
enabled=1
gpgcheck=0
# Then run:
sudo dnf clean all
sudo dnf update`),
},
}
}