https://docs.spring.io/spring-boot/reference/actuator/endpoints.html#actuator.endpoints.sbom

It was not immediately clear to me that, for Gradle, the cyclonedxBom task is not part of the overall build lifecycle.

Additionally, the output needs to be placed in a specific location to be auto-detected: https://github.com/spring-projects/spring-boot/blob/v3.3.0/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/sbom/SbomEndpoint.java#L43

It would be nice if the Spring Boot Gradle plugin reacts to the CycloneDX plugin application with some sensible default:

tasks {
    processResources {
        from(cyclonedxBom) {
            include("${cyclonedxBom.get().outputName.get()}.json")
            into("META-INF/sbom")
        }
    }
}

The include() part is necessary since the task outputs to build/reports which can contain other items not related to SBOM.

Comment From: scottfrederick

Thanks for trying out the new SBOM support @ciscoo.

The Spring Boot Gradle plugin should respond to the CycloneDX plugin and put the SBOM file in the appropriate location without additional configuration (see https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java).

Can you give more details about the Gradle tasks you are running to generate the Spring Boot jar file that includes the SBOM, and share an example project with a build configuration that does not work as you expect?

Comment From: scottfrederick

We should consider adding the CycloneDX plugin to the Reacting to Other Plugins section of the Spring Boot Gradle plugin documentation.

Comment From: ciscoo

@scottfrederick I had missed that part.

I see that the SBOM JSON file is included in the final archive (bootJar), but I had expected it to also be available when running the application locally without building the final archive.

In other words, I expected ./gradlew bootRun to also include the generated SBOM so I can view that locally, but it doesn't

I guess maybe that is something to callout or document.

Comment From: wilkinsona

When reacting to the plugin, we only configure bootJar to include the SBOM:

https://github.com/spring-projects/spring-boot/blob/9def6f86c9f88c405f302d9e044d5ea463cfe1f5/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java#L50-L58

I think we should expand this to bootWar and bootRun as well. That could be done by configuring processResources as suggested above. That will affect the contents of the plain jar and war archives as well which may or may not be what we want.

Comment From: mmoayyed

I think we should expand this to bootWar and bootRun as well.

+1 here, thank you. It took me a while to figure this out, and then we had to enable this manually in the build with specific plugin changes.

Comment From: mhalbritter

Got something in https://github.com/mhalbritter/spring-boot/tree/mh/40890-react-to-cyclonedx-gradle-plugin-application.

Comment From: ThomasVitale

I appreciate the current defaults where the cyclonedxBom Gradle task is only invoked when generating the final application JAR with bootJar (and the equivalent in Maven) since SBOMs will typically be used in the CI/CD pipeline for scanning, compliance checks, and other activities.

For big projects, having the SBOM generated as part of the local development workflow can impact the startup/iteration time and flow, besides not being needed in most scenarios. If you make the SBOM generation part of bootRun, could it be made optional and turned off by default, keeping the same behaviour as today, but making it easier to turn it on for local development for those cases where it's needed? Would that be acceptable?

Comment From: wilkinsona

For big projects, having the SBOM generated as part of the local development workflow can impact the startup/iteration time and flow, besides not being needed in most scenarios

Can you provide some concrete examples of the impact? In my experience, SBOM generation is pretty quick. I would also expect Gradle's up-to-date checking to mean it's avoided a lot of the time. Perhaps that's not working as hoped, in which case I would prefer that this is addressed in the CycloneDX plugin rather than by adding complexity to Boot's Gradle plugin in the form of configuration options.

Comment From: wilkinsona

As far as I can tell the impact is minimal.

In a real-world application with 153 jars in BOOT-INF/lib, SBOM generation takes ~6 seconds on first build. Subsequently, it's virtually instant thanks to Gradle's up-to-date checking. This continues to be the case when changing the application's own code. The SBOM is only rebuilt when a change is made to the application's compile and runtime dependencies as this change then needs to be reflected in the SBOM.

Given these datapoints, I remain in favor of consistently generating the bom for bootRun, bootJar, and bootWar.

Comment From: ThomasVitale

@wilkinsona Thanks for elaborating on that. It's a very a good point that in those cases it would be something to be addressed in the CycloneDX plugin and not in Spring Boot.