An SBOM of everything your build actually uses
A Maven plugin that writes a CycloneDX SBOM covering the resolved project dependency graph, every build plugin and its transitive dependencies, and the BOMs you import. Not just the application classpath.
Version 1.0.0 CycloneDX 1.5 Maven 3.9 Java 8+ Apache 2.0What it finds
Main build graph
The fully resolved project dependency graph across compile, runtime, provided and test scopes, with the real path that brought each artifact in.
Build tooling
Every plugin in the effective build, plus each plugin's own transitive dependencies and any extra <plugin><dependencies>. These run arbitrary code during your build and never show up in the project classpath.
BOM imports
The import-scoped POMs from <dependencyManagement>, since a BOM's release train is a trackable component in its own right.
The plugin only enumerates and writes. It does no vulnerability, end-of-life or licence annotation. Feed the SBOM to whatever tooling does that for you.
Quick start
Run it against any Maven project without touching the POM:
mvn dev.noregressions:sbom-plus-maven-plugin:1.0.0:scan
For a multi-module reactor, run the aggregate goal once from the root:
mvn dev.noregressions:sbom-plus-maven-plugin:1.0.0:scan-aggregate
Or bind it into the build so every mvn verify produces an SBOM:
<plugin>
<groupId>dev.noregressions</groupId>
<artifactId>sbom-plus-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<goals>
<goal>scan</goal>
</goals>
</execution>
</executions>
</plugin>
Goals and parameters
sbom-plus:scan
Scans the current module only. Binds to the verify phase by default.
| Parameter | Property | Default |
|---|---|---|
outputFile | sbomPlus.outputFile | ${project.build.directory}/sbom-plus.json |
sbomOutputFile | sbomPlus.sbomOutputFile | ${project.build.directory}/sbom-plus-cyclonedx.json |
sbom-plus:scan-aggregate
Runs once for a whole multi-module reactor and writes one combined report and one combined SBOM at the top level.
| Parameter | Property | Default |
|---|---|---|
outputFile | sbomPlus.outputFile | ${session.topLevelProject.build.directory}/sbom-plus-aggregate.json |
sbomOutputFile | sbomPlus.sbomOutputFile | ${session.topLevelProject.build.directory}/sbom-plus-cyclonedx-aggregate.json |
Override either path from the command line:
mvn dev.noregressions:sbom-plus-maven-plugin:1.0.0:scan -DsbomPlus.sbomOutputFile=build/sbom.json
Outputs
Each goal writes two files.
The CycloneDX SBOM
A CycloneDX 1.5 JSON document with one library component per
distinct artifact. Only artifacts that actually resolved are listed. Each
component carries:
purl, with a?type=qualifier for anything that is not a jar, such as?type=pomfor a BOM import or?type=maven-pluginfor a plugin.bom-ref, equal to the purl, which thedependenciessection refers to.scope:requiredfor compile, runtime and system dependencies,optionalfor provided, andexcludedfor test-only dependencies, build tooling and BOM imports, since those never ship in the delivered artifact.
The document also has a dependencies graph rebuilt from the
real resolution paths, and a metadata.tools entry naming the
plugin and its version. Every SBOM the test suite produces is validated
against the official CycloneDX schema.
The scan report
The plugin's own richer, per-module view. For every row it records which resolution pass found it, its scope, and the root-first path that brought it in.
{
"formatVersion" : 1,
"generatedAt" : "2026-09-06T12:29:53Z",
"modules" : [ {
"module" : "com.example:app",
"dependencies" : [ {
"coordinate" : { "groupId" : "org.slf4j", "artifactId" : "slf4j-api", "version" : "2.0.13" },
"origin" : "MAIN_BUILD",
"scope" : "compile",
"type" : "jar",
"module" : "com.example:app",
"broughtInBy" : [ { "groupId" : "ch.qos.logback", "artifactId" : "logback-classic", "version" : "1.5.6" } ]
} ],
"unresolved" : [ ]
} ]
}
origin is one of MAIN_BUILD, BUILD_TOOLING
or BOM. formatVersion is bumped whenever the report
shape changes in a way consumers need to know about.
Unresolved dependencies
A dependency that cannot be resolved does not fail the build. The typical case is a multi-module reactor scanned before it has ever been built, where one module depends on a sibling SNAPSHOT that exists nowhere yet. In that situation the plugin:
- logs a warning naming each artifact that could not be resolved,
- keeps everything else that did resolve,
- records each gap in the module's
unresolvedlist in the scan report, with the coordinate, scope and the resolver's reason, - leaves the unresolved artifact out of the CycloneDX SBOM, since an SBOM must only assert components that exist.
"unresolved" : [ {
"coordinate" : { "groupId" : "com.example", "artifactId" : "core", "version" : "1.2.0-SNAPSHOT" },
"scope" : "compile",
"reason" : "Could not find artifact com.example:core:jar:1.2.0-SNAPSHOT"
} ]
Requirements
- Maven 3.9.x
- Java 8 or later to run the plugin. The plugin is compiled with
--release 8.
Source and issues
Source, issue tracker and release notes live at
github.com/noregressions/sbom-plus-maven-plugin.
Build it locally with mvn verify, which runs the unit tests and the
forked integration builds under src/it.