Software Bill of Materials (SBOM)¶
A Software Bill of Materials (SBOM) is a document used to exchange information about software and its composition. This format is primarily used in the security field to check software and its dependencies for vulnerabilities using vulnerability databases such as CVE and OSV. The SBOM format used by the CPython project is SPDX, which can be converted to other formats as needed. The SBOM file for the dependencies included in CPython is maintained at Misc/sbom.spdx.json. The file is generated using Tools/build/generate_sbom.py.
Generating an SBOM File¶
… with uv¶
uv provides an easy way to generate an SBOM file in the CycloneDX v1.5 format using:
$ uv export --format='cyclonedx1.5' > sbom.cdx.json
However, the file contains only very basic information; for example, for cusy.tasks:
"component": {
"type": "library",
"bom-ref": "cusy-tasks-1@26.2.0",
"name": "cusy-tasks",
"version": "26.2.0",
"properties": [
{
"name": "uv:package:is_project_root",
"value": "true"
}
]
}
Using uv export --all-groups --format='cyclonedx1.5' > sbom.cdx.json, you
can also include all dependency groups in the SBOM file.
… using CycloneDX Python¶
The output from CycloneDX Python is considerably more comprehensive:
{
"bom-ref": "cusy-tasks==26.2.0",
"description": "",
"externalReferences": [
{
"comment": "PackageSource: Local",
"type": "distribution",
"url": "file:///Users/veit/cusy/prj/cusy.tasks"
},
{
"comment": "from packaging metadata Project-URL: Documentation",
"type": "documentation",
"url": "https://tasks.cusy.io/"
},
{
"comment": "from packaging metadata Project-URL: Mastodon",
"type": "other",
"url": "https://mastodon.social/@Python4DataScience"
},
{
"comment": "from packaging metadata Project-URL: GitHub",
"type": "vcs",
"url": "https://github.com/cusyio/cusy.tasks"
}
],
"licenses": [
{
"license": {
"acknowledgement": "declared",
"id": "BSD-3-Clause"
}
}
],
"name": "cusy-tasks",
"type": "library",
"version": "26.2.0"
}
The command to generate the file is:
$ uvx --from cyclonedx-bom cyclonedx-py environment .venv --output-file sbom.cdx.json
Warning
CycloneDX Python generates the SBOM file from the current .venv
directory. So if you run cyclonedx-bom in your development environment,
you will also find all your development tools listed in your SBOM file.
… with sbomify¶
sbomify provides a GitHub Action for generating the SBOM file, which uses CycloneDX Python under the bonnet. The file can then be attested using actions/attest-sbom:
---
name: Build with SBOM Attestation
on:
push:
branches: [main]
permissions:
contents: read
id-token: write
attestations: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Build
run: uv build
- name: Generate SBOM
uses: sbomify/sbomify-action@f38411f20fe2cc52e5bb7abd4d094ffc9dc5f17c # v26.7.0
env:
LOCK_FILE: uv.lock
OUTPUT_FILE: sbom.cdx.json
COMPONENT_NAME: myapp
COMPONENT_VERSION: ${{ github.sha }}
ENRICH: true
UPLOAD: false
- name: Attest SBOM
uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0
with:
subject-path: './dist'
sbom-path: './sbom.cdx.json'
In GitLab CI, you can use sbomify as follows:
stages:
- build
- sbom
build:
stage: build
script:
- uv build
artifacts:
paths:
- dist/
generate-sbom:
stage: sbom
image: ghcr.io/sbomify/sbomify-action
variables:
LOCK_FILE: uv.lock
OUTPUT_FILE: sbom.cdx.json
COMPONENT_NAME: myapp
COMPONENT_VERSION: $CI_COMMIT_TAG
UPLOAD: "false"
ENRICH: "true"
script:
- /sbomify.sh
artifacts:
paths:
- sbom.cdx.json
reports:
cyclonedx: sbom.cdx.json
You can also integrate dependency scanning:
include:
- template: Security/Dependency-Scanning.gitlab-ci.yml
generate-sbom:
stage: test
image: ghcr.io/sbomify/sbomify-action
variables:
LOCK_FILE: uv.lock
OUTPUT_FILE: gl-sbom-report.cdx.json
UPLOAD: "false"
ENRICH: "true"
script:
- /sbomify.sh
artifacts:
paths:
- gl-sbom-report.cdx.json
reports:
cyclonedx: gl-sbom-report.cdx.json
PEP 770 – SBOMs in Python packages ———————————~
PEP 770 standardises the inclusion of SBOMs in Python wheels via the
.dist-info/sboms/ directory. If you publish Python packages on
PyPI, this means that your users will automatically receive the SBOM
file when they install your package, for example:
myapp-26.2.0.dist-info
├── METADATA
├── RECORD
└── sboms/
└── myapp.cdx.json
Build backends such as Hatchling ≥ 1.28 already support this via the
sbom-files configuration:
[tool.hatch.build.targets.wheel]
sbom-files = ["myapp.cdx.json"]
Instead of generating the SBOM file from scratch during the build, a minimal CycloneDX SBOM file can be checked into the repository:
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"metadata": {
"component": {
"type": "library",
"name": "mylib",
"version": "0.0.0-placeholder"
}
},
"components": []
}
In the CI workflow, the placeholder SBOM file is then checked out along with the code. sbomify then enriches it with the latest information. Hatchling subsequently builds the wheel using the latest SBOM file, and finally the wheel is published to PyPI.
Analysis¶
There are numerous tools available for security and licence checks, each
focusing on different problem areas. Two open-source tools for SBOM analysis are
Dependency Track and GUAC.
With sbomify-action, you can upload SBOMs directly from the CI
pipeline to your Dependency Track instance using:
UPLOAD_DESTINATIONS=dependency-track