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 pinact.
The project-version output is then used in a subsequent job to upload the SBOM to our DependencyTrack instance.
Deprecated: The example above is written for the deprecated
store-sbom-dataupload. With the GitHub Actions upload, theUpload sbomstep is no longer needed, because the SBOM is uploaded directly from the same job. The version is passed to the next step asproduct-version, so it does not need to be shared across jobs as an output anymore.
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. Uploads are authenticated through the Project Identity Authority (PIA), which lets a CI/CD workload upload an SBOM for a given product with its own workload identity, without any long-lived credentials or shared secrets.
The process consists of two steps:
Request upload permission for your project (see Prerequisite below).
Implement the SBOM upload logic in your CI/CD pipeline (see GitHub Actions or Jenkins below).
Prerequisite: request upload permission#
Before a workload can upload SBOMs, we need to register it with PIA and provision the corresponding entries in DependencyTrack. To request this, open a HelpDesk issue with the following:
title:
[PROJECT NAME]: Request SBOM upload permissionlabels:
service:dependencytrackandteam:securityproject name: the Eclipse project the SBOMs belong to, e.g.
technology.openvsxproduct name(s): the name of each product you want to upload SBOMs for, as it should appear in DependencyTrack, e.g.
openvsx-serverandopenvsx-webuiworkload name(s): the CI/CD workload(s) that will perform the upload, i.e. the GitHub repository (e.g.
eclipse/openvsx) or the Jenkins instance per project (e.g.https://ci.eclipse.org/openvsx)
We will get back to you once the permissions are in place.
Note: Upload permission is granted per product name. If you want to add or change a product name, or upload from an additional workload, please open a new request.
Note: Due to Dependency-Track limitations, no two (non-SBOM) entries across the platform can have the same name, even if their parents differ. We highly encourage choosing product names that are unique to the project across the entire hierarchy. For example, instead of using
milestoneas a product name, consider a unique value such as<project>-milestone.
GitHub Actions#
Add the upload-sbom composite action from the eclipse-csi/workflows repository to the job that generates the SBOM. See its documentation for usage instructions and the full list of inputs. Use the product name as registered in the request above.
Jenkins#
The snippet below uploads an SBOM from a Jenkins pipeline, using the id-token OIDC credential for authentication. The credential is configured on your JIPP (Jenkins Instance Per Project) by the Eclipse Foundation, as part of the request above.
Update PRODUCT_NAME, PRODUCT_VERSION and SBOM_PATH to match your product, and use the product name as registered in the request above.
pipeline {
agent any
environment {
PRODUCT_NAME = '*** REPLACE ***'
PRODUCT_VERSION = '*** REPLACE ***'
SBOM_PATH = '*** REPLACE ***'
SBOM_API_DOMAIN = 'pia.eclipse.org'
}
stages {
stage('Upload SBOM') {
steps {
withCredentials([
string(
credentialsId: 'id-token',
variable: 'SBOM_ID_TOKEN'
)
]) {
sh '''
base64 -w0 "${SBOM_PATH}" > bom.b64
jq -n \
--arg name "${PRODUCT_NAME}" \
--arg version "${PRODUCT_VERSION}" \
--rawfile bom bom.b64 \
'{
product_name: $name,
product_version: $version,
bom: $bom
}' | \
curl -sS --fail-with-body \
https://${SBOM_API_DOMAIN}/v1/upload/sbom \
-H "Authorization: Bearer ${SBOM_ID_TOKEN}" \
--json @-
'''
}
}
}
}
}
Deprecated: upload via store-sbom-data#
Deprecated: The
store-sbom-dataworkflow described below is deprecated in favor of the PIA-based GitHub Actions upload above, which uploads directly from the workflow instead of relying on Otterdog to pick up artifacts. Existing users are encouraged to migrate; the migration is expected to require minimal effort. Do not use this integration for new setups.
This integration requires a parentProject ID, provisioned by the EF Security Team upon request in HelpDesk.
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 specificprojectNamevalues. For example, instead of usingmilestoneas 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.