How to generate and upload SBOMs#

This page aims to provide an example approach on how to start generating SBOMs for projects and upload them to our SBOM Registry for quick risk analysis and remediation tracking.

How to generate an SBOM#

A project repository may contain the source code of one or more products. An effective starting point is to identify the products generated by the project, then map them to their corresponding ecosystems.

SBOM generation approaches differ based on CI/CD tools of choice. At a high level, an SBOM generation workflow should:

  • Trigger for each new release

  • Prepare setup

    • Checkout the repository

    • Setup ecosystem specific tooling

  • Generate the SBOM

    • Install ecosystem specific SBOM generation tooling

    • Generate the SBOM file

  • Extract metadata

    • Get product version from SBOM

  • Upload the SBOM as artifact

Each projects’ implementation(s) of most of the steps above may vary, usually depending on:

  • product(s) ecosystem(s)

  • versioning mechanism

  • release process

  • choice of sbom generation tooling

After the generation is complete, it is encouraged to upload the SBOM(s) to a Software Composition Analysis (SCA) Platform for quick analysis and risk assessment (more on how upload in the last section).

What type of SBOM to generate?#

SBOMs can be generated under different schemas, depending on the standard of choice. Some of the most popular standards are SPDX and CycloneDX. At the Eclipse Foundation, we make available our own instance of Dependency-Track as our SBOM Registry. Given Dependency-Track only supports the CycloneDX format, we highly encourage projects to at least generate one SBOM in this format.

In terms of the SBOM file format, tools will mostly support both json and xml. Our upload integration currently supports only json file uploads.

How many SBOMs to generate?#

For project repositories that contain multiple products, and especially in the case where the ecosystems differ, it is advisable to separate SBOMs for each product. Multiple ecosystem specific workflows can be created to achieve this. Alternatively, some tools support aggregated SBOM generation for a group of products, if justified and developed within the same ecosystem.

Which SBOM generation tool to use?#

The choice of tooling for SBOM generation is highly dependent on the ecosystem in which each product is developed. For example, Maven projects required Maven-specific SBOM plugins, while other ecosystems may have their own specialized tools. Alternatively, polyglot tools are capable of supporting multiple ecosystems.

As information on available tooling is scarce, we created a Tooling Ecosystem for CycloneDX guide, where we grouped references and pointers to the tools that best suits each projects’ needs, as well as quick installation and usage steps.

Examples#

Github Actions: Maven#

Below is an example of a Github Actions workflow generate-maven-sbom.yml that creates 1 SBOM json file for 1 Maven based product using the cyclonedx-maven-plugin SBOM generation plugin. The project uses Github Releases as their release mechanism, and their versioning schema is accurately reflected in the release tags.

name: Generate Maven SBOM

# Trigger on new releases published
on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      version:
        description: "Version"
        default: "main"
        required: true

# Product specific settings
env:
  JAVA_VERSION: '<java_version>'     # java version used by the product
  JAVA_DISTRO: '<java_distro>'       # java distro used by the product
  PRODUCT_PATH: '<PRODUCT_PATH>'     # path within project repository for product source
  PLUGIN_VERSION: '<plugin_version>' # cyclonedx-maven-plugin version to use
  SBOM_TYPE: '<makeBom|makeAggregateBom|makePackageBom>' # cyclonedx plugin goal

permissions:
  contents: read

jobs:
  generate-sbom:
    runs-on: ubuntu-latest
    outputs:
      project-version: ${{ steps.version.outputs.PROJECT_VERSION }}
    steps:
      - name: Extract version
        id: version
        run: |
          VERSION="${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.version }}"
          echo "PROJECT_VERSION=$VERSION" >> $GITHUB_OUTPUT
          echo "Product version: $VERSION"

      - name: Checkout repository
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          fetch-depth: 0
          ref: ${{ steps.version.outputs.PROJECT_VERSION }}

      - name: Setup Java SDK
        uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
        with:
          java-version: ${{ env.JAVA_VERSION }}
          distribution: ${{ env.JAVA_DISTRO }}

      - name: Generate sbom
        run: |
          mvn org.cyclonedx:cyclonedx-maven-plugin:$PLUGIN_VERSION:$SBOM_TYPE -f "$PRODUCT_PATH/pom.xml"

      - name: Upload sbom
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: sbom
          path: ${{ env.PRODUCT_PATH }}/target/bom.json

In addition to being automatically triggered on new releases, the workflow above supports manual runs. It allows specifying a specific branch, commit or sha value to check out the repository and generate the SBOM from.

Make sure dependencies are pinned in Github Actions workflows, as this ensures stability and security by preventing unexpected updates or potential supply chain attacks. An alternative tool that can help in with pinning to commit SHAs is Octopin

The project-version output is then used in a subsequent job to upload the SBOM to our DependencyTrack instance.

Github Actions: Other ecosystems#

We maintain a list of examples on our Early Adopters page from projects that benefited from our hands-on implementation support. As it is organized by ecosystem, with links to their SBOM generation and upload GitHub Actions workflows, these examples can provide guidance on approaches to SBOM generation within different project ecosystems.

If no examples are available for your projects’ ecosystem, please do not hesitate to reach out to us (contact details available on our Early Adopters page). We always welcome collaborations to extend this library.

How to upload an SBOM to DependencyTrack#

Once a functional workflow for generating SBOMs is established, the next consideration is how these SBOMs should be managed and consumed. While SBOMs can be uploaded as artifacts only, locating and analyzing specific SBOMs becomes increasingly cumbersome over time as their number grows.

To address this, our SBOM Registry, a Dependency-Track instance, serves as a centralized repository where all projects can upload their SBOMs. The registry, equiped with a web-based interface available to all, provides project consumers with immediate visibility into the security posture and risk profile of a given project, while enabling project maintainers to efficiently identify, prioritize, and remediate vulnerabilities across versions and dependencies.

We highly encourage all Eclipse Foundation projects to upload their SBOMs to this registry. To achieve this, the process consists of two steps:

  1. Reach out to the us (EF Security Team) by opening an issue in HelpDesk. The issue should contain your desired project hierarchy i.e. number of products, their names. We will generate entries and get back to you with a list of parentProject IDs.

Note: Due to Dependency-Track limitations, no two (non-SBOM) entries across the platform can have the same name, even if their parents differ (see this issue for more details). We highly encourage choosing names that are unique to the project across the entire hierarchy.

  1. Implement the SBOM upload logic

To support this, we are making efforts to provide plug-and-play upload integrations for all CI/CD platforms that can be used out of the box with minimal configuration (see below).

Github Actions Support#

Simply append the below snippet at the end of the SBOM generation workflow. Make sure the job that generates the SBOM has the name generate-sbom and outputs project-version with the version of the product.

  store-sbom-data: 
    needs: ['generate-sbom']
    uses: eclipse-csi/workflows/.github/workflows/store-sbom-data.yml@main
    with:
      projectName: '<product_name>' # product name as will be shown in DependencyTrack
      projectVersion: ${{ needs.generate-sbom.outputs.project-version }}
      bomArtifact: '<artifact_name>' # name from upload in generate-sbom job
      bomFilename: 'bom.json'
      parentProject: '<parentProject_ID>' # provisioned by us in step 1

Note: Although SBOM entries may share the same name (projectName) across multiple projects, due to Dependency-Track limitations, UI issues might appear (see this issue for more details). We highly encourage using project specific projectName values. For example, instead of using milestone as a name for your project SBOMs, consider choosing a unique value, such as <project>-milestone.

store-sbom-data stores the SBOM and additional metadata in a predefined format. Otterdog picks the artifacts up upon workflow completion and automatically uploads the SBOM to the DependencyTrack instance.

Jenkins support#

Due to Dependency-Track limitations, we are currently unable to offer out of the box upload support for other CI/CD platforms. We are currently working on a system to circumvent such limitations. An official announcement will be made soon via blog post when the system is available.

As the migration is expected to require minimal effort, we strongly encourage continued adoption of existing upload integrations in the meantime.