Generating CycloneDX BOMs

An SBOM (Software Bill of Material) is a manifest that describes what a given software distribution consists of in terms of components. In addition to that, it may include a lot more information such as relationships between those components, licenses, provenance, etc. SBOMs would typically be used by software security and software supply chain risk management tools to perform vulnerability and compliance related analysis.

This guide describes Quarkus SBOM generation capabilities following CycloneDX specification.

Why Quarkus-specific tooling?

While Quarkus integrates with build tools such as Maven and Gradle, it could itself be categorized as a build tool with its own component and dependency model, build steps, and build outcomes. One of the essential component types of a Quarkus application is a Quarkus extension, which consists of a runtime and a build time artifacts, and their dependencies.

To properly resolve Quarkus extension and other application dependencies Quarkus uses its own dependency resolver, which is implemented on top of the dependency resolver provided by the underlying build tool: Maven or Gradle.

As a consequence, in case of Maven, for example, the results of dependency:tree will not include all the dependencies Quarkus will use to build an application. A similar issue will affect other dependency analysis tools that assume a project adheres to the standard Maven dependency model: they will not be able to capture the effective Quarkus application dependency graph. Unfortunately, that includes the implementation of the CycloneDX Maven plugin.

Besides the dependencies, that are an input to a build process, there is also an outcome of the build that is the final distribution of an application. Users of an application may request an SBOM manifesting not only the dependencies (the input to a build) but also the final distribution (the outcome of the build) before they agree to deploy the application. Quarkus allows application developers to choose various packaging types for their applications, some of which are Quarkus-specific. Providing certain Quarkus-specific details about components included in a distribution may help better evaluate the impact of potential security-related issues.

Dependency SBOMs

This chapter describes how to generate SBOMs manifesting only the dependencies of an application before it is built. In other words, these SBOMs will manifest the input into a build. These SBOMs could be used to perform vulnerability and compliance related analysis before building applications.

Maven Dependency SBOMs

For Quarkus Maven projects dependency SBOMs can be generated with the quarkus:dependency-sbom goal. The outcome of the goal will be saved in a target/<artifactId>-<version>-dependency-cyclonedx.json file (which can be changed by setting the outputFile goal parameter or the quarkus.dependency.sbom.output-file property). The complete Quarkus build and runtime dependency graphs will be recorded in the CycloneDX JSON format.

XML format can be requested by setting format goal parameter (or quarkus.dependency.sbom.format property) to xml.

Each component in the generated SBOM will include the quarkus:component:scope property that will indicate whether this component is used at runtime or only development/build time.

        {
          "name" : "quarkus:component:scope",
          "value" : "runtime"
        }

By default, quarkus:dependency-sbom captures the dependencies of a production build. Quarkus supports three application bootstrap modes: normal (production), test, and dev. In all three modes, an application may have different dependency graphs. The mode parameter can be used to indicate which dependency graph should be recorded. If the mode is set to test or dev, the target file name will become target/<artifactId>-<version>-<mode>-dependency-cyclonedx.json.

The complete set of parameters and their description can be obtained by executing mvn help:describe -Dcmd=quarkus:dependency-sbom -Ddetail.

Gradle Dependency SBOMs

Unlike Maven, the Gradle CycloneDX plugin implementation can be used in Quarkus projects to generate dependency SBOMs, since the implementation manifests dependency configurations registered by configured plugins.

Please, refer to the Gradle CycloneDX plugin documentation for its configuration options. Here is a list of Quarkus dependency configurations that would be relevant for manifesting:

  • quarkusProdRuntimeClasspathConfiguration - Quarkus application production runtime dependencies;

  • quarkusProdRuntimeClasspathConfigurationDeployment - Quarkus application production runtime and build time dependencies;

  • quarkusTestRuntimeClasspathConfiguration - Quarkus application test runtime dependencies;

  • quarkusTestRuntimeClasspathConfigurationDeployment - Quarkus application test runtime and build time dependencies;

  • quarkusDevRuntimeClasspathConfiguration - Quarkus application dev mode runtime dependencies;

  • quarkusDevRuntimeClasspathConfigurationDeployment - Quarkus application dev mode runtime and build time dependencies.

Given that the plugin is not aware of how Quarkus uses these dependencies, it will not be able to set the quarkus:component:scope property for components. On the other hand, the requested configuration name can be used indicate which scope to target.

Distribution SBOMs

This chapter describes SBOMs that manifest outcomes of Quarkus builds that are final application distributions.

During an application build and package assembly process, Quarkus captures certain details about the produced distribution and then allows an SBOM generator to consume and record that information in an SBOM format.

At this point, the only SBOM generator available for Quarkus users that can manifest application distributions is io.quarkus:quarkus-cyclonedx. Once it’s added as a project dependency it will generate SBOMs every time an application is built. SBOMs will be saved in the project’s build output directory under <executable-name>-cyclonedx.<format> name, where

  • <executable-name> is the base file name (without the extension) of the executable that launches an application;

  • <format> is either json (the default) or xml, which can be configured using quarkus.cyclonedx.format property. If both formats are desired quarkus.cyclonedx.format can be set to all.

Fast JAR

Fast JAR packaging uses a Quarkus-specific filesystem directory layout that contains files generated by Quarkus and Maven artifacts that are runtime dependencies of an application.

SBOMs for Fast JAR packaging type will use the executable JAR file as their main component and record both runtime and build time Quarkus application dependencies.

Runtime Components

Every file in the resulting Fast JAR distribution will appear in the SBOM with the quarkus:component:scope property set to runtime and evidence.occurrences.location field pointing to the location of the component in the application distribution directory, for example

      "purl" : "pkg:maven/org.jboss.slf4j/slf4j-jboss-logmanager@2.0.0.Final?type=jar",
      "properties" : [
        {
          "name" : "quarkus:component:scope",
          "value" : "runtime"
        }
      ],
      "evidence" : {
        "occurrences" : [
          {
            "location" : "lib/main/org.jboss.slf4j.slf4j-jboss-logmanager-2.0.0.Final.jar"
          }
        ]
      }
evidence.occurrences.location was introduced in CycloneDX schema version 1.5, for older versions the location will be indicated using the quarkus:component:location property.

Pedigree

Pedigree is a way to provide information that certain patches, or changes in general, have been applied to a certain component.

In certain cases, Quarkus may copy modified versions of dependency artifacts to an application distribution. Manipulating the original content of a component will change its hash sums which may get highlighted as suspicious by the tools comparing original component hash sums to those found in the distribution.

When Quarkus applies modifications to artifacts resolved from Maven repositories, it can manifest these changes as pedigree notes in the generated SBOM. For example, if an application developer decided to remove certain classpath resources from a dependency, such as

quarkus.class-loading.removed-resources."jakarta.transaction\:jakarta.transaction-api"=META-INF/NOTICE.md,jakarta/transaction/package.html

The resulting SBOM will include

      "purl" : "pkg:maven/jakarta.transaction/jakarta.transaction-api@2.0.1?type=jar",
      "pedigree" : {
        "notes" : "Removed META-INF/NOTICE.md,jakarta/transaction/package.html"
      },

Build time dependencies

Build time dependencies will be recorded with the quarkus:component:scope property set to development:

      "purl" : "pkg:maven/org.apache.httpcomponents/httpclient@4.5.14?type=jar",
      "properties" : [
        {
          "name" : "quarkus:component:scope",
          "value" : "development"
        }
      ]

They will not include evidence.occurrences.location since they will not be found in the distribution.

Uber JAR

SBOMs for Uber JARs will use the Uber JAR Maven artifact as their main component.

Since an Uber JAR is published as a Maven artifact itself, SBOMs generated for Uber JARs will also be automatically published as Maven artifacts. This, however, can be disabled by setting the attachSboms parameter of the quarkus:build goal to false.

Gradle users will have to explicitly configure a publishing plugin to deploy SBOMs as Maven artifacts.

Runtime components in an SBOM generated for an Uber JAR will not include evidence.occurrences.location since their content is merged in a single JAR file.

Native image

SBOMs for native images will use the native executable file as their main component.

Since native executables are not currently attached to projects as Maven artifacts, their SBOMs will not be attached as Maven artifacts either.

As in the case of an Uber JAR, runtime components in an SBOM generated for an native executable will not include evidence.occurrences.location since their corresponding code and resources are included in a single native executable file.

Mutable JAR

Mutable JAR distribution is similar to the Fast JAR one except it also includes build time dependencies to support re-augmentation (re-building) of an application.

SBOMs generated for Mutable JAR distributions will also record locations of components that will be used during re-augmentation process using evidence.occurrences.location but keeping their quarkus:component:scope property set to development. For example:

      "purl" : "pkg:maven/org.apache.httpcomponents/httpcore@4.4.16?type=jar",
      "properties" : [
        {
          "name" : "quarkus:component:scope",
          "value" : "development"
        }
      ],
      "evidence" : {
        "occurrences" : [
          {
            "location" : "lib/deployment/org.apache.httpcomponents.httpcore-4.4.16.jar"
          }
        ]
      }

Embedded Dependency SBOM

A dependency SBOM can be embedded into the application itself as a classpath resource, so that it travels with the application and can be consumed at runtime or by tools inspecting the artifact. This is enabled with:

quarkus.cyclonedx.embedded.enabled=true

The SBOM is embedded as a classpath resource at META-INF/sbom/dependency.cdx.json by default. The resource name can be customized, and its extension determines the format (.json for JSON, .xml for XML):

quarkus.cyclonedx.embedded.resource-name=META-INF/custom-sbom.json

The embedded SBOM manifests the application dependencies (the input to the build) rather than the final distribution layout. When product attribution is enabled (the default), the embedded SBOM also includes the platform-member product components.

Native image

When building a native executable, in addition to the classpath resource, the embedded SBOM is also baked into the native binary as the sbom and sbom_length global symbols, following the GraalVM SBOM specification. The sbom symbol references a GZIP-compressed copy of the SBOM (as required by the specification), which allows tools such as syft to extract the SBOM directly from the executable:

syft scan ./my-native-app -o cyclonedx-json

Product Attribution

Quarkus platforms (such as the Quarkus platform BOM or vendor-provided platforms) may aggregate extensions that belong to supported products, also referred to as offerings. When an application is built on such a platform, product attribution represents each supported product as a dedicated component in the generated SBOM and links the application artifacts that belong to that product to it. This lets downstream tools see which parts of an application are covered by a given product and match them against product-level vulnerability and support information, for example by CPE.

Product attribution is enabled by default and applies to every SBOM that includes the core application contribution (the dependency and distribution SBOMs). It can be disabled with:

quarkus.cyclonedx.product-attribution=false

For the quarkus:dependency-sbom Maven goal the equivalent parameter is quarkus.dependency.sbom.product-attribution.

How it works

Attribution is driven entirely by metadata the platform provides through its platform properties; an application does not configure products directly. Each imported platform member that declares a product identity (at minimum a CPE) yields, in the generated SBOM, a single product component that:

  • has the type framework (unless the platform specifies a different type), carries the product’s CPE, and has its CycloneDX scope set to excluded, since the product itself is not a shipped artifact;

  • is a top-level component, so it appears as a direct dependency of the main application component;

  • provides the artifacts attributed to it — the application’s runtime extension artifacts that belong to the product, together with their dependencies. These are recorded as CycloneDX 1.6 dependency.provides relationships (the product provides/implements those artifacts). On schema versions older than 1.6, where provides is not available, the same artifacts are recorded as dependsOn relationships instead.

Platform members that declare the same product PURL and CPE are merged into a single product component whose attributed artifacts are the union of the members' contributions.

Only artifacts that are actually present in the application and match the coordinates the platform attributed to the product are linked. If the application overrides the version of an attributed dependency, that dependency is not attributed to the product.

A product component is emitted whenever a platform member declares a CPE, even if none of its attributed artifacts end up present in the application.

Quarkus Property Taxonomy

名称 Value range 描述

quarkus:component:scope

runtime or development

Indicates whether a component is a runtime or a build/development time dependency of an application.

quarkus:component:location

String representing a file system path using / as a path element

Used in SBOMs with schema versions 1.4 or older. Starting from schema 1.5, evidence.occurrences.location is used instead. This property is used only if a component is found in the distribution. The value is a relative path to a file pointing to the location of a component in a distribution using / as a path element separator.

配置参考

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

类型

默认

Whether to skip SBOM generation

Environment variable: QUARKUS_CYCLONEDX_SKIP

Show more

boolean

false

SBOM file format. Supported formats are {code json} and {code xml}. The default format is JSON. If both are desired then all could be used as the value of this option.

Environment variable: QUARKUS_CYCLONEDX_FORMAT

Show more

string

json

CycloneDX specification version. The default value be the latest supported by the integrated CycloneDX library.

Environment variable: QUARKUS_CYCLONEDX_SCHEMA_VERSION

Show more

string

Whether to include the license text into generated SBOMs.

Environment variable: QUARKUS_CYCLONEDX_INCLUDE_LICENSE_TEXT

Show more

boolean

false

When Quarkus platform members include product information (a CPE and the extensions/artifacts bound to an offering) and this option is enabled, each product is represented in the SBOM as a top-level component of type framework that provides the artifacts attributed to it (CycloneDX 1.6 dependency.provides; recorded as dependsOn on older schema versions).

Environment variable: QUARKUS_CYCLONEDX_PRODUCT_ATTRIBUTION

Show more

boolean

true

Embedded dependency SBOM configuration

类型

默认

Whether a dependency SBOM should be embedded in the final application as a classpath resource.

Environment variable: QUARKUS_CYCLONEDX_EMBEDDED_ENABLED

Show more

boolean

false

Classpath resource name for the embedded dependency SBOM. The SBOM format (JSON or XML) is derived from the resource name extension.

Environment variable: QUARKUS_CYCLONEDX_EMBEDDED_RESOURCE_NAME

Show more

string

META-INF/sbom/dependency.cdx.json