Kraken’s nightly dependency-CVE scan opened #863: one open Dependabot alert
(medium) on org.apache.commons:commons-lang3, range >= 3.0, < 3.18.0,
GHSA-j288-q9x7-2f5v. The lead’s hypothesis was to add an explicit
commons-lang3 = "3.18.0" entry to gradle/libs.versions.toml.
That entry — plus an allprojects { configurations.configureEach {
resolutionStrategy.eachDependency { … } } } floor in build.gradle.kts — already
existed, landed in #431, an ancestor of the commit Kraken scanned. The alert was
open anyway.
Same shape as #850 (Bouncy Castle, see
2026-07-14-bouncycastle-buildscript-force-misses-project-configs.md): a pin’s
scope is part of the pin. The allprojects rule reaches every project
configuration, and :server:dependencyInsight --configuration jvmRuntimeClasspath
--dependency commons-lang3 confirms it’s working — :server resolves
commons-lang3:3.18.0 via commons-compress → dataframe-arrow/poi-ooxml
→ kandy, selected by the project-level rule.
But ./gradlew buildEnvironment (the buildscript classpath — Gradle plugins
themselves, resolved independently of project configs) showed commons-lang3
3.16.0 -> commons-lang3 with no override: AGP 9.2.1 → com.android.tools:repository
:32.2.1 → commons-compress:1.27.1 → commons-lang3:3.16.0, still below the
3.18.0 floor. The existing buildscript { configurations.all {
resolutionStrategy.force(...) } } block already forces Bouncy Castle, jose4j,
jdom2 and plexus-utils for exactly this reason (buildscript classpath ≠ project
classpath) but had never been extended to cover commons-lang3, because the
original #431 fix only needed to cover :server’s runtime classpath at the time.
Kraken’s “shippable runtime” classification did not hold up — this coordinate lives in AGP’s own tooling (Android Gradle Plugin build-time resolution), never on a packaged runtime classpath, matching the BC precedent’s “build/toolchain only.”
build.gradle.kts — added "org.apache.commons:commons-lang3:3.18.0" to the
existing buildscript resolutionStrategy.force(...) list (literal version string,
matching the other five buildscript-block forces — the version catalog isn’t wired
into that block). Verified with ./gradlew buildEnvironment before/after: 3.16.0
→ 3.16.0 -> 3.18.0. No change needed to gradle/libs.versions.toml or the
project-level allprojects rule — both already correct since #431.
buildscript { … } force and an allprojects {
configurations.configureEach { … } } rule cover disjoint dependency graphs.
Landing one does not landing the other; check both whenever a transitive
coordinate could plausibly be pulled in by a Gradle plugin (AGP, KSP, etc.) as
well as by project code.git merge-base --is-ancestor <fix-sha> <scanned-sha> before
assuming a lead is stale, then check ./gradlew buildEnvironment in addition to
:module:dependencyInsight — the former is the only one that sees the
buildscript classpath.