Tracking issue so a deliberate workaround does not quietly become permanent.
Current state
org.cyclonedx.bom is pinned to 2.4.1 even though Spring Initializr ships 3.x for
Spring Boot 4. The pin exists because cyclonedx 3.x fails at configuration time on Gradle
9.4.1 — a variant-mutation conflict on :cyclonedxDirectBom.
The cost of the pin is not just the old version. Spring Boot's CycloneDxPluginAction only
auto-configures the plugin version it recognises (3.x), so with 2.4.1 unrecognised it leaves
cyclonedxBom at plugin defaults — writing build/reports/bom.json and scanning the wrong
configuration set. build.gradle.kts therefore reproduces that configuration by hand:
tasks.named<org.cyclonedx.gradle.CycloneDxTask>("cyclonedxBom") {
setOutputName("application.cdx")
includeConfigs.set(listOf("productionRuntimeClasspath"))
}
That output name and configuration set are load-bearing: generateBinaryLicense's
completeness gate reads the SBOM at build/reports/application.cdx.json and compares it
against the shipped fat-jar classpath. If the SBOM silently moved or described a different
classpath, the LICENSE appendix would be wrong — and the gate exists precisely to stop that.
Why this needs a tracker rather than a comment
The rationale is documented in build.gradle.kts and AGENTS.md, so it is discoverable. What
is not discoverable is when it stops being necessary. Once cyclonedx 3.x configures cleanly on
the project's Gradle version, the right move is to drop both the pin and the manual
configuration and let Spring Boot auto-configure the task — but nothing will prompt anyone to
check.
What to do when picking this up
- Try removing the version pin and the
tasks.named<CycloneDxTask> block.
- Confirm
./gradlew build produces build/reports/application.cdx.json (not bom.json).
- Confirm the SBOM lists the Spring Boot 4 modular jars and no stale Jackson 2 entries.
- Confirm
generateBinaryLicense still passes — it is the gate that catches a mis-scoped SBOM.
- Confirm the actuator still serves
/actuator/sbom/application in the http profile.
Context: the pin arrived with #23 (Spring Boot 4 + Spring AI 2.0 upgrade).
Tracking issue so a deliberate workaround does not quietly become permanent.
Current state
org.cyclonedx.bomis pinned to 2.4.1 even though Spring Initializr ships 3.x forSpring Boot 4. The pin exists because cyclonedx 3.x fails at configuration time on Gradle
9.4.1 — a variant-mutation conflict on
:cyclonedxDirectBom.The cost of the pin is not just the old version. Spring Boot's
CycloneDxPluginActiononlyauto-configures the plugin version it recognises (3.x), so with 2.4.1 unrecognised it leaves
cyclonedxBomat plugin defaults — writingbuild/reports/bom.jsonand scanning the wrongconfiguration set.
build.gradle.ktstherefore reproduces that configuration by hand:That output name and configuration set are load-bearing:
generateBinaryLicense'scompleteness gate reads the SBOM at
build/reports/application.cdx.jsonand compares itagainst the shipped fat-jar classpath. If the SBOM silently moved or described a different
classpath, the LICENSE appendix would be wrong — and the gate exists precisely to stop that.
Why this needs a tracker rather than a comment
The rationale is documented in
build.gradle.ktsandAGENTS.md, so it is discoverable. Whatis not discoverable is when it stops being necessary. Once cyclonedx 3.x configures cleanly on
the project's Gradle version, the right move is to drop both the pin and the manual
configuration and let Spring Boot auto-configure the task — but nothing will prompt anyone to
check.
What to do when picking this up
tasks.named<CycloneDxTask>block../gradlew buildproducesbuild/reports/application.cdx.json(notbom.json).generateBinaryLicensestill passes — it is the gate that catches a mis-scoped SBOM./actuator/sbom/applicationin thehttpprofile.Context: the pin arrived with #23 (Spring Boot 4 + Spring AI 2.0 upgrade).