Generating an SBOM for Java / Kotlin (Maven)
The step below writes a CycloneDX JSON file in your own pipeline. The CRA Desk scan reads that file and turns it into a readiness report - it never generates one for you.
Add to pom.xml:
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<outputFormat>json</outputFormat>
</configuration>
</plugin>Run in CI:
mvn -B org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -DoutputFormat=json
- Produces:
- target/bom.json
- Format:
- CycloneDX JSON
The whole CI job
GitHub Actions
- uses: actions/checkout@v4
- run: mvn -B org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -DoutputFormat=json
- uses: mmalinowski/cradesk-action@v1
with:
sbom-path: target/bom.jsonGitLab CI/CD
generate-sbom:
script:
- mvn -B org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -DoutputFormat=json
include:
- component: gitlab.com/cradesk/scan/readiness@1
inputs:
sbom_path: target/bom.jsonOnly the first step changes with your stack - the CRA Desk step after it is identical everywhere.
What goes wrong here
makeAggregateBom is the important word: a multi-module build without it writes one bom per module, and the scan reads a single file rather than merging them.
What CRA Desk does with the result
Components from this build carry pkg:maven package URLs, which the watch matches against OSV's Maven advisories when the SBOM arrives and again as new advisories land. Matching runs on every plan; e-mail alerts and the full match list are what a paid plan adds.
A generator that runs is not the same as coverage. Components with no purl, no version, or from an ecosystem outside the nine we watch are counted as gaps in every report rather than reported as clean.