A comprehensive GitHub Action that generates CycloneDX Software Bill of Materials (SBOM) reports for Python projects with automatic detection and support for different Python dependency management tools.
Multi-tool Support: Automatically detects and works with:
Smart Detection: Automatically identifies the dependency management tool used in your project
Supported Formats: Generate SBOM in JSON, XML, or both
Flexible Configuration: Control inclusion of development dependencies, output formats, and more
Comprehensive Validation: Validates generated SBOM files for correctness
Rich Outputs: Provides detailed information about the generated SBOMs
name: "Generate SBOM"on: [push]jobs:
sbom:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Generate SBOM"uses: lfreleng-actions/python-sbom-action@v1name: "SBOM Generation"on: [push]jobs:
sbom:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Generate SBOM"id: sbomuses: lfreleng-actions/python-sbom-action@v1with:
include_dev: "false"sbom_format: "both"
- name: "Upload SBOM artifacts"uses: actions/upload-artifact@v4with:
name: sbom-filespath: | sbom-cyclonedx.json sbom-cyclonedx.xmlretention-days: 90
- name: "Summary"run: | echo "SBOM count: ${{ steps.sbom.outputs.component_count }}" echo "Tool used: ${{ steps.sbom.outputs.dependency_manager }}"steps:
- name: "Generate SBOM with dev dependencies"uses: lfreleng-actions/python-sbom-action@v1with:
python_version: "3.11"include_dev: "true"sbom_format: "json"sbom_spec_version: "1.6"path_prefix: "src/myproject"# Source code locationoutput_directory: "reports"# Custom report locationfilename_prefix: "my-project-sbom"
- name: "Upload SBOM artifacts"uses: actions/upload-artifact@v4with:
name: sbom-filespath: reports/my-project-sbom.json| Name | Required | Default | Description |
|---|---|---|---|
python_version | No | 3.12 | Python version for SBOM generation |
include_dev | No | false | Include dev dependencies in SBOM |
sbom_format | No | both | SBOM format: 'json', 'xml', or 'both' |
sbom_spec_version | No | 1.5 | CycloneDX specification version |
filename_prefix | No | sbom-cyclonedx | Base filename for SBOM output |
path_prefix | No | . | Directory location containing project code |
output_directory | No | . | Directory location to write SBOM reports |
fail_on_error | No | true | Fail action if SBOM generation fails |
path_prefixvsoutput_directory: These parameters serve different purposes.path_prefixspecifies where your Python project source code is, whileoutput_directoryspecifies where the SBOM/report files get saved. This allows you to generate SBOMs from source code in one directory and write the reports to another location.filename_prefix: This parameter sets the base filename for SBOM outputs (without file extension). For example,filename_prefix: "my-app"will generatemy-app.jsonandmy-app.xmlfiles. The action automatically appends the appropriate extensions based on thesbom_formatsetting.
| Name | Description |
|---|---|
sbom_json_path | Full path to generated JSON SBOM file |
sbom_xml_path | Full path to generated XML SBOM file |
dependency_manager | Detected Python dependency manager |
component_count | Number of components found in the generated SBOM |
The action detects dependency management tools in the following priority order:
- uv -
uv.lockpresent - PDM -
pdm.lockpresent - Poetry -
poetry.lockpresent - Pipenv -
Pipfile.lockpresent - pip-tools -
requirements.txtwithrequirements.inor version pins - pip - Plain
requirements.txt(fallback)
| Tool | Lock File | Install Command | Dev Dependencies |
|---|---|---|---|
| uv | uv.lock | uv sync --locked [--no-dev] | Via include_dev |
| PDM | pdm.lock | pdm sync [--prod] --no-self | Via include_dev |
| Poetry | poetry.lock | poetry install --no-root | Via include_dev |
| Pipenv | Pipfile.lock | pipenv install --deploy | Via include_dev |
| pip-tools | requirements.txt | pip install -r requirements.txt | Via dev |
| pip | requirements.txt | pip install -r requirements.txt | Via dev |
# For projects with uv.lock
- name: "Generate SBOM (uv project)"uses: lfreleng-actions/python-sbom-action@v1with:
python_version: "3.12"include_dev: "false"# Excludes dev dependencies for production SBOM# For projects with pdm.lock
- name: "Generate SBOM (PDM project)"uses: lfreleng-actions/python-sbom-action@v1with:
python_version: "3.11"include_dev: "true"# Include dev dependenciessbom_format: "json"# JSON format for CI integration# For projects with poetry.lock
- name: "Generate SBOM (Poetry project)"uses: lfreleng-actions/python-sbom-action@v1with:
include_dev: "true"filename_prefix: "poetry-sbom"# For projects with Pipfile.lock
- name: "Generate SBOM (Pipenv project)"uses: lfreleng-actions/python-sbom-action@v1with:
sbom_spec_version: "1.6"fail_on_error: "false"# Continue on errors# For projects with requirements.txt + requirements.in
- name: "Generate SBOM (pip-tools project)"uses: lfreleng-actions/python-sbom-action@v1with:
include_dev: "true"# Will use requirements-dev.txt if present# For projects with requirements.txt files
- name: "Generate SBOM (pip project)"uses: lfreleng-actions/python-sbom-action@v1with:
fail_on_error: "false"# Recommended for pip projectsname: "SBOM with Path Prefix and Custom Output"on: [push]jobs:
sbom:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Generate SBOM for project in subdirectory"uses: lfreleng-actions/python-sbom-action@v1with:
path_prefix: "backend/api"# Where the source code isoutput_directory: "sbom-reports"# Where to write SBOM filesfilename_prefix: "api-sbom"# Creates api-sbom.jsonsbom_format: "json"
- name: "Upload SBOM"uses: actions/upload-artifact@v4with:
name: api-sbompath: sbom-reports/api-sbom.json# Different filename prefixes create different output files
- name: "Generate SBOMs with custom names"uses: lfreleng-actions/python-sbom-action@v1with:
filename_prefix: "my-app-v1.2.3"# Creates: my-app-v1.2.3.json, my-app-v1.2.3.xmlsbom_format: "both"
- name: "Generate timestamped SBOM"uses: lfreleng-actions/python-sbom-action@v1with:
filename_prefix: "sbom-${{ github.sha }}"# Creates: sbom-abc123def.jsonsbom_format: "json"name: "Multi-project SBOM"on: [push]jobs:
sbom:
runs-on: ubuntu-lateststrategy:
matrix:
project: [api, worker, dashboard, shared]steps:
- uses: actions/checkout@v4
- name: "Generate SBOM for ${{ matrix.project }}"id: sbomuses: lfreleng-actions/python-sbom-action@v1with:
path_prefix: "./${{ matrix.project }}"# Source code locationoutput_directory: "sbom-reports"# Centralized report locationfilename_prefix: "sbom-${{ matrix.project }}"include_dev: "false"
- name: "Upload ${{ matrix.project }} SBOM"uses: actions/upload-artifact@v4with:
name: sbom-${{ matrix.project }}path: sbom-reports/sbom-${{ matrix.project }}.*
- name: "Summary for ${{ matrix.project }}"run: | echo "Generated SBOM for ${{ matrix.project }}" echo "Tool: ${{ steps.sbom.outputs.dependency_manager }}" echo "Components: ${{ steps.sbom.outputs.component_count }}"name: "SBOM + Security Scan"on: [push]jobs:
security:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Generate SBOM"id: sbomuses: lfreleng-actions/python-sbom-action@v1with:
sbom_format: "json"include_dev: "false"output_directory: "security-reports"
- name: "Security scan with Grype"uses: anchore/scan-action@v3with:
path: "${{ steps.sbom.outputs.sbom_json_path }}"format: "cyclonedx-json"name: "Release with SBOM"on:
release:
types: [published]jobs:
sbom:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Generate production SBOM"uses: lfreleng-actions/python-sbom-action@v1with:
include_dev: "false"sbom_format: "both"sbom_spec_version: "1.6"output_directory: "release-artifacts"filename_prefix: "production-sbom"
- name: "Attach SBOM to release"uses: softprops/action-gh-release@v1with:
files: | release-artifacts/production-sbom.json release-artifacts/production-sbom.xmlname: "Weekly SBOM Update"on:
schedule:
- cron: "0 2 * * 1"# Monday 2 AM UTCworkflow_dispatch:
jobs:
sbom:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Generate weekly SBOM"id: sbomuses: lfreleng-actions/python-sbom-action@v1
- name: "Upload current SBOM"uses: actions/upload-artifact@v4with:
name: sbom-cyclonxpath: sbom-cyclonedx.*retention-days: 30- name: "Generate SBOM with error handling"id: sbomuses: lfreleng-actions/python-sbom-action@v1with:
fail_on_error: "false"continue-on-error: true
- name: "Handle SBOM generation failure"if: steps.sbom.outcome == 'failure'run: | echo "::warning::SBOM generation failed, continuing without SBOM" echo "SBOM generation failed" >> $GITHUB_STEP_SUMMARYname: "Conditional SBOM"on: [push, pull_request]jobs:
sbom:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- name: "Check for Python project"id: checkrun: | if [[ -f "pyproject.toml" || -f "requirements.txt" || \ -f "Pipfile" ]]; then echo "is_python=true" >> $GITHUB_OUTPUT else echo "is_python=false" >> $GITHUB_OUTPUT fi - name: "Generate SBOM"if: steps.check.outputs.is_python == 'true'uses: lfreleng-actions/python-sbom-action@v1with:
fail_on_error: "false"- Detection: Scans for supported dependency files in priority order
- Tool Setup: Installs the detected dependency management tool
- Dependency Installation: Installs dependencies according to lock files
- SBOM Generation: Uses CycloneDX Python library to generate SBOM from environment
- Validation: Validates generated SBOM files for correctness
- Outputs: Provides paths and metadata about generated files
The action uses the CycloneDX Python library to generate SBOMs by analyzing the Python environment after dependency installation. This approach ensures the SBOM accurately reflects the resolved dependency tree.
- Graceful Degradation: Can continue on errors when
fail_on_error: false - Comprehensive Logging: Detailed output for troubleshooting
- Validation: Built-in SBOM file validation with helpful error messages
- Ensure your project has one of the supported lock/requirements files
- Check that the file is in the
path_prefixdirectory specified
- Verify the Python version is compatible with your dependency manager
- Check if there are any conflicting system packages
- Ensure all dependencies install without errors
- Check for missing system dependencies required by Python packages
- Try with
fail_on_error: falseto get more diagnostic information
Set fail_on_error: false to enable verbose error handling and continue
execution when errors occur.
- name: "Generate SBOM (debug mode)"uses: lfreleng-actions/python-sbom-action@v1with:
fail_on_error: "false"env:
ACTIONS_STEP_DEBUG: trueRUNNER_DEBUG: 1# Good: Pin to specific versionuses: lfreleng-actions/python-sbom-action@v1.2.3# Better: Pin to commit SHA for securityuses: lfreleng-actions/python-sbom-action@a1b2c3d4...# Trigger on dependency changeson:
push:
paths:
- "pyproject.toml"
- "*.lock"
- "requirements*.txt"
- "Pipfile.lock"# Short retention for PR builds
- name: "Upload SBOM (PR)"if: github.event_name == 'pull_request'uses: actions/upload-artifact@v4with:
retention-days: 7# Longer retention for main branch
- name: "Upload SBOM (main)"if: github.ref == 'refs/heads/main'uses: actions/upload-artifact@v4with:
retention-days: 90# Organize SBOMs by environment/purpose
- name: "Generate production SBOM"uses: lfreleng-actions/python-sbom-action@v1with:
include_dev: "false"output_directory: "sbom/production"filename_prefix: "app-prod"
- name: "Generate development SBOM"uses: lfreleng-actions/python-sbom-action@v1with:
include_dev: "true"output_directory: "sbom/development"filename_prefix: "app-dev"jobs:
sbom:
runs-on: ubuntu-latesttimeout-minutes: 15# Reasonable timeoutsteps:
- name: "Generate SBOM"uses: lfreleng-actions/python-sbom-action@v1with:
python_version: "3.12"# Use latest stableContributions are welcome! Please see our contributing guidelines and code of conduct.
This project uses the Apache License 2.0. See the LICENSE file for details.
- CycloneDX Python - The underlying SBOM generation library
- SPDX SBOM Generator: Alternative SBOM format
- Syft - Container and filesystem SBOM generator