A vulnerable transitive dependency keeps slipping into your build via several libraries. How would you use eachDependency to pin it to a safe version across the whole graph?
answer
- fires for transitives too
- match group/name then useVersion
- configurations.all for all classpaths
- because() records the CVE
- verify with dependencyInsight
basics
~10 sAdd configurations.all { resolutionStrategy.eachDependency { if it's the vulnerable module, useVersion("safe") } }. The rule fires for every transitive, so every path to that module resolves to the safe version.
solid answer
~40 sBecause `eachDependency` fires for **every** dependency in the graph — direct and transitive — it's a clean way to pin a transitive that arrives via many parents. Match the module by `requested.group`/`requested.name`, call `useVersion("<safe>")`, and add `because("CVE fix")`. Wrap it in `configurations.all` so it covers compile, runtime, and test classpaths. Every resolution path to that module now lands on the safe version regardless of which library pulled it in. Verify with `./gradlew dependencyInsight --dependency <name>`, which shows the rule's reason. Note this is one option among several — a `dependencies { constraints { } }` block or a platform/BOM is often more declarative — but `eachDependency` is the imperative tool that wins when you need conditional or computed logic.
code
kotlin · 8 linesconfigurations.all {
resolutionStrategy.eachDependency {
if (requested.name == "jackson-databind") {
useVersion("2.17.1")
because("pin patched jackson-databind")
}
}
}go deeper
Show the basic configurations.all + eachDependency + useVersion pattern and that it covers transitives.
Add because() and dependencyInsight verification; note it covers all classpaths.
Compare against constraints/platform and explain when each is preferable for security pinning.
Discuss org-wide policy: convention plugins applying such pins consistently and lifecycle for removing them.
## The problem A transitive dependency (one you never declared directly) carries a vulnerability. It enters your graph through several libraries, possibly at different versions. You want one safe version everywhere. ## Why eachDependency fits The `eachDependency` rule is invoked **once per module per resolution**, covering transitives. So a single rule catches every path to the offending module without you editing each parent declaration. ```kotlin configurations.all { resolutionStrategy.eachDependency { if (requested.group == "com.fasterxml.jackson.core" && requested.name == "jackson-databind") { useVersion("2.17.1") because("CVE-XXXX: pin jackson-databind to a patched release") } } } ``` ## Cover all configurations `configurations.all { ... }` applies the rule to every configuration — `compileClasspath`, `runtimeClasspath`, `testRuntimeClasspath`, and any plugin-added ones — so the pin is comprehensive and future-proof against new configurations. ## Verify it took effect ```bash ./gradlew dependencyInsight \ --configuration runtimeClasspath \ --dependency jackson-databind ``` The report shows the resolved version and the `because` reason, confirming the rewrite and helping the next engineer understand it. ## Trade-offs vs alternatives - **`eachDependency` + useVersion**: imperative, supports arbitrary conditions/computed versions; runs per-module so keep it cheap. - **`constraints { }`**: declarative, expresses a preferred/required version and participates more cleanly in conflict resolution and reporting. - **Platform/BOM**: best for aligning a whole family of modules to one version. For a single conditional security pin, `eachDependency` is direct and effective. For broad, long-lived version policy, prefer constraints or a platform. Whichever you choose, document the CVE in `because`/comments so the pin can be removed once upstream libraries catch up.
- How do you confirm the pin actually applied and see why?Run ./gradlew dependencyInsight --configuration runtimeClasspath --dependency <name>; it shows the resolved version and the because() reason.
- When would a constraints block be a better choice than this eachDependency rule?When you want a declarative, conflict-resolution-friendly preferred/required version with cleaner reporting and no imperative per-module callback.
saying these in an interview costs you the question
- Claiming you must edit every library that pulls the transitive — the rule covers all paths.
- Thinking the rule misses transitives — it fires for them too.