dependabot / dependabot/dependabot-core

Gradle: Add BOM (Bill of Materials) awareness to prevent incompatible dependency upgrades

Open
#15,328 0 comments 1 reaction 0 assignees View on GitHub
L: java:gradle L: java:maven T: feature-request
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.