Gå til hovedinnhold

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.

ØkosystemHvordan pakken låsesHvordan 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 tilsvarendeSom for npm
Yarn 1 (yarn.lock)En resolutions-oppføring i package.json, og oppføringen i yarn.lock flyttetSom 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.tomlSom 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.xmlFest 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 flyttetSom for npm
GoIngenting 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.json har lockfileVersion 2 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 i pnpm.overrides i package.json når packageManager navngir pnpm 9 eller eldre, eller, uten packageManager, når prosjektet har overridene sine der og ikke har noen pnpm-workspace.yaml;
  • pnpm-lock.yaml: overrides:-seksjonen, pakkens oppføringer under packages og snapshots med 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: sdist og wheels, 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, eller files.pythonhosted.org når du låser mot PyPI. En låsefil fra en hvilken som helst annen indeks avvises med lock_entry_unsupported.
  • Poetry: versjonen, beskrivelsen, python-versions og files. Poetrys content-hash dekker bare pyproject.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 sha256 selv;
  • 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:

ÅrsakBetydning
transitive_already_declaredPakken er en direkte avhengighet. Åpne PR med rettelse oppgraderer den der den er deklarert
transitive_transitive_dependencies_changedDen rettede versjonen deklarerer andre avhengigheter (for Python også en annen Requires-Python), så låsefilen trenger en full oppløsning
transitive_override_conflictEn 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_checksumYarn 2 eller senere: låsefilen trenger en sjekksum som bare Yarn kan beregne
transitive_gradle_verification_metadataGradle: bygget verifiserer avhengigheter, og den nye versjonen trenger sjekksummer som Gradle beregner
transitive_gradle_configuration_unsupportedGradle: pakken er låst i en konfigurasjon som en implementation-constraint ikke når
transitive_build_file_unsupportedGradle: byggefilen har ingen dependencies {-blokk på toppnivå
transitive_lock_entry_unsupportedLå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_propertyMaven: den styrte versjonen kommer fra en egenskap
transitive_already_managedMaven: styres allerede med den rettede versjonen eller høyere
transitive_lock_version_unsupportednpm: lockfileVersion 1. pnpm: en annen låsefilversjon enn 9.0
transitive_manifest_not_supportedEn låsefil som ikke er oppført ovenfor, som bun.lock, pdm.lock eller Pipfile.lock
transitive_target_metadata_missingAvhengighetsproxyen ga ingen metadata for den rettede versjonen, for eksempel fordi en pakkepolicy avviser den
transitive_manifest_missing, transitive_lock_missingManifestet eller låsefilen ligger ikke på den forventede stien på standardbranchen
transitive_release_age_pendingDen rettede versjonen er yngre enn utgivelsesalderen din; spør igjen etter datoen som står i detail
transitive_release_age_unknownAvhengighetsproxyen ga ikke noe publiseringstidspunkt for den rettede versjonen
transitive_branch_existsBranchen security-fix/<package>-<version> finnes allerede
transitive_repo_not_writableRepositoryet 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.