Transitive avhengigheter
En sårbar pakke er ofte ikke en du har deklarert selv. En annen avhengighet drar den inn, og det er den avhengigheten som velger versjonen. Det går ikke an å oppgradere pakken der den er deklarert, for den er ikke deklarert noe sted i repositoryet ditt. Sikkerhetsrettelser låser i stedet en slik pakke fra roten av prosjektet ditt, med den mekanismen hvert økosystem tilbyr for nettopp dette.
| Økosystem | Hvordan pakken låses | Hvordan du ber om det |
|---|---|---|
npm (package-lock.json) | En overrides-oppføring i package.json, og pakkens oppføringer i package-lock.json flyttet til den rettede versjonen | Åpne PR med rettelse på funnet, som for alle andre. Når hostet Renovate ikke finner noe å oppgradere, låser fremforge pakken innen omtrent ti minutter |
pnpm (pnpm-lock.yaml) | En overrides-oppføring i pnpm-workspace.yaml (eller pnpm.overrides i package.json for pnpm 9 og eldre), og låsefilen flyttet tilsvarende | Som for npm |
Yarn 1 (yarn.lock) | En resolutions-oppføring i package.json, og oppføringen i yarn.lock flyttet | Som for npm. Yarn 2 og senere avvises |
PyPI (uv.lock, poetry.lock) | Pakkens låseoppføring flyttet til den rettede versjonen, uten noen låsing i pyproject.toml | Som for npm |
Maven (pom.xml) | En <dependencyManagement>-oppføring i den pom.xml-filen funnet kom fra | Åpne PR med rettelse, som for npm |
| Maven (sett i SBOM-en din) | En <dependencyManagement>-oppføring i rot-pom.xml | Fest som transitiv på funnet, eller POST /orgs/{org}/dependency-updates/security-fixes/transitive-requests |
Gradle (gradle.lockfile) | En constraints-oppføring i byggefilen, og linjen i låsefilen flyttet | Som for npm |
| Go | Ingenting ekstra: go.mod lister hver modul bygget ditt bruker, merket // indirect, og rettelsen hever den linjen | Åpne PR med rettelse |
Det er en vanlig pull request med en sikkerhetsrettelse, og den samme utgivelsesalderen gjelder: en rettet versjon som er yngre enn organisasjonens Utgivelsesalder (dager) (3 som standard), foreslås ikke ennå, med mindre den retter en kjent utnyttet sårbarhet. Siden ingen Renovate-kjøring sjekker en transitiv låsing, leser fremforge publiseringstidspunktet selv, gjennom avhengighetsproxyen din: time fra npm-registeret, opplastingstidspunktet for filene til den rettede versjonen på PyPI, og for Maven og Gradle tidspunktet Maven Central oppgir for pom-filen. En rettet versjon der publiseringstidspunktet ikke kan leses, foreslås ikke.
Den har også den samme branchen (security-fix/<package>-<version>), etiketten (security-fix), de samme grensene og den samme merge-innstillingen som alle andre, og det samme valget under Når rettelser merges gjelder. Pull requesten sier at pakken er transitiv, og hvordan den ble låst.
npm
Pull requesten endrer to filer og ingenting annet:
"overrides": {
"lodash": "4.18.0"
}Dette legges til i package.json. Hver oppføring for pakken i package-lock.json med en sårbar versjon flyttes til den rettede versjonen: versjonen og tarball-URL-en endres, og integritetshashen endres der oppføringen hadde en. URL-en beholder registeret fra låsefilen din.
fremforge kjører ikke npm install eller noe annet fra repositoryet ditt. Den skriver låseoppføringene ut fra registerets metadata, lest gjennom organisasjonens avhengighetsproxy, slik at pakkepolicyene dine også gjelder for den rettede versjonen. Den skriver dem bare når det er alt en ny oppløsning ville endre:
- Den rettede versjonen deklarerer nøyaktig de samme avhengighetene som versjonen den erstatter. Ellers avvises forespørselen med
transitive_dependencies_changed, fordi treet ville endres utover denne pakken. - Hver kopi av pakken i låsefilen har en sårbar versjon. En override flytter alle kopier, så en kopi med en annen, ikke berørt versjon gjør at forespørselen avvises med
override_conflict. package-lock.jsonharlockfileVersion2 eller 3.
npm ci godtar resultatet. Fjern overriden når pakkene som drar inn pakken, selv krever den rettede versjonen.
pnpm
pnpm registrerer også overrides i låsefilen, og avviser en låsefil der overrides:-seksjonen avviker fra konfigurasjonen. Pull requesten endrer derfor begge:
- overriden, i
pnpm-workspace.yaml(som opprettes hvis repositoryet ikke har en). Den havner i stedet ipnpm.overridesipackage.jsonnårpackageManagernavngir pnpm 9 eller eldre, eller, utenpackageManager, når prosjektet har overridene sine der og ikke har noenpnpm-workspace.yaml; pnpm-lock.yaml:overrides:-seksjonen, pakkens oppføringer underpackagesogsnapshotsmed integriteten fra registeret, og hver referanse til den gamle versjonen.
pnpm install --frozen-lockfile godtar resultatet. Bare lockfileVersion: '9.0' støttes; en pakke som er låst med et suffiks for peer-avhengigheter, som foo@1.0.0(react@18.3.1), avvises med lock_entry_unsupported.
Yarn
For Yarn 1 legger pull requesten til en resolutions-oppføring i package.json og flytter pakkens oppføring i yarn.lock: versjonen, resolved-URL-en (på registeret fra låsefilen din, med tarballens sjekksum) og integrity. yarn install --frozen-lockfile godtar resultatet.
Yarn 2 og senere (en yarn.lock med __metadata) avvises med yarn_berry_checksum. Låsefilen deres registrerer en sjekksum av arkivet Yarn bygger fra pakken, og den kan bare Yarn selv beregne. Legg til en resolutions-oppføring selv og kjør yarn install.
De samme reglene som for npm gjelder for pnpm og Yarn: den rettede versjonen må deklarere de samme avhengighetene, og hver kopi av pakken i låsefilen må ha en sårbar versjon.
Python
For uv.lock og poetry.lock flytter pull requesten pakkens låseoppføring til den rettede versjonen og legger ingenting til i pyproject.toml. En pakke som pyproject.toml deklarerer, avvises med already_declared, fordi Åpne PR med rettelse oppgraderer den der. Den nye oppføringen inneholder filene til den rettede versjonen med hashene deres, lest fra organisasjonens PyPI-avhengighetsproxy:
- uv:
sdistogwheels, med URL, hash, størrelse og opplastingstidspunkt der låsefilen din registrerer dem. URL-ene beholder indeksen fra låsefilen din: avhengighetsproxyens egen URL når du låser mot den, ellerfiles.pythonhosted.orgnår du låser mot PyPI. En låsefil fra en hvilken som helst annen indeks avvises medlock_entry_unsupported. - Poetry: versjonen, beskrivelsen,
python-versionsogfiles. Poetryscontent-hashdekker barepyproject.toml, så den endres ikke.
Regelen er den samme som for npm, brukt på Pythons metadata: den rettede versjonen må ha de samme Requires-Dist og Requires-Python som versjonen den erstatter, lest fra metadataene i wheel-filen. Ellers avvises forespørselen med transitive_dependencies_changed. uv sync --locked og poetry install godtar resultatet. Pakken blir værende på den rettede versjonen til en senere uv lock eller poetry lock løser opp avhengighetene på nytt.
Maven
Avhengighetsskanningen løser opp hver pom.xml, så en sårbar pakke som bygget ditt drar inn, er et funn på den pom.xml-filen. Åpne PR med rettelse på funnet fungerer som for npm: når hostet Renovate ikke finner noe å oppgradere, fordi pom-filen ikke navngir pakken, låser fremforge den i den pom.xml-filen innen omtrent ti minutter. En pakke som bare er sett i en SBOM du laster opp, for eksempel en fra cyclonedx-maven-plugin (se avhengighetsstier), viser i stedet Fest som transitiv i Fix-kolonnen, og låses i rot-pom.xml. Uansett legger pull requesten til:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.11</version>
</dependency>
</dependencies>
</dependencyManagement>Dette setter versjonen av pakken overalt der den forekommer i bygget. Hvis pom-filen allerede styrer den med en lavere, bokstavelig versjon, heves den versjonen der den står. Forespørselen avvises når:
- pom-filen deklarerer pakken som sin egen avhengighet (
already_declared). Åpne PR med rettelse oppgraderer den der; - den styrte versjonen leses fra en egenskap, som
${jackson.version}, som andre oppføringer også kan lese (managed_by_property); - den allerede styres med den rettede versjonen eller høyere (
already_managed).
Sjekk at avhengighetene som drar inn pakken, fungerer med den nye versjonen, for et bibliotek er vanligvis testet mot versjonen det ba om. Fjern oppføringen når de selv krever den rettede versjonen.
Gradle
For et Gradle-bygg med en låsefil (gradle.lockfile) legger pull requesten til en constraint i dependencies-blokken i byggefilen ved siden av låsefilen (build.gradle.kts eller build.gradle):
dependencies {
constraints {
implementation("org.yaml:snakeyaml:2.0") {
because("fremforge security fix: pins a transitive dependency to a version that fixes its open advisories")
}
}
}Den flytter også pakkens linje i gradle.lockfile, slik at låsefilen og bygget stemmer overens og Gradle godtar låsefilen i streng modus. Som for Maven må pom-filen til den rettede versjonen deklarere de samme avhengighetene og den samme forelderen som den den erstatter. Forespørselen avvises når:
- byggefilen allerede navngir pakken (
already_declared); - bygget verifiserer avhengigheter med
gradle/verification-metadata.xml(gradle_verification_metadata). Den nye versjonen trenger sjekksummer i den filen, og dem beregner Gradle; kjør./gradlew --write-verification-metadata sha256selv; - pakken er låst i en konfigurasjon som en
implementation-constraint ikke når, for eksempel en plugins egen classpath (gradle_configuration_unsupported); - byggefilen ikke har noen
dependencies {-blokk på toppnivå (build_file_unsupported).
fremforge kjører ikke Gradle. Et Gradle-bygg av pull requesten i CI-en din sjekker låsefilen mot bygget og feiler hvis de ikke stemmer overens.
Når ingen pull request åpnes
Forespørselen viser da årsaken. Gjennom API-et er reason lik transitive_<why>, og detail forklarer den:
| Årsak | Betydning |
|---|---|
transitive_already_declared | Pakken er en direkte avhengighet. Åpne PR med rettelse oppgraderer den der den er deklarert |
transitive_transitive_dependencies_changed | Den rettede versjonen deklarerer andre avhengigheter (for Python også en annen Requires-Python), så låsefilen trenger en full oppløsning |
transitive_override_conflict | En annen kopi av pakken, med en ikke berørt versjon, ville også blitt flyttet, eller en override, resolution eller constraint låser den allerede annerledes |
transitive_yarn_berry_checksum | Yarn 2 eller senere: låsefilen trenger en sjekksum som bare Yarn kan beregne |
transitive_gradle_verification_metadata | Gradle: bygget verifiserer avhengigheter, og den nye versjonen trenger sjekksummer som Gradle beregner |
transitive_gradle_configuration_unsupported | Gradle: pakken er låst i en konfigurasjon som en implementation-constraint ikke når |
transitive_build_file_unsupported | Gradle: byggefilen har ingen dependencies {-blokk på toppnivå |
transitive_lock_entry_unsupported | Låseoppføringen har en form fremforge ikke redigerer, for eksempel et peer-suffiks i pnpm, flere låste versjoner, eller en uv-låsefil fra en indeks den ikke betjener |
transitive_managed_by_property | Maven: den styrte versjonen kommer fra en egenskap |
transitive_already_managed | Maven: styres allerede med den rettede versjonen eller høyere |
transitive_lock_version_unsupported | npm: lockfileVersion 1. pnpm: en annen låsefilversjon enn 9.0 |
transitive_manifest_not_supported | En låsefil som ikke er oppført ovenfor, som bun.lock, pdm.lock eller Pipfile.lock |
transitive_target_metadata_missing | Avhengighetsproxyen ga ingen metadata for den rettede versjonen, for eksempel fordi en pakkepolicy avviser den |
transitive_manifest_missing, transitive_lock_missing | Manifestet eller låsefilen ligger ikke på den forventede stien på standardbranchen |
transitive_release_age_pending | Den rettede versjonen er yngre enn utgivelsesalderen din; spør igjen etter datoen som står i detail |
transitive_release_age_unknown | Avhengighetsproxyen ga ikke noe publiseringstidspunkt for den rettede versjonen |
transitive_branch_exists | Branchen security-fix/<package>-<version> finnes allerede |
transitive_repo_not_writable | Repositoryet er arkivert eller et speil |
For en forespørsel via Åpne PR med rettelse (alle økosystemer unntatt Maven) beholder forespørselen No PR: nothing to change, og detail navngir årsaken.
API
npm, pnpm, Yarn, Python og Gradle trenger ikke noe utover POST /orgs/{org}/dependency-updates/security-fixes/requests. For Maven:
curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/acme/dependency-updates/security-fixes/transitive-requests" \
-H "Authorization: Bearer $FREMFORGE_TOKEN" -H "Content-Type: application/json" \
-d '{"finding_id": "<dependency finding id>"}'Den svarer 201 med forespørselen og utfallet: pr_opened med pr_number og pr_url, eller rejected med reason og detail. En avvisning før en forespørsel finnes, er et problem av typen security-fix-<reason>, for eksempel security-fix-not-transitive. Scopet er dependency-updates:write. Forespørselen listes deretter av GET …/security-fixes/requests som alle andre.