
Un proxy di caching leggero per i registry di pacchetti.
Un proxy con cache per i registri di pacchetti. Velocizza il download dei pacchetti memorizzando localmente gli artefatti nella cache, riducendo l'utilizzo di banda e migliorando l'affidabilità.
La maggior parte degli attacchi alla supply chain si basa sulla velocità: una versione malevola viene pubblicata e consumata dalle pipeline automatizzate nel giro di minuti, prima che qualcuno se ne accorga. La funzionalità di cooldown aggiunge un periodo di quarantena alle versioni appena pubblicate. Quando è abilitata, il proxy rimuove le versioni dalle risposte dei metadati finché non hanno superato una soglia configurabile.```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
Un cooldown di 3 giorni significa che quando `lodash` pubblica la versione `4.18.0`, le tue build continuano a usare `4.17.21` finché non sono trascorsi 3 giorni. Se la nuova release si rivela compromessa, non sei mai stato esposto.
Ordine di risoluzione: override del pacchetto, poi override dell'ecosistema, poi default globale. Questo ti permette di impostare un default conservativo e ritagliare eccezioni per i pacchetti in cui hai bisogno di aggiornamenti più rapidi. Vedi [docs/configuration.md](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md) per il riferimento completo alla configurazione.
## Scansione degli artefatti
Il cooldown guarda solo il timestamp di pubblicazione di una versione — non ispeziona mai i byte effettivi. La scansione degli artefatti colma questa lacuna: quando è abilitata, ogni artefatto viene messo in staging nello storage e scansionato da uno o più servizi esterni (trivy, ClamAV, Wiz, o qualsiasi altra cosa che parli un piccolo contratto HTTP/JSON) prima di essere committato nella cache e servito ai client.```yaml
scanning:
enabled: true
signing_key: ${PROXY_SCANNING_SIGNING_KEY}
scanners:
- name: clamav
url: http://clamav-adapter:8080/scan
mode: block # a block verdict deletes the artifact and returns 403
- name: trivy
url: http://trivy-adapter:8081/scan
mode: monitor # findings are logged, never gate caching
ecosystems: [npm, pypi]
Il proxy non carica mai i byte degli artefatti su uno scanner. Ogni scanner viene notificato con i metadati del pacchetto più un URL firmato a breve scadenza; lo scanner scarica i byte direttamente dallo storage del proxy. Gli scanner vengono eseguiti in modo concorrente e il primo scanner in modalità block che segnala un verdetto di non consentito vince immediatamente, annullando gli altri. Consulta docs/configuration.md per il riferimento completo della configurazione e il contratto HTTP dello scanner.
| Registry | Linguaggio/Piattaforma | Cooldown | Completato |
|---|---|---|---|
| npm | JavaScript | Sì | ✓ |
| Cargo | Rust | Sì | ✓ |
| RubyGems | Ruby | Sì | ✓ |
| Go proxy | Go | ✓ | |
| Hex | Elixir | Sì* | ✓ |
| pub.dev | Dart | Sì | ✓ |
| PyPI | Python | Sì | ✓ |
| Maven | Java | ✓ | |
| Gradle Build Cache | Java/Kotlin | ✓ | |
| NuGet | .NET | Sì | ✓ |
| Composer | PHP | Sì | ✓ |
| Conan | C/C++ | ✓ | |
| Conda | Python/R | Sì | ✓ |
| CRAN | R | ✓ | |
| Julia | Julia | ✓ | |
| Swift | Swift | ✓ | |
| Container | Docker/OCI | ✓ | |
| Homebrew | macOS/Linux | ✓ | |
| Debian | Debian/Ubuntu | ✓ | |
| RPM | RHEL/Fedora | ✓ | |
| Alpine | Alpine Linux | ✓ | |
| Arch | Arch Linux | ✗ |
Il cooldown richiede timestamp di pubblicazione nei metadati. I registry senza un "Sì" nella colonna cooldown o non espongono i timestamp oppure non sono ancora stati configurati.
* Il cooldown di Hex richiede la disabilitazione della verifica della firma del registry (HEX_NO_VERIFY_REPO_ORIGIN=1) poiché il proxy ricodifica il payload protobuf.
brew install git-pkgs/git-pkgs/proxy
Oppure scarica un binario dalla [pagina delle release](https://github.com/git-pkgs/proxy/releases).
### Helm
Installa il chart da GHCR, impostando l'URL pubblico che i client dei gestori di pacchetti
utilizzeranno per raggiungere il proxy:```bash
helm install proxy oci://ghcr.io/git-pkgs/charts/proxy \
--set config.data.base_url=https://proxy.example.com
Il chart predefinito distribuisce una replica supportata da un volume persistente da 10 GiB,
utilizzando SQLite e archiviazione di artefatti su filesystem sotto /data. Consultare
deploy/charts/proxy/values.yaml per le opzioni di configurazione di ingress,
database esterno e object storage.
go build -o proxy ./cmd/proxy
./proxy
./proxy -listen :3000 -base-url https://proxy.example.com
Il proxy è ora in esecuzione. Configura i tuoi gestori di pacchetti per utilizzarlo.
## OpenAPI (Swagger)
Questo repository utilizza swaggo per generare una specifica OpenAPI dagli handler annotati.
Genera la specifica:```bash
go install github.com/swaggo/swag/cmd/swag@latest
go generate ./internal/server
I file generati vengono scritti in docs/swagger/.
Quando il proxy è in esecuzione, recupera la specifica live da:
http://localhost:8080/openapi.jsonOppure sostituisci http://localhost:8080 con l'URL di base configurato. Questo link è mostrato anche nella dashboard.
Crea o modifica ~/.npmrc:```
registry=http://localhost:8080/npm/
Oppure imposta per progetto in `.npmrc`:```
registry=http://localhost:8080/npm/
Oppure utilizza la variabile d'ambiente:```bash npm_config_registry=http://localhost:8080/npm/ npm install
### Cargo
Crea o modifica `~/.cargo/config.toml`:```toml
[source.crates-io]
replace-with = "proxy"
[source.proxy]
registry = "sparse+http://localhost:8080/cargo/"
Oppure impostalo per progetto in .cargo/config.toml nella radice del tuo progetto.
Imposta la sorgente della gem nel tuo Gemfile:```ruby
source "http://localhost:8080/gem"
Oppure configurare globalmente:```bash
gem sources --add http://localhost:8080/gem/
bundle config mirror.https://rubygems.org http://localhost:8080/gem
Imposta la variabile d'ambiente GOPROXY:```bash export GOPROXY=http://localhost:8080/go,direct
Oppure nel tuo profilo shell per la persistenza.
### Homebrew
Punta l'API JSON e il dominio degli artefatti di Homebrew al proxy:```bash
export HOMEBREW_API_DOMAIN=http://localhost:8080/homebrew
export HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080
Il dominio degli artefatti fa da proxy ai manifest e ai blob delle bottle sotto /v2/homebrew/core/. L'instradamento GHCR è limitato a quel repository. Gli archivi sorgente, i download delle applicazioni cask, gli artefatti dei tap personalizzati e i mirror legacy delle bottle in formato flat-file utilizzano gli URL di fallback normali di Homebrew. Mantieni il fallback abilitato lasciando HOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK non impostato.
Abilita cache_metadata o imposta PROXY_CACHE_METADATA=true per conservare le risposte dell'API JSON di Homebrew per il fallback offline. I blob delle bottle e i relativi manifest OCI vengono memorizzati nella cache senza questa impostazione.
Gli upstream predefiniti sono https://formulae.brew.sh/api per l'API JSON e https://ghcr.io per gli artefatti. Per concatenare questo proxy a un altro proxy, configura i suoi endpoint Homebrew come upstream:```yaml
upstream:
homebrew_api: "https://upstream-proxy.example.com/homebrew"
homebrew_artifact: "https://upstream-proxy.example.com"
Le variabili d'ambiente equivalenti sono `PROXY_UPSTREAM_HOMEBREW_API` e `PROXY_UPSTREAM_HOMEBREW_ARTIFACT`.
### Hex (Elixir)
Configurare in `~/.hex/hex.config`:```erlang
{default_url, <<"http://localhost:8080/hex">>}.
Oppure imposta la variabile d'ambiente:```bash export HEX_MIRROR=http://localhost:8080/hex
### pub.dev (Dart/Flutter)
Imposta la variabile d'ambiente PUB_HOSTED_URL:```bash
export PUB_HOSTED_URL=http://localhost:8080/pub
Configura pip per utilizzare il proxy:```bash pip install --index-url http://localhost:8080/pypi/simple/ package_name
Oppure imposta in `~/.pip/pip.conf`:```ini
[global]
index-url = http://localhost:8080/pypi/simple/
Aggiungi al tuo ~/.m2/settings.xml:```xml
proxy
central
http://localhost:8080/maven/
L'endpoint `/maven/` utilizza Maven Central come upstream primario e ricorre al Gradle Plugin Portal per i metadati dei marker dei plugin Gradle e gli artefatti correlati quando l'upstream primario restituisce not found.
Per la risoluzione dei plugin Gradle tramite lo stesso endpoint proxy:```kotlin
pluginManagement {
repositories {
maven(url = "http://localhost:8080/maven/")
}
}
Configura in settings.gradle(.kts):```kotlin
buildCache {
local {
enabled = false
}
remote {
url = uri("http://localhost:8080/gradle/")
push = true
}
}
### NuGet
Configura in `nuget.config`:```xml
<configuration>
<packageSources>
<clear />
<add key="proxy" value="http://localhost:8080/nuget/v3/index.json" />
</packageSources>
</configuration>
Oppure usa la CLI:```bash dotnet nuget add source http://localhost:8080/nuget/v3/index.json -n proxy
### Composer (PHP)
Configura in `composer.json`:```json
{
"repositories": [
{
"type": "composer",
"url": "http://localhost:8080/composer"
}
]
}
Oppure imposta globalmente:```bash composer config -g repositories.proxy composer http://localhost:8080/composer
### Conan (C/C++)
Aggiungi il proxy come remote:```bash
conan remote add proxy http://localhost:8080/conan
conan remote disable conancenter
Configurare in ~/.conan2/remotes.json.
Configurare in ~/.condarc:```yaml
channels:
Oppure imposta tramite comando:```bash
conda config --add channels http://localhost:8080/conda/main
Imposta il repository in R:```r options(repos = c(CRAN = "http://localhost:8080/cran"))
Oppure in `~/.Rprofile` per la persistenza:```r
local({
r <- getOption("repos")
r["CRAN"] <- "http://localhost:8080/cran"
options(repos = r)
})
Imposta il server Pkg prima di avviare Julia:```bash export JULIA_PKG_SERVER=http://localhost:8080/julia
Oppure all'interno di una sessione in esecuzione:```julia
ENV["JULIA_PKG_SERVER"] = "http://localhost:8080/julia"
using Pkg; Pkg.update()
Configura il proxy come registry predefinito per il pacchetto Swift corrente:```bash swift package-registry set --allow-insecure-http http://localhost:8080/swift
Le dipendenze del registro utilizzano il loro identificatore di pacchetto con scope in `Package.swift`:```swift
dependencies: [
.package(id: "apple.swift-argument-parser", from: "1.2.0")
]
Il proxy supporta la risoluzione delle dipendenze e il download dei sorgenti. La pubblicazione con
swift package-registry publish non è supportata.
Configura Docker per utilizzare il proxy come mirror del registry in /etc/docker/daemon.json:```json
{
"registry-mirrors": ["http://localhost:8080"]
}
Poi riavvia Docker:```bash
sudo systemctl restart docker
Oppure scarica direttamente le immagini:```bash docker pull localhost:8080/library/nginx:latest
### Helm
Configura ogni repository di chart HTTP con un nome, poi aggiungi l'URL del proxy corrispondente a Helm:```yaml
upstream:
helm:
bitnami: "https://charts.bitnami.com/bitnami"
| -s | --server | SERVER | http://localhost:8080 | URL del server |
| -t | --token | TOKEN | | Token di autenticazione |
| -o | --output | FILE | stdout | File di output |
| -f | --format | FORMAT | json | Formato di output |
| -v | --verbose | | | Output dettagliato |
| -q | --quiet | | | Modalità silenziosa |
| -h | --help | | | Mostra il messaggio di aiuto |
| -V | --version | | | Mostra la versione |
# Scansione di base
tool scan example.com
# Scansione con opzioni
tool scan example.com --port 80,443 --threads 10
# Output in formato JSON
tool scan example.com --format json --output results.json
# Utilizzo di un file di configurazione
tool scan --config config.yaml
Il file di configurazione utilizza il formato YAML:
server:
host: localhost
port: 8080
timeout: 30
scan:
threads: 10
timeout: 5
retries: 3
output:
format: json
verbose: false
Tutte le richieste API richiedono un token di autenticazione:
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:8080/api/v1/scan
| Metodo | Endpoint | Descrizione |
|---|---|---|
| GET | /api/v1/status | Stato del server |
| POST | /api/v1/scan | Avvia una nuova scansione |
| GET | /api/v1/scan/{id} | Ottieni i risultati della scansione |
| DELETE | /api/v1/scan/{id} | Elimina una scansione |
| GET | /api/v1/scans | Elenca tutte le scansioni |
curl -X POST http://localhost:8080/api/v1/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"target": "example.com",
"ports": [80, 443],
"options": {
"threads": 10,
"timeout": 5
}
}'
{
"id": "scan-12345",
"status": "completed",
"target": "example.com",
"started_at": "2024-01-01T00:00:00Z",
"completed_at": "2024-01-01T00:01:00Z",
"results": [
{
"port": 80,
"state": "open",
"service": "http"
},
{
"port": 443,
"state": "open",
"service": "https"
}
]
}
# Clona il repository
git clone https://github.com/example/tool.git
cd tool
# Crea un ambiente virtuale
python -m venv venv
source venv/bin/activate # Su Windows: venv\Scripts\activate
# Installa le dipendenze
pip install -r requirements.txt
# Installa le dipendenze di sviluppo
pip install -r requirements-dev.txt
# Esegui tutti i test
pytest
# Esegui con copertura
pytest --cov=tool --cov-report=html
# Esegui test specifici
pytest tests/test_scanner.py -v
# Formattazione del codice
black tool/
# Linting
flake8 tool/
# Controllo dei tipi
mypy tool/
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)Questo progetto è distribuito sotto la licenza MIT - vedi il file LICENSE per i dettagli.
Il proxy memorizza nella cache `index.yaml` utilizzando le normali impostazioni della cache dei metadati e
memorizza nella cache gli archivi dei chart dopo averne verificato il digest SHA-256 dall'indice.
Per i chart memorizzati in un registry OCI, configurare un upstream OCI denominato e aggiungere
il prefisso riservato `upstream/{name}` al riferimento del chart:```yaml
upstream:
oci:
ghcr: "https://ghcr.io"
I apologize, but I don't see any content to translate in your message. The "INPUT:" section appears to be empty — no Markdown text was included after it.
Please paste the actual chunk 85 content you'd like translated from English to Italian, and I'll return only the translated Markdown, preserving all structure, code, paths, URLs, and identifiers exactly as required.```bash helm pull oci://localhost:8080/upstream/ghcr/owner/charts/mychart --version 1.0.0 --plain-http
### Debian / APT
Configura APT per utilizzare il proxy in `/etc/apt/sources.list.d/proxy.list`:```
deb http://localhost:8080/debian stable main contrib
Sostituisci le voci esistenti in sources.list, quindi:```bash sudo apt update
L'upstream predefinito è `http://deb.debian.org/debian`. Per fare da proxy a un repository APT diverso (ad es. Ubuntu), impostare `upstream.debian` nel file di configurazione o `PROXY_UPSTREAM_DEBIAN` nell'ambiente:```yaml
upstream:
debian: "http://archive.ubuntu.com/ubuntu"
Configura yum/dnf per utilizzare il proxy in /etc/yum.repos.d/proxy.repo:```ini
[proxy-fedora]
name=Fedora via Proxy
baseurl=http://localhost:8080/rpm/releases/$releasever/Everything/$basearch/os/
enabled=1
gpgcheck=0
Poi:```bash
sudo dnf clean all
sudo dnf update
Punta /etc/apk/repositories al proxy. Il nome del repository predefinito
alpine fa da proxy al mirror ufficiale (https://dl-cdn.alpinelinux.org/alpine):```
http://localhost:8080/apk/alpine/v3.22/main
http://localhost:8080/apk/alpine/v3.22/community
Poi:```bash
apk update
Gli indici del repository (v2 APKINDEX.tar.gz e v3 Packages.adb), le firme
separate e i pacchetti vengono serviti byte per byte senza modifiche, quindi la normale
verifica delle firme di apk continua a funzionare. Gli indici utilizzano la cache dei metadati
(metadata_ttl, fallback su dati obsoleti); i pacchetti .apk sono memorizzati nella cache
degli artefatti condivisa e rimangono disponibili quando l'upstream non è raggiungibile.
Per fare da proxy ad altri mirror o repository privati, configura upstream denominati
sotto upstream.apk (questo sostituisce il default integrato; aggiungi di nuovo alpine se
lo vuoi ancora):```yaml
upstream:
apk:
alpine: "https://dl-cdn.alpinelinux.org/alpine"
private: "https://apk.example.com"
I cannot translate this content because no text was provided. The INPUT section is empty.
Please send the actual Markdown content for chunk 103, and I will translate it from English to Italian following all the rules you specified.```
http://localhost:8080/apk/private
apk aggiunge l'architettura e il nome del file di indice a ciascuna riga del repository stesso.
Configura upstream generici con nome:```yaml upstream: generic: github: "https://github.com" github-api: "https://api.github.com"
Poi riscrivi gli URL di GitHub nelle impostazioni di mise (`~/.config/mise/config.toml`, mise ≥ 2025.9.3):```toml
[settings.url_replacements]
"regex:^https://github\\.com/([^/]+)/([^/]+)/releases/download/(.+)" = "http://localhost:8080/generic/github/$1/$2/releases/download/$3"
"regex:^https://api\\.github\\.com/(.*)" = "http://localhost:8080/generic/github-api/$1"
Gli asset di rilascio vengono memorizzati nella cache in modo permanente dopo il primo download e continuano a essere installati anche quando GitHub è inattivo. Le ricerche di tag tramite api.github.com vengono memorizzate nella cache per metadata_ttl e servite obsolete durante un'interruzione o un limite di frequenza. Esegui il commit di un mise.lock e installa con mise install --locked in modo che le installazioni bloccate non richiedano alcuna chiamata API. Aggiungi un bearer token per https://api.github.com sotto upstream.auth se la flotta supera il limite di frequenza anonimo di GitHub.
Il proxy può essere configurato tramite:
-config string Path to configuration file -listen string Address to listen on (default ":8080") -base-url string Public URL of this proxy (default "http://localhost:8080") -storage-url string Storage URL (file://, s3://, gs://, azblob://) -storage-path string Path to artifact storage directory (deprecated, use -storage-url) -database-driver string Database driver: sqlite or postgres (default "sqlite") -database-path string Path to SQLite database file (default "./cache/proxy.db") -database-url string PostgreSQL connection URL -log-level string Log level: debug, info, warn, error (default "info") -log-format string Log format: text, json (default "text") -access-log string Path to the JSONL access log -version Print version and exit
### Variabili d'ambiente```bash
PROXY_LISTEN=:8080
PROXY_BASE_URL=http://localhost:8080
PROXY_UI_URL=http://localhost:8080 # Optional; defaults to PROXY_BASE_URL
PROXY_STORAGE_URL=file:///var/cache/proxy/artifacts
PROXY_DATABASE_DRIVER=sqlite
PROXY_DATABASE_PATH=./cache/proxy.db
PROXY_DATABASE_URL=postgres://user:pass@localhost/proxy?sslmode=disable
PROXY_LOG_LEVEL=info
PROXY_LOG_FORMAT=text
PROXY_ACCESS_LOG_PATH=/var/log/proxy/access.jsonl
PROXY_UPSTREAM_SWIFT=https://tuist.dev/api/registry/swift
listen: ":8080" base_url: "http://localhost:8080"
storage: url: "file:///var/cache/proxy/artifacts" max_size: "10GB" # Optional: evict LRU when exceeded
database: driver: "sqlite" path: "/var/lib/proxy/cache.db"
log: level: "info" format: "text"
access_log: path: "/var/log/proxy/access.jsonl" # Optional JSONL activity log
upstream: npm: "https://registry.npmjs.org" cargo: "https://index.crates.io" swift: "https://tuist.dev/api/registry/swift"
cooldown: default: "3d"
Consulta il [riferimento alla configurazione](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md#upstream-registries) per ogni chiave upstream, variabile d'ambiente e URL predefinito.
Esegui con file di configurazione:```bash
./proxy -config /etc/proxy/config.yaml
SQLite è l'impostazione predefinita e funziona bene per distribuzioni su nodo singolo. Per configurazioni multi-nodo o se preferisci un database gestito, passa a Postgres:```yaml database: driver: "postgres" url: "postgres://user:password@localhost:5432/proxy?sslmode=disable"
Oppure tramite variabili d'ambiente:```bash
PROXY_DATABASE_DRIVER=postgres
PROXY_DATABASE_URL=postgres://user:password@localhost:5432/proxy?sslmode=disable
Il proxy crea le tabelle automaticamente alla prima esecuzione.
Il proxy può memorizzare gli artefatti in cache in S3 o in qualsiasi servizio compatibile con S3 (MinIO, R2, ecc.) invece che nel filesystem locale.```yaml storage: url: "s3://my-bucket-name?region=us-east-1"
Per servizi compatibili con S3 come MinIO:```yaml
storage:
url: "s3://my-bucket?endpoint=http://localhost:9000&disableSSL=true&s3ForcePathStyle=true"
Imposta le credenziali tramite le variabili d'ambiente standard di AWS (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION).
Il proxy può memorizzare gli artefatti in cache in un bucket GCS utilizzando lo schema URL gs://.```yaml
storage:
url: "gs://my-bucket-name"
L'autenticazione utilizza [Application Default Credentials](https://docs.cloud.google.com/docs/authentication/application-default-credentials), il che significa che non è necessario incorporare credenziali nella configurazione o nell'ambiente. Fonti supportate, in ordine:
- **GKE Workload Identity** — associa il service account Kubernetes che esegue il proxy a un service account Google che dispone di `roles/storage.objectAdmin` sul bucket. Il proxy utilizzerà automaticamente il token del workload.
- **Service account collegato** su GCE, Cloud Run, Cloud Functions, ecc.
- **Variabile d'ambiente `GOOGLE_APPLICATION_CREDENTIALS`** che punta a un file di chiave JSON di un service account.
- **`gcloud auth application-default login`** per lo sviluppo locale.
#### Configurazione di GKE Workload Identity```bash
# 1. Create a Google service account
gcloud iam service-accounts create git-pkgs-proxy \
--project=PROJECT_ID
# 2. Grant it access to the bucket
gsutil iam ch \
serviceAccount:git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com:objectAdmin \
gs://my-bucket-name
# 3. Bind the Kubernetes service account to it
gcloud iam service-accounts add-iam-policy-binding \
git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"
# 4. Annotate the Kubernetes service account
kubectl annotate serviceaccount KSA_NAME \
--namespace=NAMESPACE \
iam.gke.io/gcp-service-account=git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com
Quando direct_serve: true è abilitato, il proxy emette reindirizzamenti HTTP 302 verso URL GCS presigned. Workload Identity non fornisce alcuna chiave privata, quindi il backend GCS chiama l'API IAM Credentials signBlob. Concedi al service account il ruolo token-creator su se stesso:```bash
gcloud iam service-accounts add-iam-policy-binding
git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com
--role=roles/iam.serviceAccountTokenCreator
--member="serviceAccount:git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com"
## Comandi CLI
### serve (predefinito)
Avvia il server proxy. Questo è il comando predefinito se non ne viene specificato nessuno.```bash
proxy serve [flags]
proxy [flags] # same as 'proxy serve'
Pre-popola la cache da PURL, file SBOM o interi registri. Utile per garantire la disponibilità offline o riscaldare la cache prima dei deployment.```bash
proxy mirror pkg:npm/[email protected] pkg:cargo/[email protected]
proxy mirror pkg:npm/lodash
proxy mirror --sbom sbom.cdx.json
proxy mirror --dry-run pkg:npm/lodash
proxy mirror --concurrency 8 pkg:npm/[email protected]
Il comando mirror accetta gli stessi flag di storage e database di `serve`. Gli artefatti già in cache vengono saltati.
È disponibile anche un'API mirror quando il server è in esecuzione:```bash
# Start a mirror job
curl -X POST http://localhost:8080/api/mirror \
-H "Content-Type: application/json" \
-d '{"purls": ["pkg:npm/[email protected]"]}'
# Start a mirror job from an inline CycloneDX or SPDX JSON SBOM
curl -X POST http://localhost:8080/api/mirror \
-H "Content-Type: application/json" \
-d '{"sbom":{"bomFormat":"CycloneDX","components":[{"purl":"pkg:npm/[email protected]"}]}}'
# Check job status
curl http://localhost:8080/api/mirror/mirror-1
# Cancel a running job
curl -X DELETE http://localhost:8080/api/mirror/mirror-1
Mostra le statistiche della cache senza avviare il server.```bash
proxy stats
proxy stats -json
proxy stats -database-path /var/lib/proxy/cache.db
proxy stats -database-driver postgres -database-url postgres://user:pass@localhost/proxy
proxy stats -popular 20
Output di esempio:```
Cache Statistics
================
Packages: 45
Versions: 128
Artifacts: 128
Total size: 892.4 MB
Total hits: 1547
Packages by ecosystem:
npm 32
cargo 13
Most popular packages:
1. npm/lodash (342 hits, 24.7 KB)
2. npm/react (198 hits, 89.3 KB)
3. cargo/serde (156 hits, 234.1 KB)
Recently cached:
npm/[email protected] (2024-01-15 14:32, 54.2 KB)
cargo/[email protected] (2024-01-15 14:28, 412.8 KB)
| Endpoint | Descrizione |
|---|---|
GET / | Dashboard (interfaccia web) |
GET /health | Controllo dello stato e stato del circuit breaker upstream (JSON; HTTP 200 healthy, 503 unhealthy) |
GET /stats | Statistiche della cache (JSON) |
GET /metrics | Metriche Prometheus |
GET /npm/* | Protocollo del registry npm |
GET /cargo/* | Protocollo dell'indice sparse di Cargo |
GET /gem/* | Protocollo RubyGems |
GET /go/* | Protocollo del proxy dei moduli Go |
GET /hex/* | Protocollo Hex.pm |
GET /pub/* | Protocollo pub.dev |
GET /pypi/* | API simple/JSON di PyPI |
GET /maven/* | Protocollo del repository Maven |
GET /nuget/* | API NuGet V3 |
GET /composer/* | Protocollo Composer/Packagist |
GET /conan/* | Protocollo Conan C/C++ |
GET /conda/* | Protocollo Conda/Anaconda |
GET /cran/* | Protocollo CRAN (R) |
GET /julia/* | Protocollo del server Julia Pkg |
GET /swift/* | Protocollo Swift Package Registry v1 |
GET /helm/{repository}/* | Protocollo del repository di chart Helm HTTP |
GET /homebrew/* | API JSON di Homebrew |
GET /v2/* | Protocollo del registry OCI/Docker |
GET /v2/homebrew/core/* | Manifest e blob delle bottle core di Homebrew da GHCR |
GET /apk/{repository}/* |
| Endpoint | Descrizione |
|---|---|
POST /api/mirror | Avvia un job di mirroring (corpo JSON con purls o un sbom inline) |
GET /api/mirror/{id} | Ottieni lo stato e il progresso del job |
DELETE /api/mirror/{id} | Annulla un job in esecuzione |
Il proxy fornisce endpoint REST per l'arricchimento dei metadati dei pacchetti, la scansione delle vulnerabilità e il rilevamento delle versioni obsolete.
| Endpoint | Descrizione |
|---|---|
GET /api/package/{ecosystem}/{name} | Ottieni i metadati del pacchetto |
GET /api/package/{ecosystem}/{name}/{version} | Ottieni i metadati della versione con le vulnerabilità |
GET /api/vulns/{ecosystem}/{name} | Ottieni tutte le vulnerabilità per un pacchetto |
GET /api/vulns/{ecosystem}/{name}/{version} | Ottieni le vulnerabilità per una versione specifica |
POST /api/outdated | Verifica più pacchetti per versioni obsolete |
POST /api/bulk | Ricerca in blocco dei metadati dei pacchetti |
I need the actual content of chunk 143 to translate it. You've provided the instructions and metadata, but the INPUT section is empty — there's no Markdown text to translate.
Please paste the source text for chunk 143/189 and I'll return the Italian translation following all the rules above.```json
{
"ecosystem": "npm",
"name": "lodash",
"latest_version": "4.17.21",
"license": "MIT",
"license_category": "permissive",
"description": "Lodash modular utilities",
"homepage": "https://lodash.com/",
"repository": "https://github.com/lodash/lodash",
"registry_url": "https://registry.npmjs.org"
}
I need the actual content of chunk 147 to translate it. You've provided the instructions and metadata, but the INPUT section is empty — there's no Markdown text to translate.
Please paste the source content for chunk 147 and I'll return the Italian translation following all the rules above.```json
{
"package": {
"ecosystem": "npm",
"name": "lodash",
"latest_version": "4.17.21",
"license": "MIT",
"license_category": "permissive"
},
"version": {
"ecosystem": "npm",
"name": "lodash",
"version": "4.17.0",
"license": "MIT",
"published_at": "2016-06-17T03:59:56Z",
"yanked": false,
"is_outdated": true
},
"vulnerabilities": [
{
"id": "GHSA-p6mc-m468-83gw",
"summary": "Prototype Pollution in lodash",
"severity": "HIGH",
"cvss_score": 7.4,
"fixed_version": "4.17.12"
}
],
"is_outdated": true,
"license_category": "permissive"
}
curl -X POST http://localhost:8080/api/outdated
-H "Content-Type: application/json"
-d '{
"packages": [
{"ecosystem": "npm", "name": "lodash", "version": "4.17.0"},
{"ecosystem": "pypi", "name": "requests", "version": "2.25.0"}
]
}'
I need the actual content of chunk 151 to translate it. The message you sent contains only the instructions and the label "INPUT:" followed by "Response:" — but no source text between them.
Please paste the Markdown content of chunk 151 (the English text to be translated into Italian), and I will return only the translated Markdown, preserving all structure, code, paths, URLs, and identifiers exactly as required.```json
{
"results": [
{
"ecosystem": "npm",
"name": "lodash",
"version": "4.17.0",
"latest_version": "4.17.21",
"is_outdated": true
},
{
"ecosystem": "pypi",
"name": "requests",
"version": "2.25.0",
"latest_version": "2.31.0",
"is_outdated": true
}
]
}
curl -X POST http://localhost:8080/api/bulk
-H "Content-Type: application/json"
-d '{
"purls": [
"pkg:npm/[email protected]",
"pkg:pypi/[email protected]"
]
}'
Response:```json
{
"packages": {
"pkg:npm/lodash": {
"ecosystem": "npm",
"name": "lodash",
"latest_version": "4.17.21",
"license": "MIT",
"license_category": "permissive"
},
"pkg:pypi/requests": {
"ecosystem": "pypi",
"name": "requests",
"latest_version": "2.31.0",
"license": "Apache-2.0",
"license_category": "permissive"
}
}
}
{ "cached_artifacts": 142, "total_size_bytes": 523456789, "total_size": "499.2 MB", "storage_url": "file:///path/to/cache/artifacts", "database_path": "./cache/proxy.db" }
## Come Funziona
1. Il gestore di pacchetti richiede i metadati del pacchetto al proxy
2. Il proxy recupera i metadati dall'upstream, riscrive gli URL degli artefatti per puntare al proxy
3. Il gestore di pacchetti richiede l'artefatto (tarball, crate, ecc.)
4. Il proxy controlla la cache locale:
- **Cache hit**: Serve dallo storage locale
- **Cache miss**: Recupera dall'upstream, memorizza localmente, serve al client
5. Le richieste successive per lo stesso artefatto vengono servite dalla cache```
┌─────────────┐ ┌─────────┐ ┌──────────┐
│ npm/cargo │────▶│ proxy │────▶│ upstream │
│ client │◀────│ │◀────│ registry │
└─────────────┘ └─────────┘ └──────────┘
│
▼
┌─────────┐
│ cache │
│ storage │
└─────────┘
Il proxy serve un'interfaccia web sotto /ui. Non è necessaria una build separata del frontend -- i template e gli asset sono incorporati nel binario. GET / reindirizza a /ui/. L'interfaccia è montata sotto il proprio prefisso, così un reverse proxy può applicare regole di accesso diverse rispetto agli endpoint dei pacchetti (ad esempio, richiedendo l'autenticazione per PathPrefix(/ui) lasciando /npm, /pypi ecc. aperti alle macchine di build).
/ui/) -- statistiche della cache, pacchetti popolari, artefatti recentemente messi in cache e panoramica delle vulnerabilità./ui/install) -- istruzioni di configurazione per ecosistema, così non devi cercarle qui./ui/packages) -- sfoglia tutti i pacchetti in cache con filtri per ecosistema e ordinamento per hit, dimensione, nome o numero di vulnerabilità./ui/search?q=...) -- cerca i pacchetti in cache per nome./ui/package/{ecosystem}/{name}) -- metadati, licenza, vulnerabilità ed elenco delle versioni di un pacchetto. Puoi selezionare due versioni da confrontare./ui/package/{ecosystem}/{name}/{version}) -- metadati per versione, hash di integrità, stato della cache dell'artefatto e conteggi degli hit./ui/package/{ecosystem}/{name}/{version}/browse) -- sfoglia i file all'interno degli archivi in cache con evidenziazione della sintassi per i file di testo e anteprime delle immagini./ui/package/{ecosystem}/{name}/compare/{v1}...{v2}) -- diff affiancato di due versioni in cache che mostra i file aggiunti, rimossi e modificati.Il proxy espone le metriche Prometheus su GET /metrics. Tutti i nomi delle metriche hanno il prefisso proxy_.
| Metrica | Tipo | Etichette | Descrizione |
|---|---|---|---|
proxy_requests_total | counter | ecosystem, status | Risposte del proxy per ecosistema di pacchetti e stato HTTP |
proxy_request_duration_seconds | histogram | ecosystem, status | Durata delle richieste al proxy |
proxy_cache_hits_total | counter | ecosystem | Hit della cache |
proxy_cache_misses_total | counter | ecosystem | Miss della cache |
proxy_cache_size_bytes | gauge | Dimensione totale degli artefatti in cache | |
proxy_cached_artifacts_total | gauge | Numero di artefatti in cache | |
proxy_upstream_fetch_duration_seconds | histogram | ecosystem | Tempo impiegato per il fetch dall'upstream |
proxy_upstream_errors_total | counter | ecosystem, error_type | Errori di fetch dall'upstream |
proxy_storage_operation_duration_seconds | histogram | operation | Latenza di lettura/scrittura dello storage |
proxy_storage_errors_total | counter | operation | Errori di lettura/scrittura dello storage |
proxy_active_requests | gauge | Richieste in corso | |
proxy_health_probe_failures_total | counter | step | Errori della sonda di salute dello storage per step fallito (write, size, read, verify, delete). |
proxy_circuit_breaker_state |
La dimensione della cache e il conteggio degli artefatti vengono aggiornati ogni 60 secondi. Lo stato del circuit breaker viene letto dal fetcher a ogni scrape di /metrics e a ogni richiesta a /health, quindi proxy_circuit_breaker_trips_total conta gli scatti visibili tra queste letture — un breaker che si apre e si ripristina interamente tra due scrape non viene contato. Le metriche rimanenti si aggiornano a ogni richiesta.
Le metriche del breaker portano una serie per host upstream, ma solo per gli host il cui breaker è scattato almeno una volta dall'avvio. Un breaker viene creato per ogni host da cui il proxy recupera artefatti, e per alcuni ecosistemi quell'host proviene dai metadati upstream anziché dalla configurazione (composer lo prende dal dist.url di un pacchetto, helm dagli URL dei chart in index.yaml), quindi pubblicare ogni host permetterebbe ai contenuti upstream di far crescere il numero di serie per tutta la durata del processo. Una volta che un host è scattato continua a segnalarlo, quindi un ripristino appare comunque come una transizione a 0 anziché come una serie che svanisce. /health non è una serie temporale persistente ed elenca ogni breaker, scattato o meno.
L'etichetta registry è l'host dell'URL da cui è stato recuperato l'artefatto. Poiché quell'URL può provenire dai metadati upstream, non sempre è possibile ricavarne un host — ad esempio un dist.url firmato che non viene parsato correttamente — e in tal caso il breaker viene etichettato hostless-url-<digest>, dove il digest è derivato da un valore generato al momento dell'avvio. Né /metrics né /health richiedono autenticazione, quindi un URL di fetch non viene mai pubblicato come etichetta o chiave; il digest identifica il breaker per tutta la durata del processo senza rivelare l'URL sottostante né permettere che un URL scelto venga confrontato con esso.
Configura un alert su proxy_circuit_breaker_state == 2 sostenuto per più di qualche minuto: mentre un breaker è aperto, i download degli artefatti per quell'upstream falliscono con HTTP 502 a ogni miss della cache, e solo una singola richiesta di probe per intervallo di backoff raggiunge l'upstream. Gli artefatti in cache continuano a essere serviti, così come i metadati per lo stesso ecosistema (i metadati non passano attraverso il circuit breaker), quindi le installazioni falliscono in un modo che sembra un'interruzione parziale dell'upstream.
/health restituisce un report JSON strutturato sulla salute dei sottosistemi. HTTP 200 se tutti i controlli passano; 503 se qualcuno fallisce.```json
{
"status": "ok",
"checks": {
"database": {"status": "ok"},
"storage": {"status": "ok"}
},
"circuit_breakers": {
"registry.npmjs.org": "closed",
"static.crates.io": "open"
}
}
I controlli falliti includono un campo `"error"`. I fallimenti di archiviazione includono anche un campo `"step"` che identifica quale fase della sonda è fallita (`write`, `size`, `read`, `verify`, `delete`). Quando il controllo del database fallisce, la voce di archiviazione riporta `{"status": "skipped"}` in modo che la risposta contenga sempre lo stesso insieme di chiavi.
`circuit_breakers` riporta lo stato del circuit breaker di recupero degli artefatti di ciascun upstream (`"open"` o `"closed"`), indicizzato per host upstream — oppure tramite il segnaposto `hostless-url-<digest>` descritto in [Monitoring](#monitoring) quando l'URL di recupero non ha un host da leggere. La chiave viene omessa finché il proxy non ha recuperato un artefatto da almeno un upstream, e un host compare solo dopo che è stato creato un breaker per esso. I breaker scattano dopo ripetuti fallimenti dell'upstream e ritentano l'upstream dopo un backoff esponenziale. Mentre uno è aperto, i download di artefatti per quell'host restituiscono HTTP 502 in caso di cache miss senza contattare l'upstream; gli artefatti già in cache vengono comunque serviti dall'archiviazione, poiché la cache viene controllata prima del fetcher. Un breaker viene riportato come `"open"` per tutta la durata del suo backoff, inclusa la finestra half-open in cui ammette una richiesta di sonda per testare il ripristino. Lo stato del breaker è per processo e in memoria, quindi un riavvio lo azzera, ma un riavvio non è necessario per il ripristino: il backoff continua a ritentare finché il breaker è aperto, quindi si chiude da solo una volta che l'upstream torna a servire.
Un breaker aperto **non** imposta `status` su `"error"` né modifica il codice di stato HTTP: segnala un upstream specifico che rifiuta di servire, non che questo proxy è inadatto a ricevere traffico, e far fallire la sonda di readiness a causa di un singolo upstream non sano rimuoverebbe il pod dalla rotazione anche per tutti gli altri ecosistemi. Usa `proxy_circuit_breaker_state` per generare avvisi su di esso.
I risultati della sonda di archiviazione vengono memorizzati nella cache per `health.storage_probe_interval` (predefinito 30s) per limitare il costo del probing di backend remoti. Una sonda mantiene un mutex interno per un massimo di 10 secondi (il timeout per sonda hardcoded), quindi `/health` è pensato come sonda di **readiness** di Kubernetes piuttosto che come sonda di liveness — un round-trip S3 lento dovrebbe rimuovere il pod dalla rotazione, non riavviarlo.
Configurazione di scrape per Prometheus:```yaml
scrape_configs:
- job_name: git-pkgs-proxy
static_configs:
- targets: ["localhost:8080"]
Creare /etc/systemd/system/proxy.service:```ini
[Unit]
Description=git-pkgs proxy
After=network.target
[Service] Type=simple User=proxy ExecStart=/usr/local/bin/proxy -config /etc/proxy/config.yaml Restart=always RestartSec=5
[Install] WantedBy=multi-user.target
Abilita e avvia:```bash
sudo systemctl enable proxy
sudo systemctl start proxy
Nel repository è incluso un Dockerfile. Per compilare ed eseguire:```bash docker build -t proxy . docker run -p 8080:8080 -v proxy-data:/data proxy
Con Postgres e S3:```bash
docker run -p 8080:8080 \
-e PROXY_DATABASE_DRIVER=postgres \
-e PROXY_DATABASE_URL=postgres://user:pass@db:5432/proxy \
-e PROXY_STORAGE_URL=s3://my-bucket?region=us-east-1 \
-e AWS_ACCESS_KEY_ID=... \
-e AWS_SECRET_ACCESS_KEY=... \
proxy
Quando si esegue dietro nginx, Apache o un altro reverse proxy, impostare base_url sul tuo URL pubblico:```yaml
base_url: "https://proxy.example.com"
Se la UI viene raggiunta su un hostname diverso rispetto agli endpoint dei pacchetti — ad esempio, la UI esposta pubblicamente su un dominio mentre le macchine di build raggiungono un alias di rete Docker — imposta `ui_base_url` separatamente. `base_url` è l'URL utilizzato dai package manager e dalla riscrittura dei metadati; `ui_base_url` è l'URL pubblicizzato agli utenti umani che visitano la web UI (tag canonical/`og:url` e il banner della guida all'installazione):```yaml
base_url: "http://pkg-proxy:8080" # internal alias for build machines
ui_base_url: "https://proxy.example.com/ui" # public UI URL
Quando non impostato, ui_base_url assume come valore predefinito base_url.
Attenzione: il proxy serve l'interfaccia utente e gli endpoint dei pacchetti sullo stesso listener. Impostare
ui_base_urlcambia solo l'URL che l'interfaccia utente pubblicizza agli utenti; non impedisce che gli endpoint dei pacchetti siano raggiungibili sullo stesso hostname e sulla stessa porta. Quando si espone il proxy tramite un reverse proxy pubblico, limitare la route pubblica aPathPrefix(/ui)(o all'equivalente del proprio proxy), altrimenti/npm,/pypie gli altri endpoint dei pacchetti rimangono esposti insieme all'interfaccia utente.
Esempio nginx, che limita l'host pubblico all'interfaccia utente lasciando gli endpoint dei pacchetti raggiungibili solo sul listener interno:```nginx server { listen 443 ssl; server_name proxy.example.com;
location /ui/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
}
location / {
return 404;
}
}
Esempio Traefik che utilizza `PathPrefix(/ui)` in modo che il router pubblico corrisponda solo al traffico dell'interfaccia utente:```yaml
labels:
traefik.enable: "true"
traefik.http.services.pkg-proxy.loadbalancer.server.port: "8080"
traefik.http.routers.pkg-proxy.rule: "Host(`proxy.example.com`) && PathPrefix(`/ui`)"
traefik.http.routers.pkg-proxy.entrypoints: "websecure"
Il proxy memorizza gli artefatti nella directory di archiviazione configurata con questa struttura:``` cache/artifacts/ ├── npm/ │ └── lodash/ │ └── 4.17.21/ │ └── lodash-4.17.21.tgz ├── cargo/ │ └── serde/ │ └── 1.0.193/ │ └── serde-1.0.193.crate ├── oci/ │ └── library/nginx/ │ └── sha256:abc123.../ │ └── sha256:abc123... ├── deb/ │ └── nginx/ │ └── 1.18.0-6/ │ └── nginx_1.18.0-6_amd64.deb └── rpm/ └── nginx/ └── 1.24.0-1.fc39/ └── nginx-1.24.0-1.fc39.x86_64.rpm
I metadati della cache sono memorizzati in SQLite (predefinito) o PostgreSQL. Per svuotare una cache locale:```bash
rm -rf ./cache/artifacts/*
rm ./cache/proxy.db
Il proxy ricreerà il database al prossimo avvio.
Requisiti:
go.mod)```bash
git clone https://github.com/git-pkgs/proxy.git
cd proxy
go build -o proxy ./cmd/proxyEsegui i test:```bash
go test ./...
GPL-3.0-or-later
| Chef | Chef | ✗ |
| Generic | Any | ✓ |
| Helm | Kubernetes | ✓ |
| Vagrant | Vagrant | ✗ |
| Protocollo del repository Alpine APK |
GET /generic/{name}/* | Proxy di download HTTP generico (asset delle release GitHub, mise/aqua) |
GET /debian/* | Protocollo del repository Debian/APT |
GET /rpm/* | Protocollo del repository RPM/Yum |
| gauge |
registry |
| Stato del circuit breaker per il fetch degli artefatti per registry upstream (0 closed, 2 open). Pubblicato una volta che il breaker di quel registry è scattato. |
proxy_circuit_breaker_trips_total | counter | registry | Scatti del circuit breaker per registry upstream. |