Proxy de dépendances
Le proxy de dépendances est un cache pull-through pour les registres publics, exploité par organisation. Vous dirigez
docker, npm, pip, uv, dnf, Maven, NuGet, go, helm ou cargo vers le chemin du proxy de votre organisation sur frem.sh, et fremforge récupère
les contenus depuis le registre public en votre nom :
- Le premier pull d’une couche d’image ou d’un fichier de paquet est récupéré depuis la source en amont et vérifié par rapport au hash publié par celle-ci. Si votre organisation active l’analyse antivirus, il est aussi analysé par ClamAV pendant qu’il vous est transmis. Un fichier qui échoue à une vérification n’est jamais servi ni stocké.
- Les pulls suivants sont servis depuis le stockage de fremforge dans l’UE, pour chaque membre de votre organisation.
- Si la source en amont est en panne, la dernière copie valide est servie. Les tags, les packuments npm, les index
PyPI, les
repomd.xmlRPM, lesmaven-metadata.xmlMaven, les listes de versions et enregistrements NuGet, les listes de versions Go et@latest, les fichiersindex.yamlHelm et les fichiers d’index Cargo reçoivent une réponse tirée de la dernière copie valide, avec l’en-tête de réponseX-Fremforge-Proxy: stale. Voir Pannes en amont. - La politique de paquets de votre organisation et les vérifications des paquets malveillants sont évaluées pour les paquets et images passant par le proxy, et chaque pull est enregistré dans le journal d’accès au registre. Depuis le 2026-10-11, un paquet ou une image connu comme malveillant est refusé pour toutes les organisations, et une politique en mode Appliquer refuse ce qui l’enfreint ; voir Ce qui est appliqué aujourd’hui.
Le proxy est en lecture seule. Vous ne pouvez pas y pousser de contenu.
Disponibilité et activation
Le proxy est disponible dans toutes les formules et activé par défaut pour chaque organisation. Un
propriétaire de l’organisation peut le désactiver ou modifier ses paramètres sous Build et déploiement › Proxy de
dépendances ou via l’API (un jeton avec la portée policy:write) :
curl -X PUT -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"enabled": true, "malware_scan": true}' \
https://frem.sh/_app/api/v1/orgs/<org>/dependency-proxyUne organisation qui n’a jamais enregistré ces paramètres a la configuration par défaut : le proxy activé, et les runners hébergés qui passent par lui (voir Runners hébergés). Dès qu’un propriétaire les enregistre, l’organisation conserve exactement ce qui a été enregistré.
L’analyse antivirus (malware_scan) est désactivée par défaut. Lorsqu’elle est activée, chaque couche d’image,
fichier de paquet et chart que votre organisation récupère via le proxy est analysé par ClamAV, y compris
lorsqu’une autre organisation l’a mis en cache en premier sans l’analyser : cette copie est analysée une fois, la
première fois qu’une organisation qui analyse l’utilise, et son verdict vaut ensuite pour tout le monde. Les fichiers de
paquets et les charts sont analysés avant d’être servis ; pour les couches d’images, voir
Images de conteneurs. Les paquets connus comme malveillants (avis OSV MAL-*) sont détectés pour toutes les organisations,
quelle que soit la valeur de ce paramètre. La même page et le même endpoint définissent block_until_scanned pour les images
de conteneurs, qui nécessite l’analyse antivirus (voir
Images de conteneurs), et retention_days (de 7 à 365, 90 par défaut ; voir
Rétention). Un GET sur l’endpoint indique si le proxy est activé, votre utilisation et
votre plafond.
Authentification
Utilisez les mêmes identifiants que pour le registre de paquets :
- Personnes : un jeton d’accès personnel avec
read:package(ou le jeton de courte durée quefremforge authfournit à vos outils). Vous devez être membre de l’organisation. - CI : le jeton de job Forgejo Actions. Un jeton de job ne récupère que via l’organisation de son propre dépôt ; le proxy de toute autre organisation le refuse. Les jobs issus de pull requests de forks peuvent récupérer, mais jamais via une source en amont qui utilise les identifiants propres à votre organisation.
- CI externe, hôtes de build et pull secrets : un robot de registre
avec un accès en lecture. Son jeton est un identifiant
read:packagecomme un autre. - Analyse des dépendances de fremforge : l’analyse d’atteignabilité lit les tarballs npm, les wheels PyPI et les JAR Maven via le proxy de votre organisation, par une route interne que seul le service d’analyse atteint. La vérification des licences, la vérification de l’âge de publication et le graphe de modules Go lisent de la même façon les métadonnées des registres (npm, PyPI, Go, Maven Central, RubyGems et Packagist). Cet accès est en lecture seule, ne peut pas être utilisé depuis l’extérieur de fremforge, et est soumis à votre politique de paquets, à votre cache et à votre plafond de stockage comme tout autre pull.
Runners hébergés
Par défaut, les jobs sur les runners hébergés par fremforge installent via le proxy de votre organisation
(runner_pull_through, activé par défaut). Au démarrage de chaque job, le runner dirige npm, pip et uv vers
le proxy, ainsi que Go, Maven, NuGet et la base de vulnérabilités de Trivy pour les écosystèmes
listés dans runner_pull_through_ecosystems (les quatre par défaut). Le job s’authentifie avec
son propre jeton de job, de sorte que chaque installation passe par votre politique de paquets et vos vérifications antivirus et figure dans
votre journal d’accès avec le dépôt du job. Si le proxy est injoignable au démarrage du job,
le job installe depuis les registres publics via le proxy de sortie de fremforge, et ce
repli est journalisé. Définissez runner_pull_through à false pour désactiver ce comportement. Voir aussi
Caches de paquets.
Images de conteneurs. Pour ces mêmes jobs, le démon Docker du job récupère aussi les images de conteneurs
via le proxy de votre organisation : docker pull, docker run, le FROM d’un Dockerfile, ainsi que les
conteneurs du job et de services: que le runner démarre. Rien ne change dans le workflow ; les noms
d’images restent tels quels (ghcr.io/..., quay.io/...) et chaque pull est mis en cache pour votre
organisation et enregistré dans votre journal d’accès.
- Pour toutes les organisations :
ghcr.io,quay.io,mcr.microsoft.com,registry.k8s.io,public.ecr.awsetregistry.access.redhat.com. - Uniquement avec l’identifiant propre à votre organisation :
docker.io,registry.redhat.ioetregistry.connect.redhat.comne passent par le proxy qu’une fois qu’un propriétaire a ajouté l’identifiant de votre organisation pour ce registre sous Identifiants des registres en amont. Les jobs issus de pull requests de forks ne l’utilisent jamais, si bien que leurs pulls depuis ces registres vont directement au registre. Sans identifiant, les pulls Docker Hub sont anonymes et soumis aux limites de débit de Docker Hub. - Repli : le proxy est vérifié au début de chaque job. S’il est injoignable, le job récupère chaque image directement depuis le registre, comme avant, et le repli est journalisé. Un pull isolé que le proxy ne peut pas servir bascule également vers le registre.
- Un cache, pas un contrôle : pour les images sur ce chemin, un pull que votre politique de paquets ou la vérification
antivirus refuse bascule lui aussi vers le registre. Lorsqu’un refus doit arrêter le pull, récupérez explicitement depuis
frem.sh/<org>/dependency-proxy/<registry>/<image>(ci-dessous). - Non couvert : un builder
docker buildxqui utilise le driverdocker-containerexécute son propre BuildKit et récupère directement. Le driver par défautdockerpasse par le proxy.
Images de conteneurs
docker login frem.sh # a token with read:package, as for the registry
docker pull frem.sh/<org>/dependency-proxy/<upstream>/<image>:<tag>Par exemple :
docker pull frem.sh/acme/dependency-proxy/quay.io/prometheus/busybox:latestEn CI :
echo "$GITHUB_TOKEN" | docker login frem.sh -u x --password-stdinLes sources en amont depuis lesquelles vous pouvez récupérer :
| Source en amont | Identifiants | Statut |
|---|---|---|
docker.io | L’identifiant Docker Hub propre à votre organisation, obligatoire (ci-dessous) | Vérifié de bout en bout |
registry.k8s.io, mcr.microsoft.com, public.ecr.aws, registry.access.redhat.com | Aucun | Vérifié de bout en bout |
ghcr.io, quay.io | Aucun pour les images publiques. L’identifiant propre à votre organisation, facultatif, pour les images privées (ci-dessous) | Images publiques : vérifié de bout en bout. Images privées avec votre identifiant : pris en charge, pas encore vérifié |
registry.redhat.io, registry.connect.redhat.com | Le compte de service de registre Red Hat de votre organisation, obligatoire | Pris en charge, pas encore vérifié : cela nécessite un compte Red Hat, dont fremforge ne dispose pas pour ses tests |
Tout autre hôte est refusé : le proxy ne récupère jamais une URL libre.
Le proxy ne liste pas les tags d’une image. Renovate hébergé propose malgré tout des mises à jour pour une image
que vous référencez via ce chemin, comme le FROM frem.sh/<org>/dependency-proxy/docker.io/library/python:3.14-slim d’un Dockerfile.
Il recherche les nouveaux tags et digests auprès du registre en amont et les écrit dans votre
référence, qui conserve le chemin du proxy. Vos builds continuent de récupérer via le proxy, de sorte que les
contrôles de pull décrits ci-dessous s’appliquent toujours.
Les charts Helm stockés comme artefacts OCI sur ces sources en amont passent par le même chemin (Helm 3.8 ou ultérieur) :
echo "$FREMFORGE_TOKEN" | helm registry login frem.sh -u <user or robot name> --password-stdin
helm pull oci://frem.sh/<org>/dependency-proxy/ghcr.io/prometheus-community/charts/prometheus --version 29.36.1Pour les charts d’un dépôt Helm classique (index.yaml), voir Charts Helm.
Un tag est revérifié auprès de la source en amont au plus une fois par minute, par une requête HEAD, que
Docker Hub ne décompte pas de sa limite de pulls. Les couches d’images passent par les mêmes contrôles de pull que les images poussées
dans votre registre : avec l’analyse antivirus activée, les couches infectées ou impossibles à analyser sont refusées ; il en va de même des images au-delà de votre
seuil de CVE si vous avez défini block_pull. Les paquets malveillants à l’intérieur d’une image sont traités
ci-dessous. Par
défaut, une image est servie pendant que ses couches sont analysées. Avec block_until_scanned, le
premier pull d’une image pas encore analysée, ou d’une couche par digest, renvoie 503 avec
Retry-After jusqu’à la fin de l’analyse, en général en quelques secondes. Une couche qu’une analyse a trouvée
infectée est refusée à toutes les organisations.
Pendant qu’une requête récupère et analyse une couche, les autres pulls de la même couche l’attendent.
Si cela prend plus d’environ quatre minutes, ils reçoivent 503 avec Retry-After: 30
(this layer is still being fetched and malware-scanned by another request), et une nouvelle tentative est
servie une fois la couche stockée. Une analyse qui manque de temps n’est pas un verdict : la couche est
retenue, comme une couche impossible à analyser, mais aucun résultat n’est enregistré. Elle est mise en file d’attente pour l’analyseur
de couches en arrière-plan de fremforge, qui dispose d’un budget de temps plus long, et un pull ultérieur est servi une fois que cette
analyse est réussie.
Un fichier de paquet dont l’analyse dépasse son délai (npm, PyPI, RPM, Maven, NuGet, Go, Cargo ou un chart Helm) est traité de la même façon : cette requête est refusée, aucun résultat n’est enregistré, et le fichier est mis en file pour le même analyseur en arrière-plan. Une requête ultérieure est servie une fois cette analyse réussie, ou refusée si elle trouve le fichier infecté. Un RPM reste propre à votre organisation pendant cette attente : il est stocké et analysé uniquement dans l’espace de votre organisation, et une autre organisation qui récupère le même RPM récupère et analyse sa propre copie.
Limites de taille. Le proxy ne sert aucune couche ni aucun fichier de plus de 10 Gio (403). ClamAV lit au
plus 4 Gio d’un même fichier ; avec l’analyse antivirus activée, une couche ou un fichier plus volumineux ne peut donc pas être entièrement
analysé et est retenu, sauf une couche de modèle safetensors ou GGUF qui passe sa vérification de format
(voir Analyse des modèles).
Paquets malveillants dans les images en cache
Les paquets de langage contenus dans chaque image que votre organisation met en cache (paquets npm, PyPI, Maven, Go, crates,
RubyGems, NuGet, Packagist, Pub et Hex) sont comparés aux avis OSV sur les paquets malveillants
(MAL-*), la même vérification que celle qui s’exécute sur les images que vous poussez :
- après la première mise en cache de l’image, en général dans le cycle d’analyse suivant (environ 15 minutes), et
- à nouveau chaque jour, de sorte qu’un avis publié après que vous avez récupéré l’image est quand même détecté.
Une correspondance est un résultat critique dans Sécurité › Résultats › Dépendances › Logiciels malveillants, listé comme
une image nommée <org>/dependency-proxy/<upstream>/<repository> avec le digest qui la
contient, et elle est envoyée aux personnes qui reçoivent vos alertes de sécurité. L’ignorer fonctionne comme pour
tout résultat de logiciel malveillant, avec un motif et une date de fin facultative. Le résultat se ferme de lui-même
une fois que votre organisation ne met plus cette image en cache, par exemple après sa suppression par la rétention.
Le pull d’une image comportant un résultat ouvert et non ignoré est refusé avec 403 DENIED, comme pour
les images poussées, et journalisé dans votre journal d’accès comme blocked avec le motif image_malware.
Refusé depuis le 2026-10-11 ; auparavant, un tel pull était servi et enregistré comme would_block.
Identifiants des registres en amont
Docker Hub (docker.io) et les registres Red Hat (registry.redhat.io et
registry.connect.redhat.com, les images certifiées des partenaires de Red Hat) ne sont récupérés via le
proxy de dépendances qu’avec le compte propre à votre organisation. Pour GitHub (ghcr.io) et Quay
(quay.io), un identifiant est facultatif : sans identifiant, ils sont récupérés anonymement, ce qui sert les
images publiques ; ajoutez-en un pour récupérer vos images privées. Un propriétaire de l’organisation ajoute l’identifiant
sous Build et déploiement › Proxy de dépendances › Identifiants des registres en amont, ou via l’API à
/_app/api/v1/orgs/<org>/dependency-proxy/upstreams. Formes acceptées :
- Docker Hub : votre nom d’utilisateur plus un jeton d’accès personnel, ou un jeton d’accès d’organisation avec le nom de l’organisation Docker comme nom d’utilisateur.
- Red Hat : un compte de service de registre (un nom d’utilisateur tel que
1234567|ci, plus son jeton), ou son pull secret OpenShift. Ajoutez-le une fois par registre Red Hat depuis lequel vous récupérez ; chacun ne conserve que sa propre entrée du pull secret. - GitHub (
ghcr.io) : votre nom d’utilisateur GitHub plus un jeton d’accès personnel (classique) avecread:packages. - Quay (
quay.io) : un compte robot (organisation+robot) plus son jeton, ou l’entréequay.iod’un pull secret Red Hat.
Les registres Red Hat avec votre identifiant, ainsi que les images privées ghcr.io et quay.io, sont
pris en charge mais pas encore vérifiés de bout en bout : fremforge les a testés avec le flux de jetons
des registres, mais ne dispose d’aucun compte pour récupérer des images.
Une fois qu’un identifiant ghcr.io ou quay.io est stocké, chaque pull depuis ce registre l’utilise,
images publiques comprises, et est mis en cache pour votre organisation uniquement. Les jobs issus de pull requests de forks
ne l’utilisent jamais : ils récupèrent ces deux registres anonymement et n’obtiennent donc que les images publiques.
Le secret est stocké chiffré et utilisé uniquement par le proxy de dépendances, pour les pulls de votre propre organisation. Il n’est plus jamais affiché ; vous voyez une empreinte à la place. Tester la connexion le vérifie et, pour Docker Hub, indique combien de pulls il vous reste dans votre fenêtre de limite actuelle.
Les images récupérées avec votre identifiant sont mises en cache pour votre organisation uniquement, et jamais servies à une autre organisation. Les jobs issus de pull requests de forks ne peuvent pas récupérer via un registre qui exige votre identifiant. Si l’identifiant expire, les images déjà en cache continuent d’être servies et le statut affiche Refusé par le registre. Sans identifiant, un pull Docker Hub est refusé avec un message qui l’indique.
Kubernetes et OpenShift
Faites pointer un miroir vers le proxy. Pour containerd, dans /etc/containerd/certs.d/quay.io/hosts.toml :
server = "https://quay.io"
[host."https://frem.sh/v2/<org>/dependency-proxy/quay.io"]
capabilities = ["pull", "resolve"]
override_path = truePour OpenShift, avec un ImageTagMirrorSet (et un ImageDigestMirrorSet pour les digests) :
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
name: frem-sh-dependency-proxy
spec:
imageTagMirrors:
- source: quay.io
mirrors:
- frem.sh/<org>/dependency-proxy/quay.ioLe pull secret du cluster nécessite un jeton frem.sh avec read:package.
npm
.npmrc dans votre projet ou votre répertoire personnel :
registry=https://frem.sh/_app/proxy/<org>/npm/
//frem.sh/_app/proxy/<org>/npm/:_authToken=${FREMFORGE_TOKEN}Utilisez ensuite npm, pnpm ou yarn comme d’habitude. Les paquets proviennent de registry.npmjs.org, paquets
à portée (scoped) compris. Chaque tarball doit correspondre à l’integrity (sha512) que le registre npm
publie pour lui avant d’être servi.
npm audit et pnpm audit fonctionnent avec le proxy. Ils reçoivent leur réponse de la propre copie
de la base d’avis OSV de fremforge, de sorte que votre liste de dépendances n’est envoyée à aucun service d’avis
tiers. Les clients pris en charge et le format de réponse sont décrits sous
npm audit et pnpm audit via le proxy de dépendances.
Pour combiner le proxy avec les paquets que votre organisation publie dans son propre registre, dirigez votre portée vers le registre et tout le reste vers le proxy :
registry=https://frem.sh/_app/proxy/<org>/npm/
@<your-scope>:registry=https://frem.sh/api/packages/<org>/npm/
//frem.sh/_app/proxy/<org>/npm/:_authToken=${FREMFORGE_TOKEN}
//frem.sh/api/packages/<org>/npm/:_authToken=${FREMFORGE_TOKEN}PyPI
pip install --index-url "https://<user>:${FREMFORGE_TOKEN}@frem.sh/_app/proxy/<org>/pypi/simple/" requests
uv pip install --index-url "https://<user>:${FREMFORGE_TOKEN}@frem.sh/_app/proxy/<org>/pypi/simple/" requestsOu dans pip.conf / uv.toml, avec l’identifiant dans un fichier netrc ou un trousseau plutôt que dans
l’URL. L’index est servi dans les deux formats qu’utilisent les installeurs (HTML PEP 503 et JSON PEP 691), avec
le sha256, le requires-python, le statut de retrait (yank) et les métadonnées PEP 658 de chaque fichier. Chaque fichier doit
correspondre au sha256 que PyPI liste pour lui avant d’être servi.
Utilisez le proxy comme index unique. Ne l’ajoutez pas avec --extra-index-url (ou
PIP_EXTRA_INDEX_URL, UV_EXTRA_INDEX_URL) à côté d’un autre index, ni un autre index à côté de lui :
mélanger les index est ce qui rend possibles les attaques par confusion de dépendances, car l’installeur prend un
nom dans n’importe quel index qui le propose. Pour installer les paquets que votre organisation publie dans son propre registre,
lancez une installation séparée avec ce registre comme index unique et --no-deps, ou, avec uv, épinglez
chacun d’eux à ce registre par son nom (explicit = true et [tool.uv.sources]).
RPM (dnf et yum)
Chaque dépôt est accessible à l’adresse
https://frem.sh/_app/proxy/<org>/rpm/<upstream>/<repository path>Aujourd’hui, la source en amont est cdn-ubi.redhat.com, les dépôts Universal Base Image de Red Hat
(UBI 8, 9 et 10 : BaseOS, AppStream et CodeReady Builder, pour chaque architecture que Red Hat
publie), sous content/public/ubi/. Ils ne nécessitent aucun compte Red Hat. Un fichier .repo pour UBI 9
sur x86_64 :
[ubi-9-baseos-fremforge]
name=UBI 9 BaseOS through fremforge
baseurl=https://frem.sh/_app/proxy/<org>/rpm/cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/9/x86_64/baseos/os
username=<user or robot name>
password=<token with read:package>
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
[ubi-9-appstream-fremforge]
name=UBI 9 AppStream through fremforge
baseurl=https://frem.sh/_app/proxy/<org>/rpm/cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/9/x86_64/appstream/os
username=<user or robot name>
password=<token with read:package>
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-releasednf envoie username et password en authentification HTTP Basic. Utilisez un
robot de registre pour les hôtes de build et les builds d’images, et rendez
le fichier lisible uniquement par root (chmod 600), car il contient le jeton. Dans un build de conteneur,
désactivez les dépôts propres à l’image pour l’installation (dnf --disablerepo='*' --enablerepo='*-fremforge' install …), afin que rien ne soit récupéré en contournant le proxy.
Ce que fait le proxy :
repodata/repomd.xmlest revérifié auprès de la source en amont au plus toutes les 5 minutes et servi exactement tel que la source l’a publié. Un nouveaurepomd.xmln’est accepté qu’une fois que leprimary.xmlqu’il désigne a été téléchargé et correspond au sha256 et à la taille querepomd.xmlindique pour lui. D’ici là, et tant que la source en amont est en panne, le précédent est servi.- Les fichiers de métadonnées du dépôt (
primary,filelists,other,updateinfo,modules,compset leurs variantes sqlite) doivent correspondre au sha256 et à la taille indiqués dansrepomd.xml. - Les paquets doivent correspondre au sha256 et à la taille indiqués dans
primary.xml. Avec l’analyse antivirus activée, chaque paquet est aussi analysé à l’intérieur de sa charge utile compressée, et pas seulement comme fichier, et ses scripts d’installation sont analysés eux aussi. Un paquet que l’analyseur ne peut pas ouvrir est alors refusé, et non servi sans analyse. - Les signatures des paquets sont vérifiées par dnf lui-même (
gpgcheck=1), avec la clé de Red Hat, exactement comme sans le proxy. Le proxy ne modifie jamais un paquet ni les métadonnées du dépôt. - Le contenu RPM est mis en cache pour votre organisation uniquement. Une autre organisation qui récupère le même paquet récupère et stocke sa propre copie. Ainsi, le même chemin de code pourra plus tard servir du contenu Red Hat récupéré avec votre propre abonnement Red Hat, qui ne doit jamais parvenir à un autre client.
Un dépôt qui utilise des sommes de contrôle autres que sha256 n’est pas servi. La mise en proxy de cdn.redhat.com
avec votre certificat de droits Red Hat est prévue et pas encore disponible.
Maven
Maven Central est accessible à l’adresse
https://frem.sh/_app/proxy/<org>/maven/central/Faites-en le miroir de tous les dépôts dans ~/.m2/settings.xml (ou le settings.xml qu’utilise votre
build), avec l’identifiant dans un <server> de même id :
<settings>
<servers>
<server>
<id>fremforge-proxy</id>
<username><user or robot name></username>
<password>${env.FREMFORGE_TOKEN}</password>
</server>
</servers>
<mirrors>
<mirror>
<id>fremforge-proxy</id>
<name>Maven Central through fremforge</name>
<url>https://frem.sh/_app/proxy/<org>/maven/central/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>Maven envoie le nom d’utilisateur et le mot de passe en authentification HTTP Basic lorsque le proxy les
demande. Pour utiliser le proxy avec les paquets que votre organisation publie dans son propre registre, écrivez
<mirrorOf>*,!fremforge</mirrorOf> et déclarez votre registre
(https://frem.sh/api/packages/<org>/maven) comme dépôt fremforge avec son propre <server>.
Gradle (settings.gradle.kts) :
dependencyResolutionManagement {
repositories {
maven {
url = uri("https://frem.sh/_app/proxy/<org>/maven/central/")
credentials {
username = providers.environmentVariable("FREMFORGE_USER").get()
password = providers.environmentVariable("FREMFORGE_TOKEN").get()
}
}
}
}Ce que fait le proxy :
maven-metadata.xmlest revérifié auprès de Maven Central au plus toutes les 5 minutes. Une nouvelle copie n’est acceptée que si elle correspond au propre.sha1de Maven Central. D’ici là, et tant que Maven Central est en panne, la copie précédente est servie. Ses.sha1,.md5,.sha256et.sha512sont calculés à partir de la copie qui vous est servie, de sorte qu’ils lui correspondent toujours.- Les artefacts (jars, POM, fichiers
.moduleet tout autre fichier d’une version) doivent correspondre au.sha1de Maven Central et, lorsque Maven Central en publie un, à son.sha256. Un fichier sans aucune des deux sommes de contrôle n’est pas récupéré. Avec l’analyse antivirus activée, chaque fichier est analysé pendant qu’il vous est transmis. Un jar est aussi ouvert : une entrée que l’analyseur ne peut pas décompresser lui-même (zstd) est décompressée pour lui, et un jar contenant une entrée qu’aucun des deux ne peut ouvrir (par exemple LZMA) est refusé plutôt que servi sans analyse. Last-Modifiedcorrespond à l’heure à laquelle Maven Central a publié le fichier, y compris lorsqu’il provient du cache, de sorte que l’âge minimal de publication de Renovate et les autres outils qui le lisent voient la véritable date de publication. Un fichier que Maven Central a envoyé sans cet en-tête n’a aucunLast-Modified, jamais l’heure à laquelle fremforge l’a mis en cache. UnHEADsur un fichier en cache répond200avec sonContent-Lengthet ceLast-Modified.- Les fichiers de sommes de contrôle (
.sha1,.sha256, …) et les signatures (.asc) des artefacts sont transmis sans modification. Vérifiez les signatures avec le plugin PGP de votre build, comme vous le feriez sans le proxy. - Les snapshots ne sont pas servis. Maven Central n’en publie pas, et un snapshot peut changer sous
la même version. Une requête
-SNAPSHOTreçoit la réponse404, si bien que votre build passe au dépôt qui le possède.
Pour la politique de paquets, un paquet Maven est nommé groupId:artifactId. Sa date de publication est celle à laquelle
Maven Central a publié le fichier, et sa licence est la <licenses> que déclare son POM. Une licence
héritée d’un POM parent n’est pas recherchée ; elle compte donc comme non évaluée.
NuGet
La source de paquets est l’index de service du proxy :
https://frem.sh/_app/proxy/<org>/nuget/v3/index.jsonnuget.config à côté de votre solution :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="fremforge" value="https://frem.sh/_app/proxy/<org>/nuget/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<fremforge>
<add key="Username" value="<user or robot name>" />
<add key="ClearTextPassword" value="%FREMFORGE_TOKEN%" />
</fremforge>
</packageSourceCredentials>
</configuration><clear /> fait du proxy la seule source, de sorte qu’aucun paquet n’est récupéré en le contournant. NuGet développe
%FREMFORGE_TOKEN% à partir de l’environnement ; le jeton n’a donc pas besoin de figurer dans le fichier. Utilisez ensuite
dotnet restore, dotnet add package <id> --version <version> ou nuget install comme d’habitude.
Ce que fait le proxy :
- L’index de service ne liste que des ressources sur
frem.sh: le contenu des paquets (flat container) et l’enregistrement des paquets. La recherche n’est pas fournie, car la restauration et l’installation n’en ont pas besoin.dotnet add packagesans--versiona besoin de la recherche ; indiquez donc la version. - Les listes de versions et l’enregistrement sont revérifiés auprès de nuget.org au plus toutes les 5 minutes, et la dernière copie valide est servie tant que nuget.org est en panne.
- Les paquets (
.nupkg) doivent correspondre au SHA-512 et à la taille que le catalogue de nuget.org enregistre pour la version avant d’être servis. Une version dont l’entrée de catalogue ne comporte aucun hash n’est pas récupérée. Avec l’analyse antivirus activée, chaque paquet est analysé pendant qu’il vous est transmis, à l’intérieur du paquet aussi bien qu’en tant que fichier. - Les signatures des paquets sont vérifiées par le client NuGet lui-même, exactement comme sans le proxy. Le proxy ne modifie jamais un paquet.
Pour la politique de paquets, un paquet NuGet est nommé par son id en minuscules. Sa date de publication et sa
licence sont la date published de nuget.org et l’expression de licence déclarée par le paquet. Un
paquet qui déclare sa licence sous forme de fichier ou d’URL compte comme non évalué.
Modules Go
export GOPROXY=https://frem.sh/_app/proxy/<org>/go
export GOSUMDB=sum.golang.org # the default; keep it onL’authentification provient de ~/.netrc (_netrc sous Windows), que la commande go lit pour
frem.sh. Rendez le fichier lisible par vous seul (chmod 600 ~/.netrc) :
machine frem.sh
login <user or robot name>
password <token with read:package>Utilisez GOPROXY=https://frem.sh/_app/proxy/<org>/go plutôt que d’ajouter ,direct : avec direct,
un module que le proxy ne sert pas est récupéré depuis son dépôt source en contournant le proxy.
Ce que fait le proxy :
@v/listet@latestsont revérifiés auprès deproxy.golang.orgau plus toutes les 5 minutes, et la dernière copie valide est servie tant qu’il est en panne..modet.zipdoivent correspondre aux hashesh1:que la base de sommes de contrôle Go (sum.golang.org) a signés pour cette version du module. Le proxy vérifie la signature de la base avec la même clé que celle intégrée à la commande go. Une archive zip de module est décompressée et hachée de la même manière que la commande go la hache avant d’être servie. Un module que la base de sommes de contrôle ne connaît pas n’est pas servi. Avec l’analyse antivirus activée, chaque zip est analysé pendant qu’il vous est transmis.- La base de sommes de contrôle est elle aussi atteinte via le proxy. La commande go demande au proxy
s’il sert
sum.golang.org, puis récupère chaque recherche et chaque tuile par son intermédiaire. Ainsi,GOSUMDBreste activé et effectue toujours sa propre vérification complète, y compris les preuves que le proxy lui-même ne refait pas, et votre machine n’a besoin d’aucun accès direct àsum.golang.org. - Les modules privés ne sont pas servis :
proxy.golang.orgne peut pas les récupérer, et la base de sommes de contrôle ne les connaît pas. Excluez-les avecGOPRIVATE(ouGONOPROXYetGONOSUMDB), et la commande go les récupère depuis votre propre hébergement Git comme avant. - Les modules hébergés sur frem.sh ne sont jamais demandés à Google. Une requête pour un module sous
frem.sh(ou un sous-domaine) est refusée avec404avant que le proxy ne contacte qui que ce soit, car la requête elle-même révélerait le chemin du module àproxy.golang.orgetsum.golang.org. Ajoutezfrem.shàGOPRIVATEafin que la commande go récupère ces modules directement depuis frem.sh.
Ce qui parvient à Google pour les modules publics
Le proxy récupère les modules Go publics depuis le miroir de modules de Google (proxy.golang.org) et les vérifie
par rapport à la base de sommes de contrôle de Google (sum.golang.org). Lorsqu’un module ou une version n’est pas encore
en cache, Google reçoit donc :
- le chemin et la version du module récupérés (par exemple
github.com/gorilla/websocket@v1.5.0), ainsi que les recherches correspondantes dans la base de sommes de contrôle ; - des requêtes provenant des adresses de sortie de fremforge, et non de vos machines, sans le nom de votre organisation, ni utilisateur, jeton ou dépôt.
Google ne reçoit ni votre code, ni votre go.mod, ni les noms de vos dépôts, ni l’identité de
l’organisation à l’origine de la demande. Un module déjà en cache est servi sans contacter Google. Il en va
de même pour les analyseurs de sécurité : ils lisent les modules Go publics via ce proxy et ne
demandent jamais un module qui est privé selon les règles ci-dessus.
Pour la politique de paquets, un module Go est nommé par son chemin de module. Sa date de publication est celle que
proxy.golang.org enregistre pour la version. Les modules Go ne déclarent aucune licence que le proxy puisse lire ;
les règles de licence ne s’y appliquent donc pas.
Charts Helm
Les dépôts Helm classiques (un index.yaml et des archives de charts) sont servis à partir d’une liste fixe :
| Nom du dépôt | Source en amont |
|---|---|
prometheus-community | https://prometheus-community.github.io/helm-charts |
grafana | https://grafana.github.io/helm-charts |
jetstack | https://charts.jetstack.io (cert-manager) |
ingress-nginx | https://kubernetes.github.io/ingress-nginx |
Ajoutez un dépôt avec l’URL du proxy et un identifiant disposant de read:package :
helm repo add prometheus-community https://frem.sh/_app/proxy/<org>/helm/prometheus-community \
--username <user or robot name> --password-stdin <<< "$FREMFORGE_TOKEN"
helm search repo prometheus-community/prometheus
helm pull prometheus-community/prometheus --version 29.36.1
helm install my-prometheus prometheus-community/prometheus --version 29.36.1Chaque URL de chart dans l’index renvoie vers frem.sh, de sorte que Helm envoie votre identifiant avec chaque
téléchargement de chart et que --pass-credentials n’est pas nécessaire.
Ce que fait le proxy :
index.yamlest revérifié auprès du dépôt au plus toutes les 5 minutes, et la dernière copie valide est servie tant que le dépôt est en panne ou répond par autre chose qu’un index Helm. Le proxy le renvoie en JSON, que Helm lit comme du YAML.- Les charts doivent correspondre au
digest(sha256) que l’index du dépôt enregistre pour cette version avant d’être servis. Une version dont l’entrée d’index n’a pas de digest, ou dont le chart ne se trouve pas sur les hôtes propres au dépôt (par exemple une URLoci://), est exclue de l’index que vous recevez. Avec l’analyse antivirus activée, chaque chart est analysé pendant qu’il vous est transmis. - Les fichiers de provenance (
.prov) sont transmis sans modification, de sorte quehelm pull --verifyethelm install --verifyfonctionnent avec la clé publique de l’éditeur du chart, par exemple pour cert-manager :helm pull jetstack/cert-manager --version v1.21.2 --verify --keyring cert-manager-keyring.gpg. Un fichier de provenance doit nommer le chart avec le digest de l’index, sinon il n’est pas servi. Parmi les quatre dépôts, jetstack et prometheus-community publient des fichiers de provenance ; pour un chart qui n’en a pas,--verifyéchoue avecfailed to fetch provenance(404). - Les dépendances d’un chart sont résolues par Helm à partir des dépôts que nomme son
Chart.yaml. Unhelm dependency updateatteint ces dépôts directement, sauf si vous les ajoutez eux aussi via le proxy.
Le dépôt classique de Bitnami ne figure pas dans la liste : ses versions de charts actuelles sont des artefacts OCI sur
Docker Hub. Récupérez-les via le chemin des conteneurs,
oci://frem.sh/<org>/dependency-proxy/docker.io/bitnamicharts/<chart>, qui utilise l’identifiant
Docker Hub propre à votre organisation (ci-dessus).
Pour la politique de paquets, un chart est nommé par son nom de chart. Sa date de publication est la date created
dans l’index, et sa licence l’annotation artifacthub.io/license, si le chart en a une.
Cargo (crates.io)
Le proxy est un registre sparse
pour crates.io. Il nécessite Cargo 1.74 ou ultérieur. Remplacez crates-io par lui dans .cargo/config.toml,
dans votre projet ou dans ~/.cargo/config.toml pour tous les projets :
[source.crates-io]
replace-with = "fremforge"
[registries.fremforge]
index = "sparse+https://frem.sh/_app/proxy/<org>/cargo/index/"
credential-provider = "cargo:token"Cargo envoie le jeton comme en-tête Authorization complet ; donnez-lui donc le préfixe Bearer. Gardez-le
hors du fichier, dans l’environnement :
export CARGO_REGISTRIES_FREMFORGE_TOKEN="Bearer $FREMFORGE_TOKEN"
cargo fetch
cargo build --lockedAvec le remplacement de source, chaque crate de crates.io passe par le proxy, y compris les
crates qu’épingle un Cargo.lock existant, et aucune crate n’est récupérée en le contournant.
Ce que fait le proxy :
config.jsonest propre au proxy. Il renvoie les téléchargements de crates vers le chemin de votre organisation surfrem.shet indique à Cargo que le registre exige une authentification, de sorte que Cargo envoie le jeton avec chaque requête d’index et de téléchargement.- Les fichiers d’index proviennent de
index.crates.io. Ils sont revérifiés au plus toutes les 5 minutes, et la dernière copie valide est servie tant que crates.io est en panne. Chaque fichier est celui de crates.io, version pour version. Les versions retirées (yanked) y restent, marquées comme telles : Cargo utilise toujours une version que votreCargo.locképingle, et n’en choisit pas pour une nouvelle résolution. - Les crates (
.crate) proviennent destatic.crates.ioet doivent correspondre aucksum(sha256) de leur entrée d’index avant d’être servies. Une version dont l’entrée d’index n’a pas de somme de contrôle est exclue. Avec l’analyse antivirus activée, chaque crate est analysée pendant qu’elle vous est transmise, y compris à l’intérieur de l’archive. Cargo vérifie de nouveau la même somme de contrôle de son côté. - La recherche, la publication, le retrait (yank) et la gestion des propriétaires ne sont pas fournis :
cargo searchrépond404etcargo publishest refusé avec405. Publiez vos propres crates dans le registre Cargo de votre organisation.
Pour la politique de paquets, une crate est nommée par son nom tel que crates.io le publie, et sa date de
publication est le pubtime de son entrée d’index. L’index ne contient aucune licence ; les règles de licence ne s’appliquent donc pas
aux crates. Les vulnérabilités et les crates malveillantes proviennent des données crates.io d’OSV : les
avis RustSec et les enregistrements MAL-*.
Modules Terraform et OpenTofu
Le proxy sert les modules publics provenant des registres de modules et des dépôts git publics, de sorte que
tofu init et terraform init les obtiennent depuis le cache de fremforge plutôt que depuis Internet. Il
couvre :
- Les modules de registre de
registry.opentofu.orgetregistry.terraform.io, par exempleterraform-aws-modules/vpc/awsou les Azure Verified Modules (Azure/avm-*). - Les sources git sur github.com et gitlab.com à un tag ou un commit, par exemple
git::https://github.com/<owner>/<repo>.git?ref=v1.2.3ougithub.com/<owner>/<repo>?ref=v1.2.3.
Une branche est refusée : un module en cache doit rester identique ; indiquez donc un tag ou un commit. Les dépôts privés, les autres hôtes et les sources SSH ne sont pas servis.
La vérification IaC lit les modules via ce
cache pour toutes les organisations, y compris celles dont le proxy de dépendances est désactivé. La clé de cache des modules,
dont votre propre CI a besoin, ne peut pour l’instant être créée que dans les organisations internes de fremforge :
pour toute autre organisation, la section de la console n’est pas affichée et l’API répond 404.
La clé de cache des modules
OpenTofu et Terraform atteignent le cache via la clé de cache des modules de votre organisation, qui figure dans l’URL. Un propriétaire de l’organisation la crée sous Build et déploiement › Proxy de dépendances › Modules Terraform et OpenTofu. La clé n’est affichée qu’une fois, sous forme de configuration prête à coller pour OpenTofu et d’une autre pour Terraform. Ensuite, la page n’affiche que ses premiers caractères, le jour de sa dernière utilisation et un bouton Renouveler la clé de cache des modules. Après un renouvellement, l’ancienne clé continue de fonctionner pendant 24 heures, afin que les pipelines en cours se terminent ; ensuite, chaque configuration CI a besoin de la nouvelle. La création et le renouvellement d’une clé sont consignés dans le journal d’audit et parviennent à votre SIEM comme les autres événements d’audit.
La clé peut aussi être créée et renouvelée via l’API, avec un jeton disposant de policy:write :
GET /orgs/{org}/dependency-proxy/module-key affiche son préfixe et ses dates (jamais la clé), et
POST /orgs/{org}/dependency-proxy/module-key avec {"expect": "<current prefix>"} (ou "" lorsqu’il
n’y en a pas) renvoie la nouvelle clé une seule fois. Si une autre clé est devenue courante entre-temps, la réponse est
409 module-key-stale et rien ne change.
La clé permet de lire des modules publics au nom de votre organisation, et rien d’autre. Traitez-la comme un mot de passe : conservez-la dans vos secrets CI, pas dans un dépôt.
Modules de registre : aucune modification de vos sources
Faites pointer le registre d’OpenTofu vers le cache avec un
fichier de configuration CLI (~/.tofurc, ou le
fichier que désigne TF_CLI_CONFIG_FILE). Vos lignes source et version restent inchangées :
host "registry.opentofu.org" {
services = {
"modules.v1" = "https://frem.sh/_app/proxy/<org>/terraform/k/<module cache key>/registry/registry.opentofu.org/v1/modules/"
"providers.v1" = "https://registry.opentofu.org/v1/providers/"
}
}- Conservez les deux lignes. Le bloc
hostremplace tout ce qu’OpenTofu sait du registre. Sansproviders.v1, chaque installation de provider échoue avec « does not offer a OpenTofu provider registry ». - N’ajoutez pas de bloc
credentials. OpenTofu et Terraform associent les identifiants au nom d’hôte du registre ; un jeton placé dans un tel bloc serait donc aussi envoyé au registre public : avec chaque requête de provider, et avec chaque requête sur une machine où le blochostest absent. La clé de cache des modules n’a besoin d’aucun bloc d’identifiants. - Terraform : écrivez
registry.terraform.ioau lieu deregistry.opentofu.orgaux trois endroits. Nous avons vérifié cette configuration sur OpenTofu 1.13.1, avec une clé valide et avec une clé erronée (403 Forbidden). Terraform documente le même comportement pour l’hôte et les identifiants ; nous ne l’avons pas mesuré.
Pour vérifier que le cache est utilisé, exécutez TF_LOG=debug tofu init et recherchez les lignes GET https://frem.sh/_app/proxy/<org>/terraform/... pour vos modules.
Sources git
Indiquez comme source HTTPS l’archive du tag ou du commit fournie par le proxy. //* sélectionne la racine du module dans
l’archive, suivie éventuellement d’un sous-répertoire :
module "network" {
source = "https://frem.sh/_app/proxy/<org>/terraform/k/<module cache key>/git/github.com/<owner>/<repo>/v1.2.3.tar.gz//*/modules/network"
}Aucun identifiant n’est nécessaire en dehors de la clé de cache des modules dans l’URL.
Ce que fait le proxy
- Une version est épinglée lors de sa première récupération. Le proxy résout le tag en commit à partir de la
liste des refs git du dépôt lui-même (ce que lit
git ls-remote), récupère l’archive de ce commit et enregistre le commit et le SHA-256 de l’archive. Chaque requête ultérieure, de n’importe quelle organisation, obtient exactement ces octets. Une version de module de registre est épinglée au commit que désignait son tag. - Un tag déplacé ne modifie pas votre module. Le proxy revérifie les tags épinglés au plus toutes les 6 heures. Si un tag désigne désormais un autre commit, le proxy continue de servir celui qui est épinglé et enregistre que le tag en amont a été déplacé. Seul un opérateur fremforge peut réépingler un module.
- Ce contre quoi cela protège, et ce contre quoi cela ne protège pas. Les registres et les hébergeurs git ne publient aucune somme de contrôle pour les archives de modules ; la première récupération est donc considérée comme fiable. Rien de ce qui change en amont ensuite ne vous parvient : un tag redirigé ou une archive régénérée n’est pas servi. Une version qui était malveillante lors de sa première publication est servie telle quelle.
- Les archives sont vérifiées avant d’être servies. Une archive de plus de 50 Mio, qui se décompresse en
plus de 512 Mio ou 20 000 entrées, ou qui contient un chemin absolu, un chemin
.., un fichier de périphérique ou un lien pointant hors de l’archive, est refusée, et rien n’est stocké. - L’analyse antivirus s’applique aux archives de modules comme aux autres fichiers lorsque votre organisation l’a activée. OSV n’a pas d’écosystème Terraform ; aucune liste de paquets connus comme malveillants ne s’applique donc aux modules, et les règles de licence et d’âge de publication de la politique de paquets ne leur sont pas appliquées.
- Partagé, journalisé par organisation. Un module public est stocké une seule fois pour tout le monde. Les
récupérations de chaque organisation sont enregistrées dans son propre journal d’accès, avec l’acteur
module-cache-key. La clé de cache des modules elle-même n’est jamais écrite dans un journal.
Politique de paquets et paquets malveillants
La politique de paquets de votre organisation est évaluée pour les paquets npm, PyPI, RPM, Maven, NuGet, Go et Cargo et les charts Helm récupérés via le proxy, avec les mêmes règles que pour les paquets de votre registre :
- Listes d’autorisation, de refus et d’avertissement des licences, appliquées à la licence déclarée de la version.
- Vulnérabilités égales ou supérieures à votre seuil de gravité ou de CVSS, issues de la base OSV.
- Listes de refus et d’autorisation par nom de paquet et plage de versions.
- Âge minimal de publication, à partir de la date de publication de la source en amont.
- Les paquets malveillants (avis OSV
MAL-*) sont toujours vérifiés, quoi que dise la politique.
Pour les paquets RPM, la version est [epoch:]version-release, la licence est le champ License
du paquet, et l’âge de publication est le moment où le paquet est entré dans le dépôt. OSV ne dispose d’aucune
donnée sur les paquets malveillants ni sur les vulnérabilités pour les paquets RPM ; ces deux vérifications ne s’appliquent donc pas aux
RPM du proxy. Les vulnérabilités des paquets RPM sont détectées lorsque les images construites à partir d’eux
sont analysées. Il en va de même pour les charts Helm : OSV n’a pas de données
les concernant ; la licence, les listes de refus et l’âge de publication s’appliquent donc, et les images qu’un chart déploie sont
analysées là où elles sont récupérées. Une fois le refus activé, une version de chart bloquée reste dans
l’index Helm et son téléchargement est refusé avec 403.
Le refus est activé depuis le 2026-10-11. Une politique en mode enforce retire une version bloquée du
packument npm ou de l’index PyPI, de sorte que votre résolveur choisit une version autorisée, et un téléchargement direct
de cette version est refusé avec 403 en nommant la règle. Une politique en mode shadow, le mode par défaut, sert toujours
le paquet et enregistre le pull dans le journal d’accès comme would_block avec la règle qui a
correspondu. Les paquets malveillants sont refusés quel que soit le mode de votre politique, Observation et Désactivé
compris, et exclus des métadonnées de paquets que sert le proxy.
Tant que le proxy ne parvient pas à obtenir de réponse de politique de fremforge (après quelques secondes de nouvelles tentatives, et
sans réponse récente pour le même paquet sur laquelle se rabattre), il refuse le téléchargement avec
503 plutôt que de servir une version qu’il n’a pas pu vérifier contre les logiciels malveillants. Une nouvelle tentative ultérieure réussit dès
que la réponse est de nouveau disponible.
Les données d’avis sont actualisées à partir du miroir OSV de fremforge plusieurs fois par jour, et une modification de politique s’applique au pull suivant. Rien n’a besoin d’être réanalysé.
Ce qui est appliqué aujourd’hui
| Vérification | S’applique à | Aujourd’hui |
|---|---|---|
Somme de contrôle de la source en amont (digest d’image, integrity npm, sha256 PyPI, sha256 et taille de repomd.xml et primary.xml RPM, .sha1 et .sha256 Maven, SHA-512 et taille du catalogue NuGet, h1: Go signé par la base de sommes de contrôle, digest de l’index.yaml Helm, cksum de l’index Cargo) | Chaque couche, paquet et fichier de métadonnées de dépôt | Refusé en cas de non-correspondance ; rien n’est stocké |
Antivirus (ClamAV) pendant la transmission du fichier, si votre organisation a activé l’analyse antivirus (malware_scan, désactivée par défaut) | Chaque couche, fichier de paquet et chart ; charges utiles RPM décompressées ; entrées de jar, de nupkg et de zip de module que l’analyseur ne peut pas ouvrir lui-même décompressées, ou refusées | Refusé : un fichier infecté est interrompu avant son dernier octet et jamais stocké |
| Résultat d’analyse des couches, infectée ou impossible à analyser (avec l’analyse antivirus activée) | Images de conteneurs | Refusé, comme pour les images que vous poussez |
block_pull sur les vulnérabilités, si votre organisation l’a défini | Images de conteneurs | Refusé avec 403 DENIED ; voir Analyse des images |
Paquets malveillants (OSV MAL-*) dans l’image | Images de conteneurs | Refusé, comme pour les images que vous poussez ; un résultat dans l’onglet Logiciels malveillants |
Paquets malveillants (OSV MAL-*) | npm, PyPI, Maven, NuGet, Go, Cargo | Refusé avec 403, quel que soit le mode de votre politique |
| Politique de paquets : licence, vulnérabilités, liste de refus, âge de publication | npm, PyPI, Maven, NuGet, Go et Cargo (pas de licence pour Go et Cargo) | Refusé lorsque votre politique est en mode enforce ; enregistré (would_block) en mode shadow |
| Politique de paquets : licence, liste de refus, âge de publication | RPM, charts Helm | Refusé lorsque votre politique est en mode enforce ; enregistré (would_block) en mode shadow |
| Vulnérabilité connue comme exploitée avec une version corrigée (ENISA EUVD, CISA KEV) | npm, PyPI, Maven, NuGet, Go, Cargo | Refusé avec 403, quel que soit le mode de votre politique (voir ci-dessous) |
Les images en cache sont aussi analysées à la recherche de vulnérabilités et de secrets divulgués, comme les images que vous poussez ; voir Analyse des images.
Vulnérabilités connues comme exploitées
Depuis le 2026-10-13, fremforge vérifie chaque version de paquet passant par le proxy par rapport aux vulnérabilités connues pour être exploitées dans la nature : la base européenne de vulnérabilités de l’ENISA (EUVD) en premier lieu, complétée par le catalogue Known Exploited Vulnerabilities de la CISA. Une version n’est comptée que si une telle vulnérabilité l’affecte et qu’une version corrigée existe, de sorte qu’il y a toujours une version vers laquelle migrer. C’est la règle que fremforge applique déjà à ses propres images de runners.
Depuis le 31/10/2026, une telle version est refusée. Un téléchargement répond 403 avec un
message qui nomme les CVE et vous invite à mettre à niveau, et la réponse porte
x-fremforge-proxy-policy: blocked;package_policy:known_exploited. La version est aussi
retirée des métadonnées de paquet que le proxy sert, de sorte qu’une plage de versions
choisit une autre version de la plage ; seul un fichier de verrouillage ou un fichier
de build qui épingle la version concernée échoue. Le refus est enregistré dans votre journal
d’accès comme tout autre refus de politique.
C’est une règle de la plateforme, comme pour les paquets malveillants : elle s’applique quel que soit le mode de votre politique, et les exceptions de votre politique ne la lèvent pas. Le bot de mise à jour des dépendances de votre organisation voit toujours ces versions dans les métadonnées, afin de pouvoir proposer la mise à niveau. Les scanners de pull requests de fremforge les lisent aussi toujours, de sorte qu’une dépendance connue comme exploitée apparaît toujours comme un résultat au lieu de disparaître de l’analyse.
Si un build échoue à cause d’elle, passez à la version corrigée : une pull request de correctif de sécurité est peut-être déjà ouverte. Mesuré du 13/10/2026 au 31/10/2026, avant le changement, aucune organisation cliente n’a téléchargé une telle version.
Le même flux permet déjà à une version qui corrige une vulnérabilité connue comme exploitée de contourner l’âge minimal de publication de votre politique.
Stockage, plafonds et facturation
Les fichiers en cache sont comptabilisés dans le stockage de paquets de votre organisation pour leur taille totale, comme s’ils se trouvaient dans votre propre registre. Une couche de conteneur ou un fichier npm ou PyPI que plusieurs organisations récupèrent est stocké une seule fois, mais l’utilisation de chaque organisation le comptabilise. Le contenu RPM est stocké par organisation (voir RPM).
- Formules payantes : les fichiers en cache partagent un même pool de stockage de paquets avec vos propres paquets. Avec le
dépassement désactivé, le proxy peut utiliser ce que vos propres paquets laissent du pool. Lorsqu’il ne reste
plus rien, les nouvelles récupérations sont refusées avec
403(dependency proxy storage cap reached), et ce qui est déjà en cache est toujours servi. Avec le dépassement activé, le proxy n’a pas de plafond, et le stockage au-delà du pool est facturé au tarif de dépassement des paquets. - Essais : 5 Go forfaitaires de fichiers en cache.
La page Proxy de dépendances affiche votre utilisation et votre plafond. Le chiffre de vos propres paquets à partir duquel le plafond est calculé est actualisé une fois par jour.
Rétention
Un fichier en cache que votre organisation n’a pas récupéré depuis retention_days (90 par défaut, de 7 à 365)
est retiré de votre cache, avec les tags qui pointent vers lui, et cesse d’être comptabilisé dans
votre stockage. La vérification s’exécute toutes les heures. Lorsqu’aucune organisation ne référence plus un fichier, il est supprimé
du stockage de fremforge 24 heures plus tard. Le récupérer à nouveau le récupère depuis la source en amont.
Les versions de paquets encore utilisées sont conservées. Un fichier de paquet (npm, PyPI, Maven, NuGet, Go, Cargo, Helm ou RPM) n’est pas retiré, quelle que soit l’ancienneté de son dernier pull, tant que la même version du paquet est un composant actuel de l’inventaire des composants de votre organisation : dans le SBOM actuel de la branche par défaut d’un dépôt, sa dernière release, une image actuelle, un paquet de registre en ligne ou un SBOM téléversé. Une dépendance épinglée dans un fichier de verrouillage mais construite seulement deux fois par an reste donc en cache. Elle est toujours comptabilisée dans votre stockage. Dès que la version quitte tous les SBOM actuels, la règle normale s’applique de nouveau lors de la vérification horaire suivante.
Les images de base qu’utilisent vos builds actuels sont conservées. Une image de conteneur en cache n’est pas retirée, quelle que soit l’ancienneté de son dernier pull, tant que l’une des images actuelles de votre organisation est construite sur elle : chaque couche de l’image en cache est aussi une couche d’une image toujours publiée sous un tag dans le registre de votre organisation. Le manifeste de l’image, sa configuration et toutes ses couches sont conservés ensemble, de sorte qu’un pull de celle-ci continue de fonctionner, et il en va de même pour un index multiplateforme dont vous construisez sur l’image d’une plateforme. Une image qui partage seulement une couche avec vos builds (par exemple une autre image de la même distribution) n’est pas conservée par cette règle. Elle est toujours comptabilisée dans votre stockage. Dès qu’aucune image actuelle n’est construite sur elle, la règle normale s’applique de nouveau. Toutes les autres images en cache restent soumises à la règle du dernier pull. Deux cas ne sont pas reconnus et restent soumis à la règle du dernier pull : une image de base utilisée uniquement pour une plateforme autre que linux/amd64, et un build qui recompresse les couches de l’image de base au lieu de les réutiliser.
Pannes en amont
Lorsqu’un registre en amont est en panne, lent ou refuse les requêtes, les builds continuent de fonctionner pour tout ce que votre organisation a déjà récupéré :
- Les fichiers déjà récupérés (couches d’images,
.tgz, wheels,.jar,.nupkg,.zipet.modGo, charts Helm, crates) sont servis depuis le stockage de fremforge. Leur service n’attend jamais la source en amont. - Les index et tags (tags d’images, packuments npm, index PyPI,
repomd.xmlRPM,maven-metadata.xmlMaven, listes de versions et enregistrements NuGet,@v/listet@latestGo,index.yamlHelm, fichiers d’index Cargo) reçoivent une réponse tirée de la dernière copie valide. La réponse porte alorsX-Fremforge-Proxy: stale, de sorte qu’une nouvelle version publiée pendant la panne n’est pas visible tant que la source en amont n’est pas rétablie. - Les tags d’images qu’une autre organisation a mis en cache sont eux aussi servis depuis la dernière copie valide, lorsque votre organisation n’a jamais récupéré ce tag : uniquement pour les images publiques récupérées sans identifiants, et uniquement depuis le stockage partagé de fremforge, jamais à partir d’un contenu qu’une autre organisation a récupéré avec ses propres identifiants de registre. Les images Docker Hub sont toujours récupérées avec l’identifiant propre à votre organisation et ne sont pas partagées de cette façon.
- Tout ce qui n’a jamais été récupéré répond
502, car il n’y a rien à servir.
Si le service de connexion ou d’autorisation de fremforge lui-même est brièvement indisponible, les requêtes qui ont été autorisées au cours des 15 dernières minutes continuent d’être servies depuis le cache (lectures uniquement). Un jeton révoqué ou une adhésion supprimée prend néanmoins effet dès que fremforge peut le vérifier.
Ce qui survit à une panne est limité par la rétention. Un fichier que votre organisation n’a pas
récupéré depuis retention_days (90 par défaut) est retiré. Il doit ensuite être récupéré à nouveau depuis la
source en amont, ce qui est impossible tant que celle-ci est en panne. Les versions de paquets de votre
inventaire des composants, et les images de base sur lesquelles vos images actuelles sont construites, sont conservées dans tous les cas
(voir Rétention). Pour tout autre élément qui doit
survivre à une longue panne, récupérez-le au moins une fois au cours de votre période de rétention, ou augmentez
retention_days.
Journal d’accès
Chaque pull via le proxy apparaît dans le journal d’accès au registre de votre organisation avec l’origine proxy,
à l’exception de deux types de trafic CI de routine : les lectures de métadonnées autorisées d’un job CI (index de paquets et
listes de versions) ne sont plus stockées depuis le 2026-10-12, et les téléchargements d’un job CI que le proxy sert
depuis son cache sont comptés dans le recensement des pulls par jour, version,
dépôt et exécution depuis le 2026-10-13. Les téléchargements d’un job CI récupérés depuis le registre en amont, ses
refus et ses erreurs restent des événements.
Le journal enregistre le paquet, la version et le fichier, qui l’a récupéré (un utilisateur ou, pour la CI, le dépôt
du job), le résultat et toute décision de politique. Un pull via frem.sh servi depuis le cache
est servi par le proxy (200) ; celui d’un job CI est une redirection vers le stockage objet (307), sauf pour les fichiers Maven jusqu’à 1 Mio. Dans les deux cas, sa
taille est enregistrée. Une requête HEAD via frem.sh est enregistrée comme GET,
car le CDN transmet les requêtes HEAD à fremforge sous forme de GET.
Les lectures propres à l’analyse des dépendances (voir plus haut) ne passent ni par le CDN ni par le proxy de téléversement ; elles ne
figurent donc pas dans le journal d’accès, et fremforge les journalise sous forme de comptages par analyse.
Ce que voit la source en amont
fremforge contacte la source en amont que vous avez choisie, en votre nom. La source en amont reçoit l’adresse IP
de fremforge et le nom de l’image ou du paquet. Pour docker.io, les registres Red Hat, et
ghcr.io ou quay.io lorsque vous avez stocké un identifiant pour eux, elle reçoit aussi l’identifiant propre à votre
organisation, de sorte que le pull est décompté sur votre compte chez ce fournisseur.
Elle ne reçoit rien concernant vos utilisateurs. La plupart de ces registres sont exploités par des entreprises situées hors de
l’UE. Après la
première récupération, les pulls sont servis depuis le stockage européen de fremforge sans recontacter la source en amont,
sauf pour revérifier les tags, les métadonnées npm et PyPI, les repomd.xml RPM, les maven-metadata.xml Maven et les listes de versions
et l’enregistrement NuGet, les listes de versions Go, les fichiers index.yaml Helm et les fichiers d’index Cargo (au plus toutes les 5 minutes). La base de sommes de contrôle de Go est
elle aussi atteinte via le proxy, pour le compte de la commande go.
Erreurs
| Statut | Signification |
|---|---|
401 | Aucun identifiant, ou frem.sh ne l’a pas accepté. |
403 | Vous n’êtes pas membre, le proxy est désactivé pour l’organisation, l’identifiant n’a pas read:package, un jeton de job appartient à une autre organisation, le plafond de stockage de votre organisation est atteint, ou une vérification a refusé la requête (le message la nomme). |
404 | La source en amont ne l’a pas, ou l’hôte en amont n’est pas disponible via le proxy. |
405 | Une écriture. Le proxy est en lecture seule. |
429 | La limite de récupérations en amont de votre organisation a été atteinte. Réessayez après le nombre de secondes indiqué par Retry-After. |
502 | La source en amont est indisponible et rien n’est en cache pour cette requête. |
503 | Une dépendance (analyseur antivirus, vérification de politique) est indisponible ; le proxy est occupé ; ou une autre requête est encore en train de récupérer et d’analyser la même couche. Réessayez après Retry-After. |