
Un proxy de cache léger pour les registres de paquets.
Un proxy de mise en cache pour les registres de paquets. Accélère les téléchargements de paquets en mettant en cache les artefacts localement, réduisant l'utilisation de la bande passante et améliorant la fiabilité.
La plupart des attaques de la chaîne d'approvisionnement reposent sur la rapidité : une version malveillante est publiée et consommée par des pipelines automatisés en quelques minutes, avant que quiconque ne s'en aperçoive. La fonctionnalité de refroidissement ajoute une période de quarantaine aux versions nouvellement publiées. Lorsqu'elle est activée, le proxy retire les versions des réponses de métadonnées jusqu'à ce qu'elles aient dépassé un seuil configurable.```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 délai de refroidissement de 3 jours signifie que lorsque `lodash` publie la version `4.18.0`, vos builds continuent d'utiliser `4.17.21` jusqu'à ce que 3 jours se soient écoulés. Si la nouvelle version s'avère compromise, vous n'avez jamais été exposé.
Ordre de résolution : override de paquet, puis override d'écosystème, puis valeur par défaut globale. Cela vous permet de définir une valeur par défaut conservatrice et de créer des exceptions pour les paquets où vous avez besoin de mises à jour plus rapides. Voir [docs/configuration.md](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md) pour la référence complète de configuration.
## Analyse des artefacts
Le refroidissement ne regarde que l'horodatage de publication d'une version — il n'inspecte jamais les octets réels. L'analyse des artefacts comble cette lacune : lorsqu'elle est activée, chaque artefact est mis en attente dans le stockage et analysé par un ou plusieurs services externes (trivy, ClamAV, Wiz, ou tout autre service respectant un petit contrat HTTP/JSON) avant d'être validé dans le cache et servi aux clients.```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]
Le proxy ne téléverse jamais les octets des artefacts vers un scanner. Chaque scanner est notifié avec les métadonnées du paquet ainsi qu'une URL signée à courte durée de vie ; le scanner récupère lui-même les octets depuis le stockage propre du proxy. Les scanners s'exécutent simultanément, et le premier scanner en mode block à signaler un verdict de non-autorisation l'emporte immédiatement, annulant les autres. Voir docs/configuration.md pour la référence complète de configuration et le contrat HTTP des scanners.
| Registre | Langage/Plateforme | Cooldown | Terminé |
|---|---|---|---|
| npm | JavaScript | Oui | ✓ |
| Cargo | Rust | Oui | ✓ |
| RubyGems | Ruby | Oui | ✓ |
| Go proxy | Go | ✓ | |
| Hex | Elixir | Oui* | ✓ |
| pub.dev | Dart | Oui | ✓ |
| PyPI | Python | Oui | ✓ |
| Maven | Java | ✓ | |
| Gradle Build Cache | Java/Kotlin | ✓ | |
| NuGet | .NET | Oui | ✓ |
| Composer | PHP | Oui | ✓ |
| Conan | C/C++ | ✓ | |
| Conda | Python/R | Oui | ✓ |
| CRAN | R | ✓ | |
| Julia | Julia | ✓ | |
| Swift | Swift | ✓ | |
| Container | Docker/OCI | ✓ | |
| Homebrew | macOS/Linux | ✓ | |
| Debian | Debian/Ubuntu | ✓ | |
| RPM | RHEL/Fedora | ✓ | |
| Alpine | Alpine Linux | ✓ | |
| Arch | Arch Linux |
Le cooldown nécessite des horodatages de publication dans les métadonnées. Les registres sans « Oui » dans la colonne cooldown soit n'exposent pas d'horodatages, soit n'ont pas encore été configurés.
* Le cooldown Hex nécessite de désactiver la vérification de signature du registre (HEX_NO_VERIFY_REPO_ORIGIN=1) puisque le proxy réencode la charge utile protobuf.
brew install git-pkgs/git-pkgs/proxy
Ou téléchargez un binaire depuis la [page des releases](https://github.com/git-pkgs/proxy/releases).
### Helm
Installez le chart depuis GHCR, en définissant l'URL publique que les clients
de gestionnaires de paquets utiliseront pour atteindre le proxy :```bash
helm install proxy oci://ghcr.io/git-pkgs/charts/proxy \
--set config.data.base_url=https://proxy.example.com
Le chart par défaut déploie un replica soutenu par un volume persistant de 10 GiB,
utilisant SQLite et un stockage d'artefacts sur système de fichiers sous /data. Voir
deploy/charts/proxy/values.yaml pour les options de configuration
d'ingress, de base de données externe et de stockage d'objets.
go build -o proxy ./cmd/proxy
./proxy
./proxy -listen :3000 -base-url https://proxy.example.com
Le proxy est maintenant en cours d'exécution. Configurez vos gestionnaires de paquets pour l'utiliser.
## OpenAPI (Swagger)
Ce dépôt utilise swaggo pour générer une spécification OpenAPI à partir des gestionnaires annotés.
Générez la spécification :```bash
go install github.com/swaggo/swag/cmd/swag@latest
go generate ./internal/server
Les fichiers générés sont écrits dans docs/swagger/.
Lorsque le proxy est en cours d'exécution, récupérez la spécification en direct depuis :
http://localhost:8080/openapi.jsonOu remplacez http://localhost:8080 par votre URL de base configurée. Ce lien est également affiché sur le tableau de bord.
Créez ou modifiez ~/.npmrc :```
registry=http://localhost:8080/npm/
Ou définir par projet dans `.npmrc` :```
registry=http://localhost:8080/npm/
Ou utilisez la variable d'environnement :```bash npm_config_registry=http://localhost:8080/npm/ npm install
### Cargo
Créez ou modifiez `~/.cargo/config.toml` :```toml
[source.crates-io]
replace-with = "proxy"
[source.proxy]
registry = "sparse+http://localhost:8080/cargo/"
Ou définissez-le par projet dans .cargo/config.toml à la racine de votre projet.
Définissez la source de la gem dans votre Gemfile :```ruby
source "http://localhost:8080/gem"
Ou configurer globalement :```bash
gem sources --add http://localhost:8080/gem/
bundle config mirror.https://rubygems.org http://localhost:8080/gem
Définissez la variable d'environnement GOPROXY :```bash export GOPROXY=http://localhost:8080/go,direct
Ou dans votre profil shell pour la persistance.
### Homebrew
Faites pointer l'API JSON et le domaine des artefacts de Homebrew vers le proxy :```bash
export HOMEBREW_API_DOMAIN=http://localhost:8080/homebrew
export HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080
Le domaine artifact proxyfie les manifestes et les blobs de bottles sous /v2/homebrew/core/. Le routage GHCR est limité à ce dépôt. Les archives sources, les téléchargements d'applications cask, les artifacts de taps personnalisés et les miroirs de bottles flat-file hérités utilisent les URLs de repli normales de Homebrew. Laissez le repli activé en laissant HOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK non défini.
Activez cache_metadata ou définissez PROXY_CACHE_METADATA=true pour conserver les réponses de l'API JSON de Homebrew en vue d'un repli hors ligne. Les blobs de bottles et leurs manifestes OCI sont mis en cache sans ce paramètre.
Les upstreams sont par défaut https://formulae.brew.sh/api pour l'API JSON et https://ghcr.io pour les artifacts. Pour chaîner ce proxy à un autre proxy, configurez ses endpoints Homebrew comme upstreams :```yaml
upstream:
homebrew_api: "https://upstream-proxy.example.com/homebrew"
homebrew_artifact: "https://upstream-proxy.example.com"
Les variables d'environnement équivalentes sont `PROXY_UPSTREAM_HOMEBREW_API` et `PROXY_UPSTREAM_HOMEBREW_ARTIFACT`.
### Hex (Elixir)
Configurez dans `~/.hex/hex.config` :```erlang
{default_url, <<"http://localhost:8080/hex">>}.
Ou définissez la variable d'environnement :```bash export HEX_MIRROR=http://localhost:8080/hex
### pub.dev (Dart/Flutter)
Définissez la variable d'environnement PUB_HOSTED_URL :```bash
export PUB_HOSTED_URL=http://localhost:8080/pub
Configurez pip pour utiliser le proxy :```bash pip install --index-url http://localhost:8080/pypi/simple/ package_name
Ou définir dans `~/.pip/pip.conf` :```ini
[global]
index-url = http://localhost:8080/pypi/simple/
Ajoutez à votre ~/.m2/settings.xml :```xml
proxy
central
http://localhost:8080/maven/
Le point de terminaison `/maven/` utilise Maven Central comme dépôt amont principal et bascule vers le Gradle Plugin Portal pour les métadonnées de marqueur de plugin Gradle et les artefacts associés lorsque le dépôt amont principal renvoie une réponse « not found ».
Pour la résolution de plugins Gradle via le même point de terminaison proxy :```kotlin
pluginManagement {
repositories {
maven(url = "http://localhost:8080/maven/")
}
}
Configurer dans settings.gradle(.kts) :```kotlin
buildCache {
local {
enabled = false
}
remote {
url = uri("http://localhost:8080/gradle/")
push = true
}
}
### NuGet
Configurer dans `nuget.config` :```xml
<configuration>
<packageSources>
<clear />
<add key="proxy" value="http://localhost:8080/nuget/v3/index.json" />
</packageSources>
</configuration>
Ou utilisez la CLI :```bash dotnet nuget add source http://localhost:8080/nuget/v3/index.json -n proxy
### Composer (PHP)
Configurer dans `composer.json` :```json
{
"repositories": [
{
"type": "composer",
"url": "http://localhost:8080/composer"
}
]
}
Ou définir globalement :```bash composer config -g repositories.proxy composer http://localhost:8080/composer
### Conan (C/C++)
Ajoutez le proxy en tant que remote :```bash
conan remote add proxy http://localhost:8080/conan
conan remote disable conancenter
Ou configurez dans ~/.conan2/remotes.json.
Configurez dans ~/.condarc :```yaml
channels:
Ou définir via la commande :```bash
conda config --add channels http://localhost:8080/conda/main
Définissez le dépôt dans R :```r options(repos = c(CRAN = "http://localhost:8080/cran"))
Ou dans `~/.Rprofile` pour la persistance :```r
local({
r <- getOption("repos")
r["CRAN"] <- "http://localhost:8080/cran"
options(repos = r)
})
Définissez le serveur Pkg avant de démarrer Julia :```bash export JULIA_PKG_SERVER=http://localhost:8080/julia
Ou à l'intérieur d'une session en cours :```julia
ENV["JULIA_PKG_SERVER"] = "http://localhost:8080/julia"
using Pkg; Pkg.update()
Configurez le proxy comme registre par défaut pour le paquet Swift actuel :```bash swift package-registry set --allow-insecure-http http://localhost:8080/swift
Les dépendances de registre utilisent leur identifiant de paquet à portée dans `Package.swift` :```swift
dependencies: [
.package(id: "apple.swift-argument-parser", from: "1.2.0")
]
Le proxy prend en charge la résolution des dépendances et le téléchargement des sources. La publication avec
swift package-registry publish n'est pas prise en charge.
Configurez Docker pour utiliser le proxy comme miroir de registre dans /etc/docker/daemon.json :```json
{
"registry-mirrors": ["http://localhost:8080"]
}
Puis redémarrez Docker :```bash
sudo systemctl restart docker
Ou récupérez directement les images :```bash docker pull localhost:8080/library/nginx:latest
### Helm
Configurez chaque dépôt de chart HTTP avec un nom, puis ajoutez l'URL de proxy correspondante à Helm :```yaml
upstream:
helm:
bitnami: "https://charts.bitnami.com/bitnami"
| --no-color | Désactive la sortie colorée |
| --debug | Active la journalisation de débogage |
| --verbose | Active la journalisation verbeuse |
| --silent | Supprime toute sortie |
| --version | Affiche la version et quitte |
| --help | Affiche le message d'aide et quitte |```bash
helm repo add bitnami http://localhost:8080/helm/bitnami
helm repo update
helm pull bitnami/nginx
Le proxy met en cache `index.yaml` en utilisant les paramètres normaux de cache de métadonnées et
met en cache les archives de charts après avoir vérifié leur empreinte SHA-256 à partir de l'index.
Pour les charts stockés dans un registre OCI, configurez un upstream OCI nommé et ajoutez
le préfixe réservé `upstream/{name}` à la référence du chart :```yaml
upstream:
oci:
ghcr: "https://ghcr.io"
--no-color : Désactive la sortie colorée.--verbose : Active la journalisation détaillée.--quiet : Supprime toute sortie sauf les erreurs.--config <path> : Spécifie un fichier de configuration personnalisé.--timeout <seconds> : Définit un délai d'expiration pour les requêtes réseau.--retry <count> : Définit le nombre de tentatives en cas d'échec.--proxy <url> : Utilise le proxy spécifié pour les requêtes réseau.--user-agent <string> : Définit une chaîne User-Agent personnalisée.--header <header> : Ajoute un en-tête HTTP personnalisé.--cookie <cookie> : Ajoute un cookie personnalisé.--data <data> : Envoie les données spécifiées dans le corps de la requête.--method <method> : Spécifie la méthode HTTP à utiliser.--url <url> : Spécifie l'URL cible.--output <file> : Écrit la sortie dans le fichier spécifié.--input <file> : Lit l'entrée depuis le fichier spécifié.--format <format> : Spécifie le format de sortie.--threads <count> : Définit le nombre de threads à utiliser.--rate-limit <rate> : Définit la limite de débit pour les requêtes.--random-agent : Utilise un User-Agent aléatoire pour chaque requête.--follow-redirects : Suit les redirections HTTP.--insecure : Ignore les erreurs de certificat SSL.--silent : Supprime toute sortie sauf les résultats.--debug : Active la sortie de débogage.--version : Affiche les informations de version.--help : Affiche le message d'aide.```bash
helm pull oci://localhost:8080/upstream/ghcr/owner/charts/mychart --version 1.0.0 --plain-http### Debian / APT
Configurez APT pour utiliser le proxy dans `/etc/apt/sources.list.d/proxy.list` :```
deb http://localhost:8080/debian stable main contrib
Remplacez vos entrées existantes de sources.list, puis :```bash sudo apt update
La valeur par défaut en amont est `http://deb.debian.org/debian`. Pour proxyfier un autre dépôt APT (par exemple Ubuntu), définissez `upstream.debian` dans le fichier de configuration ou `PROXY_UPSTREAM_DEBIAN` dans l'environnement :```yaml
upstream:
debian: "http://archive.ubuntu.com/ubuntu"
Configurez yum/dnf pour utiliser le proxy dans /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
Puis :```bash
sudo dnf clean all
sudo dnf update
Faites pointer /etc/apk/repositories vers le proxy. Le nom de dépôt par défaut
alpine proxy le miroir officiel (https://dl-cdn.alpinelinux.org/alpine) :```
http://localhost:8080/apk/alpine/v3.22/main
http://localhost:8080/apk/alpine/v3.22/community
Puis :```bash
apk update
Les index de dépôt (v2 APKINDEX.tar.gz et v3 Packages.adb), les
signatures détachées et les paquets sont servis octet par octet sans
modification, de sorte que la vérification normale des signatures d'apk
continue de fonctionner. Les index utilisent le cache de métadonnées
(metadata_ttl, repli sur les données périmées) ; les paquets .apk sont
stockés dans le cache d'artefacts partagé et restent disponibles lorsque
l'upstream est injoignable.
Pour proxyfier d'autres miroirs ou dépôts privés, configurez des upstreams
nommés sous upstream.apk (cela remplace la valeur par défaut intégrée ;
rajoutez alpine si vous le souhaitez toujours) :```yaml
upstream:
apk:
alpine: "https://dl-cdn.alpinelinux.org/alpine"
private: "https://apk.example.com"
# KitPloit - Outils de sécurité open source
## Outils
- [**KitPloit**](https://www.kitploit.com/) - Votre source principale pour les outils de sécurité open source.
## Derniers outils
- [**Tool Name**](https://www.kitploit.com/2024/01/tool-name.html) - Description de l'outil.```
http://localhost:8080/apk/private
apk ajoute l'architecture et le nom de fichier d'index à chaque ligne de dépôt lui-même.
Configurez des upstreams génériques nommés :```yaml upstream: generic: github: "https://github.com" github-api: "https://api.github.com"
Ensuite, réécrivez les URL GitHub dans les paramètres de 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"
Les ressources de release sont mises en cache de façon permanente après le premier téléchargement et continuent de s'installer même lorsque GitHub est indisponible. Les recherches de tags via api.github.com sont mises en cache pendant metadata_ttl et servies de manière obsolète pendant une panne ou une limitation de débit. Committez un mise.lock et installez avec mise install --locked afin que les installations épinglées ne nécessitent aucun appel API. Ajoutez un bearer token pour https://api.github.com sous upstream.auth si la flotte dépasse la limite de débit anonyme de GitHub.
Le proxy peut être configuré via :
-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
### Variables d'environnement```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"
Voir la [référence de configuration](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md#upstream-registries) pour chaque clé upstream, variable d'environnement et URL par défaut.
Exécuter avec un fichier de configuration :```bash
./proxy -config /etc/proxy/config.yaml
SQLite est la base de données par défaut et convient bien aux déploiements sur un seul nœud. Pour les configurations multi-nœuds ou si vous préférez une base de données managée, passez à Postgres :```yaml database: driver: "postgres" url: "postgres://user:password@localhost:5432/proxy?sslmode=disable"
Ou via des variables d'environnement :```bash
PROXY_DATABASE_DRIVER=postgres
PROXY_DATABASE_URL=postgres://user:password@localhost:5432/proxy?sslmode=disable
Le proxy crée les tables automatiquement lors de la première exécution.
Le proxy peut stocker les artefacts mis en cache dans S3 ou tout service compatible S3 (MinIO, R2, etc.) au lieu du système de fichiers local.```yaml storage: url: "s3://my-bucket-name?region=us-east-1"
Pour les services compatibles S3 comme MinIO :```yaml
storage:
url: "s3://my-bucket?endpoint=http://localhost:9000&disableSSL=true&s3ForcePathStyle=true"
Définissez les identifiants via les variables d'environnement AWS standard (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION).
Le proxy peut stocker les artefacts mis en cache dans un bucket GCS en utilisant le schéma d'URL gs://.```yaml
storage:
url: "gs://my-bucket-name"
L'authentification utilise [Application Default Credentials](https://docs.cloud.google.com/docs/authentication/application-default-credentials), ce qui signifie qu'aucun identifiant n'a besoin d'être intégré dans la configuration ou l'environnement. Sources prises en charge, dans l'ordre :
- **GKE Workload Identity** — liez le compte de service Kubernetes exécutant le proxy à un compte de service Google disposant de `roles/storage.objectAdmin` sur le bucket. Le proxy utilisera automatiquement le jeton de la charge de travail.
- **Compte de service attaché** sur GCE, Cloud Run, Cloud Functions, etc.
- **Variable d'environnement `GOOGLE_APPLICATION_CREDENTIALS`** pointant vers un fichier de clé JSON de compte de service.
- **`gcloud auth application-default login`** pour le développement local.
#### Configuration de 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
Lorsque direct_serve: true est activé, le proxy émet des redirections HTTP 302 vers des URL GCS présignées. Workload Identity ne fournit aucune clé privée, donc le backend GCS appelle l'API IAM Credentials signBlob. Accordez au compte de service le rôle de créateur de jetons sur lui-même :```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"
## Commandes CLI
### serve (par défaut)
Démarre le serveur proxy. C'est la commande par défaut si aucune n'est spécifiée.```bash
proxy serve [flags]
proxy [flags] # same as 'proxy serve'
Pré-remplir le cache à partir de PURLs, de fichiers SBOM ou de registres entiers. Utile pour garantir la disponibilité hors ligne ou préchauffer le cache avant les déploiements.```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]
La commande mirror accepte les mêmes options de stockage et de base de données que `serve`. Les artefacts déjà mis en cache sont ignorés.
Une API mirror est également disponible lorsque le serveur est en cours d'exécution :```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
Affiche les statistiques du cache sans exécuter le serveur.```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
Exemple de sortie :```
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)
| Point de terminaison | Description |
|---|---|
GET / | Tableau de bord (interface web) |
GET /health | Vérification de l'état et état du disjoncteur en amont (JSON ; HTTP 200 sain, 503 non sain) |
GET /stats | Statistiques du cache (JSON) |
GET /metrics | Métriques Prometheus |
GET /npm/* | Protocole du registre npm |
GET /cargo/* | Protocole d'index sparse Cargo |
GET /gem/* | Protocole RubyGems |
GET /go/* | Protocole de proxy de modules Go |
GET /hex/* | Protocole Hex.pm |
GET /pub/* | Protocole pub.dev |
GET /pypi/* | API simple/JSON PyPI |
GET /maven/* | Protocole de dépôt Maven |
GET /nuget/* | API NuGet V3 |
GET /composer/* | Protocole Composer/Packagist |
GET /conan/* | Protocole Conan C/C++ |
GET /conda/* | Protocole Conda/Anaconda |
GET /cran/* | Protocole CRAN (R) |
GET /julia/* | Protocole de serveur Julia Pkg |
GET /swift/* | Protocole Swift Package Registry v1 |
GET /helm/{repository}/* | Protocole de dépôt de charts Helm HTTP |
GET /homebrew/* | API JSON Homebrew |
GET /v2/* | Protocole de registre OCI/Docker |
GET /v2/homebrew/core/* | Manifestes et blobs de bouteilles Homebrew core depuis GHCR |
GET /apk/{repository}/* |
| Point de terminaison | Description |
|---|---|
POST /api/mirror | Démarrer une tâche de miroir (corps JSON avec purls ou un sbom en ligne) |
GET /api/mirror/{id} | Obtenir l'état et la progression de la tâche |
DELETE /api/mirror/{id} | Annuler une tâche en cours d'exécution |
Le proxy fournit des points de terminaison REST pour l'enrichissement des métadonnées de paquets, l'analyse des vulnérabilités et la détection des versions obsolètes.
| Point de terminaison | Description |
|---|---|
GET /api/package/{ecosystem}/{name} | Obtenir les métadonnées d'un paquet |
GET /api/package/{ecosystem}/{name}/{version} | Obtenir les métadonnées d'une version avec les vulnérabilités |
GET /api/vulns/{ecosystem}/{name} | Obtenir toutes les vulnérabilités d'un paquet |
GET /api/vulns/{ecosystem}/{name}/{version} | Obtenir les vulnérabilités d'une version spécifique |
POST /api/outdated | Vérifier plusieurs paquets pour les versions obsolètes |
POST /api/bulk | Recherche groupée de métadonnées de paquets |
I need the actual content of chunk 143 to translate it. The message you sent contains only the instructions and the label "INPUT:" followed by "Response:" — but no source text was included.
Please paste the Markdown content for chunk 143/189 and I will return the French translation, preserving all structure and leaving code, commands, paths, URLs, and identifiers untouched.```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 to translate. You've provided the instructions and metadata, but the INPUT section is empty — there's no Markdown text for chunk 147.
Please paste the source content for this chunk and I'll return the French 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. 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 151 and I'll return the French translation following all the rules you've specified.```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]"
]
}'
I need the actual content of chunk 155 to translate it. The message you sent contains only the instructions and the label "INPUT:" followed by "Response:" — but no source text was included.
Please paste the Markdown content of chunk 155 (the English source text), and I will return the French translation following all the rules you specified.```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" }
## Fonctionnement
1. Le gestionnaire de paquets demande les métadonnées du paquet au proxy
2. Le proxy récupère les métadonnées depuis l'amont, réécrit les URL des artefacts pour qu'elles pointent vers le proxy
3. Le gestionnaire de paquets demande l'artefact (tarball, crate, etc.)
4. Le proxy vérifie le cache local :
- **Cache hit** : Sert depuis le stockage local
- **Cache miss** : Récupère depuis l'amont, stocke localement, sert au client
5. Les requêtes suivantes pour le même artefact sont servies depuis le cache```
┌─────────────┐ ┌─────────┐ ┌──────────┐
│ npm/cargo │────▶│ proxy │────▶│ upstream │
│ client │◀────│ │◀────│ registry │
└─────────────┘ └─────────┘ └──────────┘
│
▼
┌─────────┐
│ cache │
│ storage │
└─────────┘
Le proxy sert une interface web sous /ui. Aucune compilation frontend séparée n'est nécessaire -- les templates et les assets sont intégrés dans le binaire. GET / redirige vers /ui/. L'interface est montée sous son propre préfixe afin qu'un reverse proxy puisse lui appliquer des règles d'accès différentes de celles des endpoints de paquets (par exemple, exiger une authentification pour PathPrefix(/ui) tout en laissant /npm, /pypi etc. ouverts aux machines de build).
/ui/) -- statistiques de cache, paquets populaires, artefacts récemment mis en cache et aperçu des vulnérabilités./ui/install) -- instructions de configuration par écosystème, pour ne pas avoir à les chercher ici./ui/packages) -- parcourir tous les paquets en cache avec filtrage par écosystème et tri par hits, taille, nom ou nombre de vulnérabilités./ui/search?q=...) -- rechercher les paquets en cache par nom./ui/package/{ecosystem}/{name}) -- métadonnées, licence, vulnérabilités et liste des versions d'un paquet. Vous pouvez sélectionner deux versions à comparer./ui/package/{ecosystem}/{name}/{version}) -- métadonnées par version, hash d'intégrité, statut du cache d'artefacts et compteurs de hits./ui/package/{ecosystem}/{name}/{version}/browse) -- parcourir les fichiers à l'intérieur des archives en cache avec coloration syntaxique pour les fichiers texte et aperçus d'images./ui/package/{ecosystem}/{name}/compare/{v1}...{v2}) -- diff côte à côte de deux versions en cache montrant les fichiers ajoutés, supprimés et modifiés.Le proxy expose des métriques Prometheus à GET /metrics. Tous les noms de métriques sont préfixés par proxy_.
| Métrique | Type | Labels | Description |
|---|---|---|---|
proxy_requests_total | counter | ecosystem, status | Réponses du proxy par écosystème de paquets et statut HTTP |
proxy_request_duration_seconds | histogram | ecosystem, status | Durée des requêtes du proxy |
proxy_cache_hits_total | counter | ecosystem | Hits de cache |
proxy_cache_misses_total | counter | ecosystem | Misses de cache |
proxy_cache_size_bytes | gauge | Taille totale des artefacts en cache | |
proxy_cached_artifacts_total | gauge | Nombre d'artefacts en cache | |
proxy_upstream_fetch_duration_seconds | histogram | ecosystem | Temps passé à récupérer depuis l'upstream |
proxy_upstream_errors_total | counter | ecosystem, error_type | Échecs de récupération upstream |
proxy_storage_operation_duration_seconds | histogram | operation | Latence de lecture/écriture du stockage |
proxy_storage_errors_total | counter | operation | Échecs de lecture/écriture du stockage |
proxy_active_requests | gauge | Requêtes en cours | |
proxy_health_probe_failures_total | counter | step | Échecs de sonde de santé du stockage par étape défaillante (write, size, read, verify, delete). |
proxy_circuit_breaker_state |
La taille du cache et le nombre d'artefacts sont rafraîchis toutes les 60 secondes. L'état du disjoncteur est lu depuis le fetcher à chaque scrape de /metrics et à chaque requête /health, donc proxy_circuit_breaker_trips_total compte les déclenchements visibles entre ces lectures — un disjoncteur qui s'ouvre et se rétablit entièrement entre deux scrapes n'est pas compté. Les autres métriques sont mises à jour à chaque requête.
Les métriques du disjoncteur portent une série par hôte upstream, mais uniquement pour les hôtes dont le disjoncteur s'est déclenché au moins une fois depuis le démarrage. Un disjoncteur est créé par hôte depuis lequel le proxy récupère des artefacts, et pour certains écosystèmes cet hôte provient des métadonnées upstream plutôt que de la configuration (composer le tire du dist.url d'un paquet, helm des URLs de charts dans index.yaml), donc publier chaque hôte laisserait le contenu upstream faire croître le nombre de séries pendant toute la durée de vie du processus. Une fois qu'un hôte s'est déclenché, il continue de reporter, donc un rétablissement apparaît toujours comme une transition vers 0 plutôt que comme une série qui disparaît. /health n'est pas une série temporelle persistante et liste tous les disjoncteurs, déclenchés ou non.
Le label registry est l'hôte de l'URL depuis laquelle l'artefact a été récupéré. Comme cette URL peut provenir des métadonnées upstream, il n'est pas toujours possible d'en extraire un hôte — un dist.url signé qui échoue à l'analyse, par exemple — et un tel disjoncteur est étiqueté hostless-url-<digest> à la place, où le digest est indexé par une valeur tirée au démarrage. Ni /metrics ni /health n'exigent d'authentification, donc une URL de récupération n'est jamais publiée comme label ou comme clé ; le digest identifie le disjoncteur aussi longtemps que le processus tourne sans révéler l'URL derrière lui ni permettre qu'une URL choisie y soit associée.
Alertez sur proxy_circuit_breaker_state == 2 maintenu pendant plus de quelques minutes : tant qu'un disjoncteur est ouvert, les téléchargements d'artefacts pour cet upstream échouent avec HTTP 502 à chaque miss de cache, et une seule requête de sonde par intervalle de backoff atteint l'upstream. Les artefacts en cache continuent d'être servis, tout comme les métadonnées du même écosystème (les métadonnées ne passent pas par le disjoncteur), donc les installations échouent d'une manière qui ressemble à une panne upstream partielle.
/health renvoie un rapport JSON structuré de la santé des sous-systèmes. HTTP 200 si toutes les vérifications passent ; 503 si l'une échoue.```json
{
"status": "ok",
"checks": {
"database": {"status": "ok"},
"storage": {"status": "ok"}
},
"circuit_breakers": {
"registry.npmjs.org": "closed",
"static.crates.io": "open"
}
}
Les vérifications en échec incluent un champ `"error"`. Les échecs de stockage incluent également un champ `"step"` identifiant l'étape de sonde qui a échoué (`write`, `size`, `read`, `verify`, `delete`). Lorsque la vérification de la base de données échoue, l'entrée de stockage indique `{"status": "skipped"}` afin que la réponse porte toujours le même ensemble de clés.
`circuit_breakers` rapporte l'état du disjoncteur de récupération d'artefacts de chaque amont (`"open"` ou `"closed"`), indexé par hôte amont — ou par le placeholder `hostless-url-<digest>` décrit dans [Monitoring](#monitoring) lorsque l'URL de récupération n'a pas d'hôte à lire. La clé est omise tant que le proxy n'a pas récupéré d'artefact depuis au moins un amont, et un hôte n'apparaît qu'une fois qu'un disjoncteur a été créé pour lui. Les disjoncteurs se déclenchent après des échecs amont répétés et réessaient l'amont après un backoff exponentiel. Tant qu'un disjoncteur est ouvert, les téléchargements d'artefacts pour cet hôte renvoient HTTP 502 en cas d'absence en cache sans contacter l'amont ; les artefacts déjà en cache sont toujours servis depuis le stockage, car le cache est vérifié avant le fetcher. Un disjoncteur est rapporté comme `"open"` pendant tout son backoff, y compris la fenêtre half-open dans laquelle il admet une requête de sonde pour tester la reprise. L'état du disjoncteur est par processus et en mémoire, donc un redémarrage le réinitialise, mais un redémarrage n'est pas nécessaire pour la reprise : le backoff continue de réessayer tant que le disjoncteur est ouvert, il se ferme donc de lui-même une fois que l'amont sert à nouveau.
Un disjoncteur ouvert ne définit **pas** `status` à `"error"` et ne change pas le code de statut HTTP : il signale un amont spécifique refusant de servir, et non ce proxy inapte à recevoir du trafic, et faire échouer la sonde de readiness à cause d'un seul amont défaillant retirerait le pod de la rotation pour tous les autres écosystèmes également. Utilisez `proxy_circuit_breaker_state` pour alerter à ce sujet.
Les résultats de la sonde de stockage sont mis en cache pendant `health.storage_probe_interval` (30s par défaut) afin de borner le coût de sondage des backends distants. Une sonde détient un mutex interne pendant jusqu'à 10 secondes (le timeout par sonde codé en dur), donc `/health` est conçu comme une sonde de **readiness** Kubernetes plutôt qu'une sonde de liveness — un aller-retour S3 lent devrait retirer le pod de la rotation, pas le redémarrer.
Configuration de scrape pour Prometheus :```yaml
scrape_configs:
- job_name: git-pkgs-proxy
static_configs:
- targets: ["localhost:8080"]
Créez /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
Activer et démarrer :```bash
sudo systemctl enable proxy
sudo systemctl start proxy
Un Dockerfile est inclus dans le dépôt. Compiler et exécuter :```bash docker build -t proxy . docker run -p 8080:8080 -v proxy-data:/data proxy
Avec Postgres et 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
Lors de l'exécution derrière nginx, Apache ou un autre proxy inverse, définissez base_url sur votre URL publique :```yaml
base_url: "https://proxy.example.com"
Si l'interface utilisateur est accessible via un nom d'hôte différent de celui des points de terminaison des paquets — par exemple, l'interface utilisateur exposée publiquement sur un domaine tandis que les machines de build accèdent à un alias de réseau Docker — définissez `ui_base_url` séparément. `base_url` est l'URL utilisée par les gestionnaires de paquets et la réécriture des métadonnées ; `ui_base_url` est l'URL annoncée aux humains visitant l'interface web (balises canonical/`og:url` et la bannière du guide d'installation) :```yaml
base_url: "http://pkg-proxy:8080" # internal alias for build machines
ui_base_url: "https://proxy.example.com/ui" # public UI URL
Lorsqu'elle n'est pas définie, ui_base_url prend par défaut la valeur de base_url.
Avertissement : le proxy sert l'interface utilisateur et les points de terminaison de paquets sur le même listener. Définir
ui_base_urlne change que l'URL que l'interface utilisateur annonce aux humains ; cela n'empêche pas les points de terminaison de paquets d'être accessibles sur le même nom d'hôte et le même port. Lorsque vous placez le proxy derrière un reverse proxy public, restreignez la route publique àPathPrefix(/ui)(ou l'équivalent de votre proxy), sinon/npm,/pypiet les autres points de terminaison de paquets restent exposés aux côtés de l'interface utilisateur.
Exemple nginx, restreignant l'hôte public à l'interface utilisateur tout en laissant les points de terminaison de paquets accessibles uniquement sur le listener interne :```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;
}
}
Exemple Traefik utilisant `PathPrefix(/ui)` afin que le routeur public ne corresponde qu'au trafic de l'interface utilisateur :```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"
Le proxy stocke les artefacts dans le répertoire de stockage configuré avec la structure suivante :``` 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
Les métadonnées du cache sont stockées dans SQLite (par défaut) ou PostgreSQL. Pour vider un cache local :```bash
rm -rf ./cache/artifacts/*
rm ./cache/proxy.db
Le proxy recréera la base de données au prochain démarrage.
Prérequis :
go.mod)```bash
git clone https://github.com/git-pkgs/proxy.git
cd proxy
go build -o proxy ./cmd/proxyExécuter les tests :```bash
go test ./...
GPL-3.0-or-later
| ✗ |
| Chef | Chef | ✗ |
| Generic | Any | ✓ |
| Helm | Kubernetes | ✓ |
| Vagrant | Vagrant | ✗ |
| Protocole de dépôt Alpine APK |
GET /generic/{name}/* | Proxy de téléchargement HTTP générique (ressources de release GitHub, mise/aqua) |
GET /debian/* | Protocole de dépôt Debian/APT |
GET /rpm/* | Protocole de dépôt RPM/Yum |
| gauge |
registry |
| État du disjoncteur de récupération d'artefacts par registre upstream (0 fermé, 2 ouvert). Publié une fois que le disjoncteur de ce registre s'est déclenché. |
proxy_circuit_breaker_trips_total | counter | registry | Déclenchements du disjoncteur par registre upstream. |