Naar de hoofdinhoud

Dependency-proxy

De dependency-proxy is een pull-through-cache voor publieke registries, per organisatie. Je richt docker, npm, pip, uv, dnf, Maven, NuGet, go, helm of cargo op het proxypad van je organisatie op frem.sh, en fremforge haalt namens jou op uit de publieke registry:

  • De eerste pull van een imagelaag of pakketbestand wordt bij de upstream opgehaald en gecontroleerd tegen de eigen hash van de upstream. Zet je organisatie malwarescanning aan, dan wordt het bestand ook met ClamAV gescand terwijl het naar je toe streamt. Een bestand dat een controle niet doorstaat, wordt nooit geleverd en nooit opgeslagen.
  • Latere pulls worden geleverd uit de opslag van fremforge in de EU, voor elk lid van je organisatie.
  • Is de upstream onbereikbaar, dan wordt de laatste goede kopie geleverd. Tags, npm-packuments, PyPI-indexen, RPM-repomd.xml, Maven-maven-metadata.xml, versielijsten en registraties van NuGet, versielijsten en @latest van Go, Helm-index.yaml-bestanden en indexbestanden van Cargo worden beantwoord vanuit de laatste goede kopie, met de responsheader X-Fremforge-Proxy: stale. Zie Storingen bij de upstream.
  • Het pakketbeleid van je organisatie en de controles op kwaadaardige pakketten worden toegepast op pakketten en images via de proxy, en elke pull wordt vastgelegd in je registertoegangslog. Sinds 2026-10-11 wordt een bekend kwaadaardig pakket of image voor elke organisatie geweigerd, en een beleid in de modus Afdwingen weigert wat ertegen ingaat; zie Wat vandaag wordt afgedwongen.

De proxy is alleen-lezen. Je kunt er niet naar pushen.

Beschikbaarheid en inschakelen

De proxy is beschikbaar in elk abonnement en staat voor elke organisatie standaard aan. Een eigenaar van de organisatie kan hem uitzetten of de instellingen wijzigen onder Bouwen en uitrollen › Proxy voor afhankelijkheden of via de API (een token met de scope 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-proxy

Een organisatie die deze instellingen nooit heeft opgeslagen, heeft de standaard: de proxy aan, en gehoste runners die erdoorheen ophalen (zie Gehoste runners). Zodra een eigenaar ze opslaat, houdt de organisatie precies wat er is opgeslagen.

Malwarescanning (malware_scan) staat standaard uit. Staat het aan, dan wordt elke imagelaag, elk pakketbestand en elke chart die je organisatie via de proxy ophaalt met ClamAV gescand, ook als een andere organisatie het eerder zonder scan heeft gecachet: die kopie wordt één keer gescand, de eerste keer dat een organisatie die scant hem gebruikt, en het oordeel geldt daarna voor iedereen. Pakketbestanden en charts worden gescand voordat ze worden geleverd; voor imagelagen, zie Containerimages. Bekende kwaadaardige pakketten (OSV-advisories MAL-*) worden voor elke organisatie gematcht, wat deze instelling ook zegt. Dezelfde pagina en hetzelfde endpoint stellen block_until_scanned in voor containerimages, waarvoor malwarescanning aan moet staan (zie Containerimages), en retention_days (7 tot 365, standaard 90; zie Bewaartermijn). Een GET op het endpoint toont of de proxy aan staat, je gebruik en je limiet.

Authenticatie

Gebruik dezelfde inloggegevens als voor het pakketregister:

  • Mensen: een persoonlijk toegangstoken met read:package (of het kortlevende token dat fremforge auth aan je tools geeft). Je moet lid zijn van de organisatie.
  • CI: het jobtoken van Forgejo Actions. Een jobtoken haalt alleen op via de organisatie van zijn eigen repository; de proxy van elke andere organisatie weigert het. Jobs uit pull requests van forks mogen ophalen, maar nooit via een upstream die de eigen inloggegevens van je organisatie gebruikt.
  • Externe CI, buildhosts en pull secrets: een registryrobot met leestoegang. Zijn token is een read:package-credential zoals elk ander.
  • De dependency-scan van fremforge: de bereikbaarheidsanalyse leest npm-tarballs, PyPI-wheels en Maven-JAR’s via de proxy van je organisatie, via een interne route die alleen de scandienst bereikt. De licentiecontrole, de controle op de leeftijd van de release en de modulegraaf van Go lezen registrymetadata (npm, PyPI, Go, Maven Central, RubyGems en Packagist) op dezelfde manier. Dit is alleen-lezen, kan niet van buiten fremforge worden gebruikt, en krijgt je pakketbeleid, cache en opslaglimiet zoals elke andere pull.

Gehoste runners

Standaard installeren jobs op door fremforge gehoste runners via de proxy van je organisatie (runner_pull_through, standaard aan). Bij de start van elke job richt de runner npm, pip en uv op de proxy, en ook Go, Maven, NuGet en de kwetsbaarheidsdatabase van Trivy voor de ecosystemen in runner_pull_through_ecosystems (standaard alle vier). De job authenticeert met zijn eigen jobtoken, dus elke installatie doorloopt je pakketbeleid en malwarecontroles en staat in je toegangslog met de repository van de job. Is de proxy bij de start van de job niet bereikbaar, dan installeert de job in plaats daarvan uit de publieke registries via de egressproxy van fremforge, en de terugval wordt gelogd. Zet runner_pull_through op false om dit uit te zetten. Zie ook Pakketcaches.

Containerimages. Voor dezelfde jobs haalt ook de Docker-daemon van de job containerimages via de proxy van je organisatie op: docker pull, docker run, de FROM van een Dockerfile, en de job- en services:-containers die de runner start. In de workflow verandert niets; de imagenamen blijven zoals ze zijn (ghcr.io/..., quay.io/...) en elke pull wordt voor je organisatie gecachet en in je toegangslog vastgelegd.

  • Voor elke organisatie: ghcr.io, quay.io, mcr.microsoft.com, registry.k8s.io, public.ecr.aws en registry.access.redhat.com.
  • Alleen met de eigen inloggegevens van je organisatie: docker.io, registry.redhat.io en registry.connect.redhat.com gaan pas via de proxy wanneer een eigenaar de inloggegevens van je organisatie voor die registry heeft toegevoegd onder Upstream-inloggegevens. Jobs uit pull requests van forks gebruiken ze nooit, dus hun pulls uit deze registries gaan rechtstreeks naar de registry. Zonder inloggegevens zijn pulls van Docker Hub anoniem en vallen ze onder de rate limits van Docker Hub.
  • Terugval: de proxy wordt aan het begin van elke job gecontroleerd. Is hij niet bereikbaar, dan haalt de job elk image rechtstreeks uit de registry, zoals voorheen, en de terugval wordt gelogd. Een enkele pull die de proxy niet kan leveren, valt ook terug op de registry.
  • Een cache, geen poort: voor images op dit pad valt een pull die je pakketbeleid of de malwarecontrole weigert ook terug op de registry. Moet een weigering de pull tegenhouden, haal dan expliciet op uit frem.sh/<org>/dependency-proxy/<registry>/<image> (hieronder).
  • Niet gedekt: een docker buildx-builder die de driver docker-container gebruikt, draait zijn eigen BuildKit en haalt rechtstreeks op. De standaarddriver docker gaat via de proxy.

Containerimages

docker login frem.sh            # a token with read:package, as for the registry
docker pull frem.sh/<org>/dependency-proxy/<upstream>/<image>:<tag>

Bijvoorbeeld:

docker pull frem.sh/acme/dependency-proxy/quay.io/prometheus/busybox:latest

In CI:

echo "$GITHUB_TOKEN" | docker login frem.sh -u x --password-stdin

De upstreams waaruit je kunt ophalen:

UpstreamInloggegevensStatus
docker.ioDe eigen Docker Hub-inloggegevens van je organisatie, verplicht (hieronder)End-to-end geverifieerd
registry.k8s.io, mcr.microsoft.com, public.ecr.aws, registry.access.redhat.comGeenEnd-to-end geverifieerd
ghcr.io, quay.ioGeen voor publieke images. De eigen inloggegevens van je organisatie, optioneel, voor privé-images (hieronder)Publieke images: end-to-end geverifieerd. Privé-images met je inloggegevens: ondersteund, nog niet geverifieerd
registry.redhat.io, registry.connect.redhat.comHet serviceaccount van je organisatie voor de Red Hat-registry, verplichtOndersteund, nog niet geverifieerd: daarvoor is een Red Hat-account nodig, en fremforge heeft er geen om mee te testen

Elke andere host wordt geweigerd: de proxy haalt nooit een vrij opgegeven URL op.

De proxy toont de tags van een image niet. Gehoste Renovate stelt nog steeds updates voor van een image waarnaar je via dit pad verwijst, zoals een Dockerfile-FROM frem.sh/<org>/dependency-proxy/docker.io/library/python:3.14-slim. Renovate zoekt nieuwe tags en digests op bij de upstream-registry en schrijft ze in je verwijzing, die het proxypad behoudt. Je builds blijven via de proxy ophalen, dus de pull-controles hieronder blijven gelden.

Helm-charts die als OCI-artefacten op deze upstreams staan, komen via hetzelfde pad (Helm 3.8 of later):

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.1

Voor charts in een klassieke Helm-repository (index.yaml), zie Helm-charts.

Een tag wordt hoogstens één keer per minuut opnieuw bij de upstream gecontroleerd, met een HEAD-verzoek, dat Docker Hub niet meetelt voor zijn pull-limiet. Imagelagen doorlopen dezelfde pull-controles als images die naar je register zijn gepusht: met malwarescanning aan worden geïnfecteerde of onscanbare lagen geweigerd, en ook images boven je CVE-drempel als je block_pull instelt. Kwaadaardige pakketten in een image worden hieronder behandeld. Standaard wordt een image geleverd terwijl zijn lagen worden gescand. Met block_until_scanned antwoordt de eerste pull van een nog niet gescand image, of van een laag op digest, 503 met Retry-After totdat de scan klaar is, meestal binnen enkele seconden. Een laag die bij een scan geïnfecteerd bleek, wordt aan elke organisatie geweigerd.

Terwijl één verzoek een laag ophaalt en scant, wachten andere pulls van dezelfde laag daarop. Duurt dat langer dan ongeveer vier minuten, dan krijgen ze 503 met Retry-After: 30 (this layer is still being fetched and malware-scanned by another request), en een nieuwe poging wordt geleverd zodra de laag is opgeslagen. Een scan die door zijn tijd heen raakt, is geen oordeel: de laag wordt achtergehouden, zoals een onscanbare, maar er wordt geen resultaat vastgelegd. Ze wordt in de wachtrij gezet voor de laagscanner van fremforge op de achtergrond, die meer tijd heeft, en een latere pull wordt geleverd zodra die scan slaagt.

Een pakketbestand waarvoor de scantijd opraakt (npm, PyPI, RPM, Maven, NuGet, Go, Cargo of een Helm-chart), wordt op dezelfde manier behandeld: dat verzoek wordt geweigerd, er wordt geen resultaat vastgelegd en het bestand wordt in de wachtrij gezet voor dezelfde achtergrondscanner. Een later verzoek wordt geleverd zodra die scan slaagt, of geweigerd als die het bestand geïnfecteerd vindt. Een RPM-pakket blijft van je organisatie zolang het wacht: het wordt alleen in de eigen ruimte van je organisatie opgeslagen en gescand, en een andere organisatie die hetzelfde RPM-pakket ophaalt, haalt een eigen kopie op en scant die.

Groottelimieten. De proxy levert geen laag of bestand groter dan 10 GiB (403). ClamAV leest hoogstens 4 GiB van één bestand, dus met malwarescanning aan kan een grotere laag of een groter bestand niet volledig worden gescand en wordt het achtergehouden, behalve een modellaag in safetensors of GGUF die de formaatcontrole doorstaat (zie Modelscanning).

Kwaadaardige pakketten in gecachete images

De taalpakketten in elk image dat je organisatie cachet (npm-, PyPI-, Maven-, Go-, crates-, RubyGems-, NuGet-, Packagist-, Pub- en Hex-pakketten) worden gematcht tegen de OSV-advisories voor kwaadaardige pakketten (MAL-*), dezelfde controle die draait op de images die je pusht:

  • nadat het image voor het eerst is gecachet, meestal binnen de volgende scancyclus (ongeveer 15 minuten), en
  • daarna elke dag opnieuw, zodat een advisory die is gepubliceerd nadat je het image ophaalde toch wordt gevonden.

Een match is een kritieke bevinding onder Beveiliging › Bevindingen › Afhankelijkheden › Malware, vermeld als een image met de naam <org>/dependency-proxy/<upstream>/<repository> en de digest die het bevat, en ze wordt gestuurd naar de mensen die je beveiligingsmeldingen ontvangen. Afwijzen werkt zoals bij elke malwarebevinding, met een reden en een optionele einddatum. De bevinding sluit vanzelf zodra je organisatie dat image niet meer cachet, bijvoorbeeld nadat de bewaartermijn het heeft verwijderd.

Een pull van een image met een openstaande, niet-afgewezen bevinding wordt geweigerd met 403 DENIED, zoals bij gepushte images, en in je toegangslog vastgelegd als blocked met de reden image_malware. Geweigerd sinds 2026-10-11; daarvoor werd zo’n pull geleverd en vastgelegd als would_block.

Upstream-inloggegevens

Docker Hub (docker.io) en de Red Hat-registries (registry.redhat.io en registry.connect.redhat.com, de gecertificeerde partnerimages van Red Hat) worden alleen via de dependency-proxy opgehaald met het eigen account van je organisatie. Voor GitHub (ghcr.io) en Quay (quay.io) zijn inloggegevens optioneel: zonder worden ze anoniem opgehaald, wat publieke images levert; voeg ze toe om je privé-images op te halen. Een eigenaar van de organisatie voegt de inloggegevens toe onder Bouwen en uitrollen › Proxy voor afhankelijkheden › Upstream-inloggegevens, of via de API op /_app/api/v1/orgs/<org>/dependency-proxy/upstreams. Geaccepteerde vormen:

  • Docker Hub: je gebruikersnaam plus een persoonlijk toegangstoken, of een organisatietoegangstoken met de naam van de Docker-organisatie als gebruikersnaam.
  • Red Hat: een registry-serviceaccount (een gebruikersnaam zoals 1234567|ci, plus het token), of het bijbehorende OpenShift-pull secret. Voeg het één keer toe per Red Hat-registry waaruit je ophaalt; elke registry bewaart alleen zijn eigen deel van het pull secret.
  • GitHub (ghcr.io): je GitHub-gebruikersnaam plus een persoonlijk toegangstoken (classic) met read:packages.
  • Quay (quay.io): een robotaccount (organisation+robot) plus het token, of het quay.io-deel van een Red Hat-pull secret.

De Red Hat-registries met je inloggegevens, en privé-images op ghcr.io en quay.io, worden ondersteund maar zijn nog niet end-to-end geverifieerd: fremforge heeft ze getest tegen de tokenflow van de registries, maar heeft geen account om mee op te halen.

Zodra inloggegevens voor ghcr.io of quay.io zijn opgeslagen, gebruikt elke pull uit die registry ze, ook voor publieke images, en wordt alles alleen voor je organisatie gecachet. Jobs uit pull requests van forks gebruiken ze nooit: zij halen anoniem op uit die twee registries, en krijgen dus alleen publieke images.

Het secret wordt versleuteld opgeslagen en alleen door de dependency-proxy gebruikt, voor de pulls van je eigen organisatie. Het wordt nooit meer getoond; je ziet in plaats daarvan een fingerprint. Verbinding testen controleert het en toont voor Docker Hub hoeveel pulls er nog over zijn in je huidige limietvenster.

Images die met je inloggegevens zijn opgehaald, worden alleen voor je organisatie gecachet en nooit aan een andere organisatie geleverd. Jobs uit pull requests van forks kunnen niet ophalen via een registry die je inloggegevens vereist. Verlopen de inloggegevens, dan worden al gecachete images nog steeds geleverd en toont de status Geweigerd door het register. Zonder inloggegevens wordt een pull van Docker Hub geweigerd met een melding die dat zegt.

Kubernetes en OpenShift

Richt een mirror op de proxy. containerd, in /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 = true

OpenShift, met een ImageTagMirrorSet (en een ImageDigestMirrorSet voor 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.io

Het pull secret van het cluster heeft een frem.sh-token met read:package nodig.

npm

.npmrc in je project of je homedirectory:

registry=https://frem.sh/_app/proxy/<org>/npm/
//frem.sh/_app/proxy/<org>/npm/:_authToken=${FREMFORGE_TOKEN}

Gebruik daarna npm, pnpm of yarn zoals gewoonlijk. Pakketten komen van registry.npmjs.org, inclusief pakketten met een scope. Elke tarball moet overeenkomen met de integrity (sha512) die de npm-registry ervoor publiceert, voordat hij wordt geleverd.

npm audit en pnpm audit werken tegen de proxy. Ze worden beantwoord vanuit de eigen kopie van fremforge van de OSV-advisorydatabase, dus je lijst met dependencies wordt niet naar een advisorydienst van derden gestuurd. Ondersteunde clients en het antwoordformaat staan beschreven onder npm audit en pnpm audit via de dependency-proxy.

Om de proxy te combineren met pakketten die je organisatie in haar eigen register publiceert, stuur je je scope naar het register en al het andere naar de 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/" requests

Of in pip.conf / uv.toml, met de inloggegevens in een netrc-bestand of keyring in plaats van in de URL. De index wordt geleverd in beide formaten die installers gebruiken (PEP 503 HTML en PEP 691 JSON), met voor elk bestand de sha256, requires-python, de yank-status en de PEP 658-metadata. Elk bestand moet overeenkomen met de sha256 die PyPI ervoor vermeldt, voordat het wordt geleverd.

Gebruik de proxy als je enige index. Voeg hem niet toe met --extra-index-url (of PIP_EXTRA_INDEX_URL, UV_EXTRA_INDEX_URL) naast een andere index, en ook geen andere index naast hem: het mengen van indexen maakt dependency-confusion-aanvallen mogelijk, omdat de installer een naam neemt van welke index hem ook aanbiedt. Om pakketten te installeren die je organisatie in haar eigen register publiceert, voer je een aparte installatie uit met dat register als enige index en --no-deps, of pin je met uv elk van die pakketten op naam aan dat register vast (explicit = true en [tool.uv.sources]).

RPM (dnf en yum)

Elke repository is bereikbaar op

https://frem.sh/_app/proxy/<org>/rpm/<upstream>/<repository path>

Op dit moment is de upstream cdn-ubi.redhat.com, de Universal Base Image-repositories van Red Hat (UBI 8, 9 en 10: BaseOS, AppStream en CodeReady Builder, voor elke architectuur die Red Hat publiceert), onder content/public/ubi/. Daarvoor is geen Red Hat-account nodig. Een .repo-bestand voor UBI 9 op 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-release

dnf stuurt username en password als HTTP Basic-authenticatie. Gebruik een registryrobot voor buildhosts en imagebuilds, en maak het bestand alleen leesbaar voor root (chmod 600), omdat het het token bevat. Schakel in een containerbuild de eigen repositories van het image uit voor de installatie (dnf --disablerepo='*' --enablerepo='*-fremforge' install …), zodat niets buiten de proxy om wordt opgehaald.

Wat de proxy doet:

  • repodata/repomd.xml wordt hoogstens elke 5 minuten opnieuw bij de upstream gecontroleerd en precies zo geleverd als de upstream het publiceerde. Een nieuwe repomd.xml wordt pas geaccepteerd wanneer de primary.xml die erin wordt genoemd, is gedownload en overeenkomt met de sha256 en grootte die repomd.xml ervoor opgeeft. Tot dan, en zolang de upstream onbereikbaar is, wordt de vorige geleverd.
  • Bestanden met repositorymetadata (primary, filelists, other, updateinfo, modules, comps en de sqlite-varianten) moeten overeenkomen met de sha256 en grootte in repomd.xml.
  • Pakketten moeten overeenkomen met de sha256 en grootte in primary.xml. Met malwarescanning aan wordt elk pakket ook in zijn gecomprimeerde payload gescand, niet alleen als bestand, en worden ook de installatiescripts gescand. Een pakket dat de scanner niet kan openen, wordt dan geweigerd en niet ongescand geleverd.
  • Pakkethandtekeningen worden door dnf zelf gecontroleerd (gpgcheck=1), tegen de sleutel van Red Hat, precies zoals zonder de proxy. De proxy wijzigt nooit een pakket of de repositorymetadata.
  • RPM-inhoud wordt alleen voor je organisatie gecachet. Een andere organisatie die hetzelfde pakket ophaalt, haalt een eigen kopie op en slaat die op. Zo kan hetzelfde codepad later Red Hat-inhoud leveren die met je eigen Red Hat-abonnement is opgehaald, en die mag nooit bij een andere klant terechtkomen.

Een repository die checksums gebruikt met iets anders dan sha256, wordt niet geleverd. Het proxyen van cdn.redhat.com met je Red Hat-entitlementcertificaat is gepland en nog niet beschikbaar.

Maven

Maven Central is bereikbaar op

https://frem.sh/_app/proxy/<org>/maven/central/

Maak er de mirror van voor elke repository in ~/.m2/settings.xml (of de settings.xml die je build gebruikt), met de inloggegevens in een <server> met dezelfde 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 stuurt de gebruikersnaam en het wachtwoord als HTTP Basic-authenticatie wanneer de proxy erom vraagt. Om de proxy samen te gebruiken met pakketten die je organisatie in haar eigen register publiceert, schrijf je <mirrorOf>*,!fremforge</mirrorOf> en declareer je je register (https://frem.sh/api/packages/<org>/maven) als repository fremforge met een eigen <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()
            }
        }
    }
}

Wat de proxy doet:

  • maven-metadata.xml wordt hoogstens elke 5 minuten opnieuw bij Maven Central gecontroleerd. Een nieuwe kopie wordt alleen geaccepteerd als die overeenkomt met de eigen .sha1 ervan van Maven Central. Tot dan, en zolang Maven Central onbereikbaar is, wordt de vorige kopie geleverd. De .sha1, .md5, .sha256 en .sha512 ervan worden berekend uit de kopie die je krijgt, zodat ze er altijd mee overeenkomen.
  • Artefacten (jars, POM’s, .module-bestanden en elk ander bestand van een release) moeten overeenkomen met de .sha1 van Maven Central en, wanneer Maven Central er een publiceert, met de .sha256. Een bestand zonder een van beide checksums wordt niet opgehaald. Met malwarescanning aan wordt elk bestand gescand terwijl het naar je toe streamt. Een jar wordt ook geopend: een entry die de scanner zelf niet kan uitpakken (zstd), wordt ervoor uitgepakt, en een jar met een entry die geen van beide kan openen (bijvoorbeeld LZMA), wordt geweigerd in plaats van ongescand geleverd.
  • Last-Modified is het moment waarop Maven Central het bestand publiceerde, ook wanneer het uit de cache komt, zodat de minimale releaseleeftijd van Renovate en andere tools die het lezen het echte releasemoment zien. Een bestand dat Maven Central zonder deze header stuurde, krijgt helemaal geen Last-Modified, nooit het moment waarop fremforge het cachete. Een HEAD op een gecachet bestand antwoordt 200 met de Content-Length en deze Last-Modified.
  • Checksumbestanden (.sha1, .sha256, …) en handtekeningen (.asc) van artefacten worden ongewijzigd doorgegeven. Controleer handtekeningen met de PGP-plugin van je build, zoals je zonder de proxy zou doen.
  • Snapshots worden niet geleverd. Maven Central publiceert er geen, en een snapshot kan onder dezelfde versie veranderen. Een -SNAPSHOT-verzoek wordt beantwoord met 404, zodat je build doorgaat naar de repository die hem wel heeft.

Voor het pakketbeleid heet een Maven-pakket groupId:artifactId. Het releasemoment is het moment waarop Maven Central het bestand publiceerde, en de licentie is de <licenses> die de POM declareert. Een licentie die van een parent-POM wordt geërfd, wordt niet opgezocht en telt dus als niet beoordeeld.

NuGet

De pakketbron is de service-index van de proxy:

https://frem.sh/_app/proxy/<org>/nuget/v3/index.json

nuget.config naast je 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 /> maakt de proxy de enige bron, zodat geen pakket buiten de proxy om wordt opgehaald. NuGet vult %FREMFORGE_TOKEN% in vanuit de omgeving, dus het token hoeft niet in het bestand te staan. Gebruik daarna dotnet restore, dotnet add package <id> --version <version> of nuget install zoals gewoonlijk.

Wat de proxy doet:

  • De service-index vermeldt alleen resources op frem.sh: de pakketinhoud (flat container) en de pakketregistratie. Zoeken wordt niet geboden, omdat restore en install het niet nodig hebben. dotnet add package zonder --version heeft zoeken nodig, dus geef de versie op.
  • Versielijsten en registratie worden hoogstens elke 5 minuten opnieuw bij nuget.org gecontroleerd, en de laatste goede kopie wordt geleverd zolang nuget.org onbereikbaar is.
  • Pakketten (.nupkg) moeten overeenkomen met de SHA-512 en grootte die de catalog van nuget.org voor de release vastlegt, voordat ze worden geleverd. Een release waarvan de catalog-entry geen hash bevat, wordt niet opgehaald. Met malwarescanning aan wordt elk pakket gescand terwijl het naar je toe streamt, zowel de inhoud van het pakket als het bestand zelf.
  • Pakkethandtekeningen worden door de NuGet-client zelf gecontroleerd, precies zoals zonder de proxy. De proxy wijzigt nooit een pakket.

Voor het pakketbeleid heet een NuGet-pakket naar zijn id in kleine letters. Het releasemoment en de licentie zijn de published-datum van nuget.org en de gedeclareerde licentie-expressie van het pakket. Een pakket dat zijn licentie als bestand of URL declareert, telt als niet beoordeeld.

Go-modules

export GOPROXY=https://frem.sh/_app/proxy/<org>/go
export GOSUMDB=sum.golang.org      # the default; keep it on

Authenticatie komt uit ~/.netrc (_netrc op Windows), dat het go-commando leest voor frem.sh. Maak het bestand alleen voor jezelf leesbaar (chmod 600 ~/.netrc):

machine frem.sh
login <user or robot name>
password <token with read:package>

Gebruik GOPROXY=https://frem.sh/_app/proxy/<org>/go zonder ,direct toe te voegen: met direct wordt een module die de proxy niet levert buiten de proxy om uit de bronrepository opgehaald.

Wat de proxy doet:

  • @v/list en @latest worden hoogstens elke 5 minuten opnieuw bij proxy.golang.org gecontroleerd, en de laatste goede kopie wordt geleverd zolang die onbereikbaar is.
  • .mod en .zip moeten overeenkomen met de h1:-hashes die de Go-checksumdatabase (sum.golang.org) voor die moduleversie heeft ondertekend. De proxy verifieert de handtekening van de database met dezelfde sleutel die in het go-commando is ingebouwd. Een module-zip wordt uitgepakt en gehasht zoals het go-commando dat doet, voordat hij wordt geleverd. Een module die de checksumdatabase niet kent, wordt niet geleverd. Met malwarescanning aan wordt elke zip gescand terwijl hij naar je toe streamt.
  • Ook de checksumdatabase wordt via de proxy bereikt. Het go-commando vraagt de proxy of hij sum.golang.org levert, en haalt daarna elke lookup en tile via de proxy op. Zo blijft GOSUMDB aan en doet het nog steeds zijn eigen volledige verificatie, inclusief de bewijzen die de proxy zelf niet herhaalt, en je machine heeft geen directe toegang tot sum.golang.org nodig.
  • Privémodules worden niet geleverd: proxy.golang.org kan ze niet ophalen, en de checksumdatabase kent ze niet. Sluit ze uit met GOPRIVATE (of GONOPROXY en GONOSUMDB), en het go-commando haalt ze zoals voorheen op uit je eigen Git-hosting.
  • Modules die op frem.sh worden gehost, worden nooit bij Google opgevraagd. Een verzoek om een module onder frem.sh (of een subdomein) wordt met 404 geweigerd voordat de proxy iemand benadert, omdat het verzoek zelf proxy.golang.org en sum.golang.org het pad van de module zou vertellen. Zet frem.sh in GOPRIVATE, zodat het go-commando die modules rechtstreeks van frem.sh ophaalt.

Wat Google ontvangt voor publieke modules

De proxy haalt publieke Go-modules op uit de modulemirror van Google (proxy.golang.org) en controleert ze tegen de checksumdatabase van Google (sum.golang.org). Wanneer een module of versie nog niet gecachet is, ontvangt Google daarom:

  • het modulepad en de versie die worden opgehaald (bijvoorbeeld github.com/gorilla/websocket@v1.5.0), en de lookups in de checksumdatabase daarvoor;
  • verzoeken vanaf de egressadressen van fremforge, niet vanaf je machines, zonder de naam van je organisatie, gebruiker, token of repository.

Google ontvangt niet je code, je go.mod, de namen van je repositories of welke organisatie het vroeg. Een module die al gecachet is, wordt geleverd zonder Google te benaderen. Hetzelfde geldt voor de beveiligingsscanners: ze lezen publieke Go-modules via deze proxy, en vragen nooit om een module die volgens de regels hieronder privé is.

Voor het pakketbeleid heet een Go-module naar zijn modulepad. Het releasemoment is het moment dat proxy.golang.org voor de versie vastlegt. Go-modules declareren geen licentie die de proxy kan lezen, dus licentieregels gelden er niet voor.

Helm-charts

Klassieke Helm-repositories (een index.yaml en chartarchieven) worden geleverd uit een vaste lijst:

RepositorynaamUpstream
prometheus-communityhttps://prometheus-community.github.io/helm-charts
grafanahttps://grafana.github.io/helm-charts
jetstackhttps://charts.jetstack.io (cert-manager)
ingress-nginxhttps://kubernetes.github.io/ingress-nginx

Voeg een repository toe met de URL van de proxy en inloggegevens met 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.1

Elke chart-URL in de index verwijst terug naar frem.sh, dus Helm stuurt je inloggegevens mee bij elke chartdownload en --pass-credentials is niet nodig.

Wat de proxy doet:

  • index.yaml wordt hoogstens elke 5 minuten opnieuw bij de repository gecontroleerd, en de laatste goede kopie wordt geleverd zolang de repository onbereikbaar is of iets antwoordt dat geen Helm-index is. De proxy geeft hem terug als JSON, wat Helm als YAML leest.
  • Charts moeten overeenkomen met de digest (sha256) die de index van de repository voor die versie vastlegt, voordat ze worden geleverd. Een versie waarvan de indexentry geen digest heeft, of waarvan de chart niet op de eigen hosts van de repository staat (bijvoorbeeld een oci://-URL), wordt weggelaten uit de index die je krijgt. Met malwarescanning aan wordt elke chart gescand terwijl hij naar je toe streamt.
  • Provenance-bestanden (.prov) worden ongewijzigd doorgegeven, zodat helm pull --verify en helm install --verify werken met de publieke sleutel van de uitgever van de chart, bijvoorbeeld voor cert-manager: helm pull jetstack/cert-manager --version v1.21.2 --verify --keyring cert-manager-keyring.gpg. Een provenance-bestand moet de chart noemen met de digest uit de index, anders wordt het niet geleverd. Van de vier repositories publiceren jetstack en prometheus-community provenance-bestanden; voor een chart zonder zo’n bestand mislukt --verify met failed to fetch provenance (404).
  • De dependencies van een chart worden door Helm opgelost uit de repositories die de Chart.yaml noemt. Een helm dependency update bereikt die repositories rechtstreeks, tenzij je ze ook via de proxy toevoegt.

De klassieke repository van Bitnami staat niet op de lijst: de huidige chartversies daarvan zijn OCI-artefacten op Docker Hub. Haal ze op via het containerpad, oci://frem.sh/<org>/dependency-proxy/docker.io/bitnamicharts/<chart>, dat de eigen Docker Hub-inloggegevens van je organisatie gebruikt (hierboven).

Voor het pakketbeleid heet een chart naar zijn chartnaam. Het releasemoment is de created-datum in de index, en de licentie de annotatie artifacthub.io/license, als de chart die heeft.

Cargo (crates.io)

De proxy is een sparse registry voor crates.io. Hij vereist Cargo 1.74 of later. Vervang crates-io erdoor in .cargo/config.toml, in je project, of in ~/.cargo/config.toml voor elk project:

[source.crates-io]
replace-with = "fremforge"

[registries.fremforge]
index = "sparse+https://frem.sh/_app/proxy/<org>/cargo/index/"
credential-provider = "cargo:token"

Cargo stuurt het token als de volledige Authorization-header, dus geef het het voorvoegsel Bearer. Houd het buiten het bestand, in de omgeving:

export CARGO_REGISTRIES_FREMFORGE_TOKEN="Bearer $FREMFORGE_TOKEN"
cargo fetch
cargo build --locked

Met de bronvervanging komt elke crate van crates.io via de proxy, inclusief de crates die een bestaande Cargo.lock vastpint, en wordt geen crate buiten de proxy om opgehaald.

Wat de proxy doet:

  • config.json is van de proxy zelf. Het verwijst crate-downloads terug naar het pad van je organisatie op frem.sh en vertelt Cargo dat de registry authenticatie vereist, zodat Cargo het token meestuurt bij elk index- en downloadverzoek.
  • Indexbestanden komen van index.crates.io. Ze worden hoogstens elke 5 minuten opnieuw gecontroleerd, en de laatste goede kopie wordt geleverd zolang crates.io onbereikbaar is. Elk bestand is dat van crates.io zelf, versie voor versie. Ge-yankte versies blijven erin staan, gemarkeerd als yanked: Cargo gebruikt er nog een die je Cargo.lock vastpint, en kiest er geen voor een nieuwe resolutie.
  • Crates (.crate) komen van static.crates.io en moeten overeenkomen met de cksum (sha256) in hun indexentry, voordat ze worden geleverd. Een versie waarvan de indexentry geen checksum heeft, wordt weggelaten. Met malwarescanning aan wordt elke crate gescand terwijl hij naar je toe streamt, ook de inhoud van het archief. Cargo controleert dezelfde checksum aan zijn kant nog eens.
  • Zoeken, publiceren, yanken en eigenaren worden niet geboden: cargo search antwoordt 404 en cargo publish wordt geweigerd met 405. Publiceer je eigen crates in het Cargo-register van je organisatie.

Voor het pakketbeleid heet een crate naar zijn naam zoals crates.io die publiceert, en het releasemoment is de pubtime in de indexentry. De index bevat geen licentie, dus licentieregels gelden niet voor crates. Kwetsbaarheden en kwaadaardige crates komen uit de crates.io-gegevens van OSV: de RustSec-advisories en de MAL-*-records.

Terraform- en OpenTofu-modules

De proxy levert publieke modules uit de moduleregistries en uit publieke git-repositories, zodat tofu init en terraform init ze uit de cache van fremforge halen in plaats van van het internet. Hij dekt:

  • Registrymodules van registry.opentofu.org en registry.terraform.io, bijvoorbeeld terraform-aws-modules/vpc/aws of de Azure Verified Modules (Azure/avm-*).
  • Git-bronnen op github.com en gitlab.com op een tag of een commit, bijvoorbeeld git::https://github.com/<owner>/<repo>.git?ref=v1.2.3 of github.com/<owner>/<repo>?ref=v1.2.3.

Een branch wordt geweigerd: een gecachete module moet hetzelfde blijven, dus noem een tag of een commit. Privé-repositories, andere hosts en SSH-bronnen worden niet geleverd.

De IaC-controle leest modules via deze cache voor elke organisatie, ook voor een organisatie waarvan de dependency-proxy uit staat. De modulecachesleutel, die je eigen CI nodig heeft, kan voorlopig alleen worden aangemaakt in de interne organisaties van fremforge: voor elke andere organisatie wordt het consolegedeelte niet getoond en antwoordt de API 404.

De modulecachesleutel

OpenTofu en Terraform bereiken de cache via de modulecachesleutel van je organisatie, die in de URL staat. Een eigenaar van de organisatie maakt hem aan onder Bouwen en uitrollen › Proxy voor afhankelijkheden › Terraform- en OpenTofu-modules. De sleutel wordt één keer getoond, als kant-en-klare configuratie voor OpenTofu en een voor Terraform. Daarna toont de pagina alleen de eerste tekens, de dag waarop hij voor het laatst is gebruikt, en een knop Roteren. Na een rotatie blijft de vorige sleutel 24 uur werken, zodat lopende pipelines kunnen afronden; daarna heeft elke CI-configuratie de nieuwe nodig. Het aanmaken en roteren van een sleutel wordt vastgelegd in het auditlog en komt net als andere auditgebeurtenissen in je SIEM terecht.

De sleutel kan ook via de API worden aangemaakt en geroteerd, met een token dat policy:write heeft: GET /orgs/{org}/dependency-proxy/module-key toont het voorvoegsel en de datums (nooit de sleutel), en POST /orgs/{org}/dependency-proxy/module-key met {"expect": "<current prefix>"} (of "" als er geen is) geeft de nieuwe sleutel één keer terug. Is er intussen een andere sleutel actief geworden, dan is het antwoord 409 module-key-stale en verandert er niets.

Met de sleutel kun je publieke modules lezen als je organisatie, en verder niets. Behandel hem als een wachtwoord: bewaar hem in je CI-secrets, niet in een repository.

Registrymodules: geen wijziging aan je bronnen

Richt de registry van OpenTofu op de cache met een CLI-configuratiebestand (~/.tofurc, of het bestand dat TF_CLI_CONFIG_FILE noemt). Je source- en version-regels blijven zoals ze zijn:

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/"
  }
}
  • Houd beide regels. Het host-blok vervangt alles wat OpenTofu over de registry weet. Zonder providers.v1 mislukt elke providerinstallatie met “does not offer a OpenTofu provider registry”.
  • Voeg geen credentials-blok toe. OpenTofu en Terraform koppelen inloggegevens aan de hostnaam van de registry, dus een token daarin zou ook naar de publieke registry worden gestuurd: bij elk providerverzoek, en bij elk verzoek op een machine waar het host-blok ontbreekt. De modulecachesleutel heeft geen credentials-blok nodig.
  • Terraform: schrijf registry.terraform.io in plaats van registry.opentofu.org op alle drie de plekken. We hebben deze configuratie geverifieerd op OpenTofu 1.13.1, met een sleutel en met een verkeerde (403 Forbidden). Terraform documenteert hetzelfde gedrag voor host en inloggegevens; dat hebben we niet gemeten.

Om te controleren dat de cache wordt gebruikt, voer je TF_LOG=debug tofu init uit en zoek je naar regels GET https://frem.sh/_app/proxy/<org>/terraform/... voor je modules.

Git-bronnen

Geef het archief van de proxy voor de tag of commit op als HTTPS-bron. //* selecteert de moduleroot in het archief, en een subdirectory volgt daarna:

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"
}

Naast de modulecachesleutel in de URL zijn geen inloggegevens nodig.

Wat de proxy doet

  • Een versie wordt bij de eerste fetch vastgepind. De proxy zet de tag om naar een commit uit de eigen lijst met git-refs van de repository (wat git ls-remote leest), haalt het archief van die commit op, en legt de commit en de SHA-256 van het archief vast. Elk later verzoek, van welke organisatie ook, krijgt precies die bytes. Een versie van een registrymodule wordt vastgepind op de commit die de tag noemde.
  • Een verplaatste tag verandert je module niet. De proxy controleert vastgepinde tags hoogstens elke 6 uur opnieuw. Noemt een tag nu een andere commit, dan blijft de proxy de vastgepinde leveren en legt hij vast dat de upstream-tag is verplaatst. Alleen een operator van fremforge kan een module opnieuw vastpinnen.
  • Waartegen dit beschermt, en waartegen niet. Registries en git-hosts publiceren geen checksum voor modulearchieven, dus de eerste fetch wordt vertrouwd. Niets wat daarna upstream verandert, bereikt jou: een omgezette tag of een opnieuw gegenereerd archief wordt niet geleverd. Een versie die kwaadaardig was toen hij voor het eerst werd gepubliceerd, wordt geleverd zoals hij was.
  • Archieven worden gecontroleerd voordat ze worden geleverd. Een archief groter dan 50 MiB, dat uitpakt tot meer dan 512 MiB of 20.000 entries, of dat een absoluut pad, een ..-pad, een devicebestand of een link naar buiten het archief bevat, wordt geweigerd, en er wordt niets opgeslagen.
  • Malwarescanning geldt voor modulearchieven zoals voor andere bestanden wanneer je organisatie het aan heeft staan. OSV heeft geen Terraform-ecosysteem, dus er geldt geen lijst met bekende kwaadaardige modules, en de licentie- en releaseleeftijdsregels van het pakketbeleid worden er niet op toegepast.
  • Gedeeld, per organisatie gelogd. Een publieke module wordt één keer voor iedereen opgeslagen. De fetches van elke organisatie worden in haar eigen toegangslog vastgelegd, met als actor module-cache-key. De modulecachesleutel zelf wordt nooit naar een log geschreven.

Pakketbeleid en kwaadaardige pakketten

Het pakketbeleid van je organisatie wordt toegepast op npm-, PyPI-, RPM-, Maven-, NuGet-, Go- en Cargo-pakketten en Helm-charts die via de proxy worden opgehaald, met dezelfde regels als voor pakketten in je register:

  • Licentie-lijsten voor toestaan, weigeren en waarschuwen, toegepast op de gedeclareerde licentie van de versie.
  • Kwetsbaarheden op of boven je drempel voor ernst of CVSS, uit de OSV-database.
  • Weiger- en toestaanlijsten op pakketnaam en versiebereik.
  • Minimale releaseleeftijd, vanaf het publicatiemoment bij de upstream.
  • Kwaadaardige pakketten (OSV-advisories MAL-*) worden altijd gecontroleerd, wat het beleid ook zegt.

Voor RPM-pakketten is de versie [epoch:]version-release, de licentie het veld License van het pakket, en de releaseleeftijd het moment waarop het pakket in de repository kwam. OSV heeft geen gegevens over kwaadaardige pakketten of kwetsbaarheden voor RPM-pakketten, dus die twee controles gelden niet voor RPM’s in de proxy. Kwetsbaarheden in RPM-pakketten worden gevonden wanneer de images die ermee zijn gebouwd worden gescand. Hetzelfde geldt voor Helm-charts: OSV heeft geen gegevens voor charts, dus licentie, weigerlijsten en releaseleeftijd gelden, en de images die een chart uitrolt, worden gescand waar ze worden opgehaald. Zodra weigeren aan staat, blijft een geblokkeerde chartversie in de Helm-index staan en wordt de download ervan geweigerd met 403.

Weigeren staat aan sinds 2026-10-11. Een beleid in de modus Afdwingen haalt een geblokkeerde versie uit het npm-packument of de PyPI-index, zodat je resolver een toegestane versie kiest, en een directe download ervan wordt geweigerd met 403 met de naam van de regel. Een beleid in de modus Schaduw, de standaard, levert het pakket nog steeds en legt de pull in het toegangslog vast als would_block met de regel die matchte. Kwaadaardige pakketten worden geweigerd, wat de modus van je beleid ook is, Schaduw en Uit inbegrepen, en weggelaten uit de pakketmetadata die de proxy levert.

Zolang de proxy geen antwoord over het beleid van fremforge kan krijgen (na een paar seconden opnieuw proberen, en zonder recent antwoord voor hetzelfde pakket om op terug te vallen), weigert hij de download met 503 in plaats van een versie te leveren die hij niet op malware kon controleren. Later opnieuw proberen lukt zodra het antwoord er weer is.

Advisorygegevens worden meerdere keren per dag vernieuwd uit de OSV-mirror van fremforge, en een beleidswijziging geldt vanaf de volgende pull. Er hoeft niets opnieuw te worden gescand.

Wat vandaag wordt afgedwongen

ControleGeldt voorVandaag
Checksum van de upstream (imagedigest, npm-integrity, PyPI-sha256, sha256 en grootte van RPM-repomd.xml en primary.xml, Maven-.sha1 en .sha256, SHA-512 en grootte uit de NuGet-catalog, Go-h1: ondertekend door de checksumdatabase, Helm-index.yaml-digest, Cargo-index-cksum)Elke laag, elk pakket en elk bestand met repositorymetadataGeweigerd bij een afwijking; er wordt niets opgeslagen
Antivirus (ClamAV) terwijl het bestand naar je toe streamt, als je organisatie malwarescanning heeft aangezet (malware_scan, standaard uit)Elke laag, elk pakketbestand en elke chart; RPM-payloads uitgepakt; entries in jar, nupkg en module-zip die de scanner zelf niet kan openen, uitgepakt of geweigerdGeweigerd: een geïnfecteerd bestand wordt vóór de laatste byte afgebroken en nooit opgeslagen
Scanresultaat van een laag, geïnfecteerd of onscanbaar (met malwarescanning aan)ContainerimagesGeweigerd, zoals bij images die je pusht
Kwetsbaarheden-block_pull, als je organisatie het heeft ingesteldContainerimagesGeweigerd met 403 DENIED; zie Imagescanning
Kwaadaardige pakketten (OSV MAL-*) in het imageContainerimagesGeweigerd, zoals bij images die je pusht; een bevinding op het tabblad Malware
Kwaadaardige pakketten (OSV MAL-*)npm, PyPI, Maven, NuGet, Go, CargoGeweigerd met 403, wat de modus van je beleid ook is
Pakketbeleid: licentie, kwetsbaarheden, weigerlijst, releaseleeftijdnpm, PyPI, Maven, NuGet, Go en Cargo (geen licentie voor Go en Cargo)Geweigerd wanneer je beleid in de modus Afdwingen staat; vastgelegd (would_block) in de modus Schaduw
Pakketbeleid: licentie, weigerlijst, releaseleeftijdRPM, Helm-chartsGeweigerd wanneer je beleid in de modus Afdwingen staat; vastgelegd (would_block) in de modus Schaduw
Bekend misbruikte kwetsbaarheid met een gerepareerde versie (ENISA EUVD, CISA KEV)npm, PyPI, Maven, NuGet, Go, CargoGeweigerd met 403, wat de modus van je beleid ook is (zie hieronder)

Gecachete images worden ook op kwetsbaarheden en gelekte secrets gescand, net als de images die je pusht; zie Imagescanning.

Bekend misbruikte kwetsbaarheden

Sinds 2026-10-13 controleert fremforge elke pakketversie via de proxy tegen de kwetsbaarheden waarvan bekend is dat ze actief worden misbruikt: eerst de EU Vulnerability Database (EUVD) van ENISA, met daarbovenop de Known Exploited Vulnerabilities-catalogus van CISA. Een versie telt alleen mee wanneer zo’n kwetsbaarheid haar treft en er een gerepareerde versie bestaat, zodat er altijd een versie is om naar over te stappen. Dit is de regel die fremforge al op zijn eigen runner-images toepast.

Sinds 31-10-2026 wordt zo’n versie geweigerd. Een download antwoordt 403 met een melding die de CVE’s noemt en je vraagt te upgraden, en het antwoord draagt x-fremforge-proxy-policy: blocked;package_policy:known_exploited. De versie wordt ook weggelaten uit de pakketmetadata die de proxy serveert, zodat een versiebereik een andere versie in het bereik kiest; alleen een lockbestand of buildbestand dat de getroffen versie vastpint, faalt. De weigering wordt zoals elke andere beleidsweigering vastgelegd in je toegangslog.

Dit is een platformregel, net als bij kwaadaardige pakketten: hij geldt ongeacht de modus van je beleid, en de uitzonderingen van je beleid heffen hem niet op. De bot voor afhankelijkheidsupdates van je organisatie ziet deze versies nog steeds in de metadata, zodat hij de upgrade kan voorstellen. De pull-request-scanners van fremforge lezen ze ook nog steeds, zodat een bekend misbruikte afhankelijkheid als bevinding blijft verschijnen in plaats van uit de scan te verdwijnen.

Als een build erop faalt, stap over op de gerepareerde versie: een pull request met een beveiligingsfix staat misschien al open. Gemeten van 13-10-2026 tot 31-10-2026, vóór de omschakeling, heeft geen klantorganisatie zo’n versie gedownload.

Dezelfde feed laat een versie die een bekend misbruikte kwetsbaarheid repareert al de minimale releaseleeftijd van je beleid overslaan.

Opslag, limieten en facturatie

Gecachete bestanden tellen met hun volledige grootte mee voor de pakketopslag van je organisatie, alsof ze in je eigen register stonden. Een containerlaag of npm- of PyPI-bestand dat door meerdere organisaties wordt opgehaald, wordt één keer opgeslagen, maar telt mee voor het gebruik van elke organisatie. RPM-inhoud wordt per organisatie opgeslagen (zie RPM).

  • Betaalde abonnementen: gecachete bestanden delen één opslagpool voor pakketten met je eigen pakketten. Met overschrijding uit mag de proxy gebruiken wat je eigen pakketten van de pool overlaten. Is er niets meer over, dan worden nieuwe fetches geweigerd met 403 (dependency proxy storage cap reached), en wat al gecachet is, wordt nog steeds geleverd. Met overschrijding aan is er geen proxylimiet, en opslag boven de pool wordt gefactureerd tegen het overschrijdingstarief voor pakketten.
  • Proefperiodes: een vaste 5 GB aan gecachete bestanden.

De pagina Proxy voor afhankelijkheden toont je gebruik en je limiet. Het cijfer voor je eigen pakketten waarop de limiet wordt gebaseerd, wordt één keer per dag vernieuwd.

Bewaartermijn

Een gecachet bestand dat je organisatie gedurende retention_days (standaard 90, van 7 tot 365) niet heeft opgehaald, wordt uit je cache verwijderd, samen met de tags die ernaar verwijzen, en telt niet meer mee voor je opslag. De controle draait elk uur. Zodra geen enkele organisatie meer naar een bestand verwijst, wordt het 24 uur later uit de opslag van fremforge verwijderd. Opnieuw ophalen haalt het weer bij de upstream op.

Pakketversies die nog in gebruik zijn, blijven bewaard. Een pakketbestand (npm, PyPI, Maven, NuGet, Go, Cargo, Helm of RPM) wordt niet verwijderd, hoe lang geleden het ook voor het laatst is opgehaald, zolang dezelfde pakketversie een actuele component is in de componenteninventaris van je organisatie: in de actuele SBOM van de standaardbranch van een repository, de laatste release ervan, een actueel image, een live registerpakket of een geüploade SBOM. Een dependency die in een lockfile is vastgepind maar maar twee keer per jaar wordt gebouwd, blijft daardoor gecachet. Ze telt nog steeds mee voor je opslag. Zodra de versie uit elke actuele SBOM verdwijnt, geldt bij de volgende controle per uur weer de normale regel.

Basisimages die je huidige builds gebruiken, blijven bewaard. Een gecachet containerimage wordt niet verwijderd, hoe lang geleden het ook voor het laatst is opgehaald, zolang een van de huidige images van je organisatie erop is gebouwd: elke laag van het gecachete image is ook een laag van een image dat nog onder een tag in het register van je organisatie is gepubliceerd. Het manifest van het image, de configuratie en alle lagen blijven samen bewaard, zodat een pull ervan blijft werken, en dat geldt ook voor een multi-platformindex waarvan je op een platformimage bouwt. Een image dat alleen een laag deelt met je builds (bijvoorbeeld een ander image op dezelfde distributie), wordt door deze regel niet bewaard. Het telt nog steeds mee voor je opslag. Zodra er geen huidig image meer op is gebouwd, geldt weer de normale regel. Elk ander gecachet image houdt de regel van de laatste pull. Twee gevallen worden niet herkend en houden de regel van de laatste pull: een basisimage dat alleen wordt gebruikt voor een ander platform dan linux/amd64, en een build die de lagen van het basisimage opnieuw comprimeert in plaats van ze te hergebruiken.

Storingen bij de upstream

Wanneer een upstream-registry onbereikbaar of traag is of weigert, blijven builds werken voor alles wat je organisatie eerder heeft opgehaald:

  • Bestanden die je eerder hebt opgehaald (imagelagen, .tgz, wheels, .jar, .nupkg, Go-.zip en .mod, Helm-charts, crates) worden geleverd uit de opslag van fremforge. Het leveren ervan wacht nooit op de upstream.
  • Indexen en tags (imagetags, npm-packuments, PyPI-indexen, RPM-repomd.xml, Maven- maven-metadata.xml, versielijsten en registraties van NuGet, Go-@v/list en @latest, Helm-index.yaml, indexbestanden van Cargo) worden beantwoord vanuit de laatste goede kopie. Het antwoord bevat dan X-Fremforge-Proxy: stale, dus een nieuwe release die tijdens de storing is gepubliceerd, is pas zichtbaar wanneer de upstream terug is.
  • Imagetags die een andere organisatie heeft gecachet, worden ook vanuit de laatste goede kopie geleverd wanneer je organisatie die tag nooit heeft opgehaald: alleen voor publieke images die zonder inloggegevens zijn opgehaald, en alleen uit de gedeelde opslag van fremforge, nooit uit inhoud die een andere organisatie met haar eigen registry-inloggegevens heeft opgehaald. Docker Hub-images worden altijd met de eigen inloggegevens van je organisatie opgehaald en worden niet op deze manier gedeeld.
  • Alles wat nooit eerder is opgehaald, antwoordt 502, omdat er niets te leveren is.

Is de eigen aanmeld- of autorisatiedienst van fremforge kort niet beschikbaar, dan blijven verzoeken die in de laatste 15 minuten zijn toegestaan uit de cache geleverd (alleen lezen). Een ingetrokken token of een verwijderd lidmaatschap gaat nog steeds in zodra fremforge het kan controleren.

Wat een storing overleeft, wordt begrensd door de bewaartermijn. Een bestand dat je organisatie gedurende retention_days (standaard 90) niet heeft opgehaald, wordt verwijderd. Daarna moet het opnieuw bij de upstream worden opgehaald, wat niet kan zolang de upstream onbereikbaar is. Pakketversies in je componenteninventaris, en de basisimages waarop je huidige images zijn gebouwd, blijven hoe dan ook bewaard (zie Bewaartermijn). Voor al het andere dat een lange storing moet overleven: haal het minstens één keer binnen je bewaartermijn op, of verhoog retention_days.

Toegangslog

Elke pull via de proxy verschijnt in het registertoegangslog van je organisatie met herkomst proxy, behalve twee soorten routinematig CI-verkeer: de toegestane metadataleesacties van een CI-job (pakketindexen en versielijsten) worden sinds 2026-10-12 niet opgeslagen, en de downloads van een CI-job die de proxy uit zijn cache levert, worden sinds 2026-10-13 per dag, versie, repository en run geteld in de pull-telling. De downloads van een CI-job die bij de upstream-registry worden opgehaald, de weigeringen en de fouten zijn nog steeds gebeurtenissen. Het log legt het pakket, de versie en het bestand vast, wie het ophaalde (een gebruiker, of voor CI de repository van de job), de uitkomst en een eventuele beleidsbeslissing. Een pull via frem.sh die uit de cache wordt geleverd, wordt door de proxy geleverd (200); die van een CI-job is een redirect naar objectopslag (307), behalve voor Maven-bestanden tot 1 MiB. Hoe dan ook wordt de grootte vastgelegd. Een HEAD-verzoek via frem.sh wordt vastgelegd als GET, omdat het CDN HEAD-verzoeken als GET naar fremforge doorstuurt. De eigen leesacties van de dependency-scan (hierboven) gaan niet via het CDN of de uploadproxy, dus ze staan niet in het toegangslog; fremforge logt ze als aantallen per scan.

Wat de upstream ziet

fremforge benadert namens jou de upstream die je hebt gekozen. De upstream ontvangt het IP-adres van fremforge en de naam van het image of pakket. Voor docker.io, de Red Hat-registries, en ghcr.io of quay.io wanneer je er inloggegevens voor hebt opgeslagen, ontvangt hij ook de eigen inloggegevens van je organisatie, zodat de pull daar meetelt voor je account. Hij ontvangt niets over je gebruikers. De meeste van deze registries worden beheerd door bedrijven buiten de EU. Na de eerste fetch worden pulls geleverd uit de EU-opslag van fremforge zonder de upstream opnieuw te benaderen, behalve om tags, npm- en PyPI-metadata, RPM-repomd.xml, Maven-maven-metadata.xml en versielijsten en registratie van NuGet, versielijsten van Go, Helm-index.yaml-bestanden en indexbestanden van Cargo opnieuw te controleren (hoogstens elke 5 minuten). De checksumdatabase van Go wordt ook via de proxy bereikt, namens het go-commando.

Fouten

StatusBetekenis
401Geen inloggegevens, of frem.sh accepteerde ze niet.
403Geen lid, de proxy staat uit voor de organisatie, de inloggegevens missen read:package, een jobtoken voor een andere organisatie, de opslaglimiet van je organisatie is bereikt, of een weigering door een controle (de melding noemt die).
404De upstream heeft het niet, of de upstream-host is niet beschikbaar via de proxy.
405Een schrijfactie. De proxy is alleen-lezen.
429De limiet voor upstream-fetches van je organisatie is bereikt. Probeer het opnieuw na het aantal seconden in Retry-After.
502De upstream is niet beschikbaar en er is niets gecachet voor dit verzoek.
503Een afhankelijke dienst (malwarescanner, beleidscontrole) is niet beschikbaar; de proxy is bezet; of een ander verzoek is nog bezig met het ophalen en scannen van dezelfde laag. Probeer het opnieuw na Retry-After.