dependabot / dependabot/dependabot-core
Gradle: Add BOM (Bill of Materials) awareness to prevent incompatible dependency upgrades
- Dominant language
- Ruby
- Stars
- 5.8k
- Forks
- 1.5k
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 149
Description
## Summary
Dependabot's Gradle parser has no awareness of Bill of Materials (BOM) dependencies. When a project uses a BOM to manage dependency versions (via Gradle's native `platform()` / `enforcedPlatform()` or the Spring `io.spring.dependency-management` plugin's `imports { mavenBom() }`), Dependabot treats every dependency with an explicit version string as independently bumpable — even if the version is meant to be governed by the BOM.
This leads to Dependabot proposing version upgrades that break BOM compatibility, producing runtime `ClassNotFoundException` / `NoSuchMethodError` failures that compile cleanly but explode in production.
## Problem
BOMs (like `azure-sdk-bom`, `spring-boot-dependencies`, `aws-sdk-bom`, `jackson-bom`) are curated compatibility matrices: all libraries listed in the BOM are tested together at their specified versions. Upgrading a single managed library independently of its BOM breaks this contract.
### Real-world example
Our project declares:
```kotlin
// buildSrc convention plugin — manages versions for all subprojects
dependencyManagement {
dependencies {
imports { mavenBom("com.azure:azure-sdk-bom:1.3.7") }
// BOM manages azure-ai-translation-text at 1.1.9
}
}
```
```kotlin
// libs/text/build.gradle.kts
implementation("com.azure:azure-ai-translation-text:1.1.9")
```
Dependabot saw `1.1.9` and bumped it to `2.0.0` in a grouped PR alongside 8 other safe minor/patch updates. The 2.0.0 library compiled fine (Gradle resolved the direct dependency to 2.0.0), but at runtime the transitive Azure dependencies remained at BOM-managed 1.x-compatible versions, causing `ClassNotFoundException` in production.
**The correct fix** is to remove the explicit version and let the BOM manage it:
```kotlin
implementation("com.azure:azure-ai-translation-text") // version from BOM
```
But Dependabot should also understand this relationship to avoid proposing incompatible upgrades.
## Desired behavior
1. **Detect BOM-managed dependencies**: When parsing Gradle files, recognize dependencies whose versions are governed by a BOM (declared via `platform()`, `enforcedPlatform()`, or `imports { mavenBom() }`).
2. **Suppress independent version bumps for BOM-managed deps**: If a dependency's version matches the version specified in the imported BOM, don't propose upgrading it independently. The version should only change when the BOM itself is upgraded.
3. **Propose BOM upgrades**: Treat the BOM declaration itself as a versionable dependency (e.g., bump `azure-sdk-bom:1.3.7` → `1.3.8`). When the BOM is bumped, the managed dependency versions flow automatically.
4. **Warn on BOM version overrides**: If a dependency declares an explicit version that differs from what the BOM specifies, flag it in the PR description (e.g., "Note: `azure-ai-translation-text:2.0.0` overrides BOM-managed version `1.1.9`").
## Current parser limitations
Looking at the [Gradle file parser source](https://github.com/dependabot/dependabot-core/blob/main/gradle/lib/dependabot/gradle/file_parser.rb), it:
- Does not parse `platform()` or `enforcedPlatform()` declarations
- Does not parse `imports { mavenBom(...) }` blocks (Spring dependency management plugin)
- Has no data structure to track BOM-managed vs. independently versioned dependencies
- Contains zero BOM-related code or comments
## Scope
This affects all Gradle projects using BOMs, which is extremely common in the Java ecosystem:
- **Azure SDK**: `com.azure:azure-sdk-bom`
- **AWS SDK v2**: `software.amazon.awssdk:bom`
- **Spring Boot**: `org.springframework.boot:spring-boot-dependencies`
- **Spring Cloud**: `org.springframework.cloud:spring-cloud-dependencies`
- **Jackson**: `com.fasterxml.jackson:jackson-bom`
- **gRPC**: `io.grpc:grpc-bom`
- **OpenTelemetry**: `io.opentelemetry:opentelemetry-bom`
- **JUnit**: `org.junit:junit-bom`
- **Netty**: `io.netty:netty-bom`
The Maven ecosystem has analogous BOM support, and the Maven Dependabot parser may have similar gaps.
## Workarounds
Current workarounds are all imperfect:
1. **Remove explicit versions for BOM-managed deps** — best practice, but Dependabot still can't bump the BOM itself
2. **Use `ignore` rules** — requires manually maintaining an ignore list per BOM
3. **Restrict `update-types` to minor/patch** — prevents this specific failure but also suppresses legitimate major version PRs (see #14202)
Contributor guide
Research direction
Start with gradle/lib/dependabot/gradle/file_parser.rb, the parser source identified in the issue, and trace how dependency declarations become versionable dependencies. Then investigate the existing Gradle parsing flow for platform(), enforcedPlatform(), and imports { mavenBom(...) }. Done means BOM-managed dependencies are tracked, independent bumps are suppressed, BOM declarations can be upgraded, and explicit overrides are reported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, ruby
- Domain
- build-system, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100