Since Spring Boot 3.3 the gradle plugin copies the bom generated by cyclonedx in the resources, s.t. the jars contain these files. CycloneDx generates a creation timestamp into the generated SBOM file and thus this file changes on each execution. All tasks having a input on the jar (such as test) but also the the jar generation task itself thus have different gradle cache keys each execution and therefore effectively the cache is disabled for all projects that have the cyclonedx plugin applied and configured.
I am aware that one could argue that this should be fixed by cyclonedx. On the other hand I believe this timestamp is necessary for other tools (such as the dependency track) and I don't think they will disable it.
One quick fix for all consumers is to add the following into their build.gradle (use the correct filename here):
normalization {
runtimeClasspath {
ignore "META-INF/sbom/bom.xml"
}
}
Comment From: wilkinsona
One quick fix for all consumers is to add the following into their
build.gradle
I don't think we can do this as it may result in an old sbom being used and it getting out of sync with the application's dependencies. That could result in a false negative for a security vulnerability.
I am aware that one could argue that this should be fixed by cyclonedx
Indeed, that's exactly what I think should happen. Please raise an issue against the CycloneDX plugin.
Comment From: aykborstelmann
Thanks for the fast answer !
I don't think we can do this as it may result in an old sbom being used and it getting out of sync with the application's dependencies. That could result in a false negative for a security vulnerability.
This could not happen, since if the dependencies change, all tasks depending on the jar and those that build the jar would be retriggered anyways. However, I agree that it is not that clean to base on this.
I will give it a try in opening an issue at cyclonedx's side, but don't hope for too much as I think the timestamp is relevant from their perspective.
Still, if you decide to not add something as normalization to fix this issue, I would value at least a toggle to disable this feature from spring boot perspective. In our project we don't need it. We only have cyclonedx for dependency track, yet our build times multiplied since the spring boot plugin update. I could imagine more people to have the same circumstances as we do.
Comment From: wilkinsona
I will give it a try in opening an issue at cyclonedx's side, but don't hope for too much as I think the timestamp is relevant from their perspective.
Given that SBOMs are important for security, I would hope that they will do something about it as build repeatability is also important for security. The ability for a build to produce byte-for-byte identical output allows a tag to be verified and for binaries to be recreated if necessary.
I would value at least a toggle to disable this feature from spring boot perspective. In our project we don't need it.
That's a situation that I don't think we'd considered thus far. Thanks for raising it. I'll re-open this issue so that we can consider what to do.
Comment From: wilkinsona
I think the timestamp is relevant from their perspective
I just experimented a bit and it's not clear how relevant the timestamp is. It isn't considered when Gradle performs an up-to-date check of the cyclonedxBom task so you can end up with an SBOM with a metadata.timestamp that's stale.
Interestingly, cloud native buildpacks, that value repeatability very highly, don't include a timestamp in the SBOM's metadata. Here's an example from the SBOM for paketo-buildpacks_executable-jar:
"metadata":
{
"component":
{
"bom-ref": "8dcbd803f369ec9f",
"name": "/workspace",
"type": "file"
},
"tools":
{
"components":
[
{
"author": "anchore",
"name": "syft",
"type": "application",
"version": "0.99.0"
}
]
}
}
The Maven plugin for CycloneDX automatically omits the timestamp when reproducible builds are enabled. The same has been requested for the Gradle plugin.
Comment From: wilkinsona
It's not quite a toggle, but you can stop the SBOM from being included in the uber jar (and the classpath of bootRun) like this:
tasks.named('processResources') {
exclude { "application.cdx.json".equals(it.name) }
}
Comment From: wilkinsona
We discussed this yesterday and concluded that we don't want to do anything here, for now at least. Given the workaround above, the Maven plugin already supporting repeatable builds, and it looking like the Gradle plugin is heading in the same direction, the need for an opt-out isn't clear at the moment. We can reconsider in the future if the need becomes clear.