Skip to content

Instantly share code, notes, and snippets.

@mrpollo
Last active March 12, 2026 19:17
Show Gist options
  • Select an option

  • Save mrpollo/15c1ba66a448e5cfa372c1349ecb97b8 to your computer and use it in GitHub Desktop.

Select an option

Save mrpollo/15c1ba66a448e5cfa372c1349ecb97b8 to your computer and use it in GitHub Desktop.
PX4-Autopilot SBOM Generation Plan

Plan: SBOM Generation for PX4-Autopilot

Format: SPDX 2.3 JSON

  • ISO standard (ISO/IEC 5962), aligns with Linux Foundation/Dronecode ecosystem
  • Zephyr RTOS (sibling LF project) uses SPDX, creating ecosystem consistency
  • SPDX License List identifiers already used in PX4 source headers
  • EU CRA compliance ready (reporting obligations start Sep 2026)
  • Construct JSON directly with stdlib (no pip dependency added to build chain)

What gets produced

One SBOM per board target, always generated as part of every build.

  • Each of the 60+ board targets gets its own sbom.spdx.json in its build directory, reflecting exactly which components are compiled into that firmware variant.
  • SBOM generation is part of the default CMake build (ALL target). Every make px4_fmu-v6x_default automatically produces build/px4_fmu-v6x_default/sbom.spdx.json.
  • Disable via env var: PX4_SBOM_DISABLE=1 make px4_sitl_default
  • Generation is fast (~2 seconds): just git queries + JSON construction. No measurable impact on build times.
  • On release tags, the existing artifact packaging and upload pipeline picks up sbom.spdx.json alongside .px4 files. No special CI logic needed.

Content depth: package-level only.

Each SBOM lists components with: name, version (commit hash or version spec), SPDX license identifier, supplier, download URL, and Package URL (purl). No individual source file entries (filesAnalyzed: false). Approximately 500 lines / 20 KB of JSON per board.

Expected component count per SBOM:

  • 1 primary package: PX4 firmware for the specific board
  • ~33 packages: git submodules (exact count depends on board; some submodules like simulation tools are not included in hardware targets)
  • ~31 packages: Python build dependencies from requirements.txt
  • Variable: PX4 internal modules/drivers enabled for the board (from config_module_list)
  • Total: ~70-100 packages per board SBOM

Relationships:

  • DESCRIBES: document describes the PX4 firmware package
  • CONTAINS: PX4 firmware contains submodules and internal modules
  • BUILD_DEPENDENCY_OF: Python packages are build dependencies of PX4

Documentation

6. docs/en/contribute/sbom.md (new page)

Documents for developers and integrators:

  • What is an SBOM and why PX4 generates them
  • Format: SPDX 2.3 JSON, what each field means
  • How SBOMs are generated (part of every build, CMake target)
  • Where to find them: build/<target>/sbom.spdx.json, GitHub Releases, S3
  • How to disable: PX4_SBOM_DISABLE=1
  • What to expect: ~70-100 packages per board, package-level only, no file entries
  • How to validate: JSON schema check, NTIA conformance checker
  • How to update the license map when adding/removing submodules
  • Regulatory context: NTIA/CISA minimum elements, EU CRA timeline

7. docs/en/contribute/licenses.md (existing, add reference)

  • Add a section or link pointing to sbom.md for machine-readable license data

8. docs/en/_sidebar.md and docs/en/SUMMARY.md

  • Add sbom.md entry under the Contribute section

Files to Create

1. Tools/ci/generate_sbom.py (~350 lines)

  • Parse .gitmodules for submodule name, path, URL
  • Run git ls-tree HEAD for commit hashes (works even with uninitialized submodules)
  • Parse Tools/setup/requirements.txt for Python deps
  • Hardcoded SUBMODULE_LICENSES dict mapping submodule path to SPDX license identifier
  • Accept --modules-file for board-specific module list
  • Accept --board, --compiler, --output flags
  • Output valid SPDX 2.3 JSON with:
    • spdxVersion: "SPDX-2.3"
    • dataLicense: "CC0-1.0"
    • documentNamespace using UUID5 from git hash + board (deterministic/reproducible)
    • PX4 as primary package with primaryPackagePurpose: FIRMWARE
    • Submodules as packages with CONTAINS relationships
    • Python deps as packages with BUILD_DEPENDENCY_OF relationships
    • Board-specific modules as packages with CONTAINS relationships
    • filesAnalyzed: false on all packages (skip file-level entries)
    • externalRef with Package URLs (purls) for each component
  • Zero external dependencies (stdlib only)

2. cmake/sbom.cmake (~40 lines)

  • option(GENERATE_SBOM "Generate SPDX SBOM" ON) -- defaults to ON
  • Check ENV{PX4_SBOM_DISABLE}: if set, override option to OFF
  • When ON:
    • Write config_module_list to ${PX4_BINARY_DIR}/config_module_list.txt
    • add_custom_command producing ${PX4_BINARY_DIR}/sbom.spdx.json
    • add_custom_target(sbom ALL ...) -- part of default build
  • When OFF: no targets created, zero overhead

Files to Modify

3. CMakeLists.txt

  • Add include(sbom) after existing include(metadata) (~line 486)

4. Tools/ci/package_build_artifacts.sh

  • Copy sbom.spdx.json into artifact directory alongside .px4 files

5. .github/workflows/build_all_targets.yml

  • Add **/*.spdx.json to GitHub Release upload glob
  • Add S3 upload path for SBOMs alongside firmware

Implementation Order

  1. Create Tools/ci/generate_sbom.py -- test standalone: python3 Tools/ci/generate_sbom.py --source-dir . --board px4_sitl_default --output /tmp/sbom.spdx.json
  2. Create cmake/sbom.cmake + add include(sbom) to root CMakeLists.txt
  3. Test: make px4_sitl_default (SBOM generated automatically), verify build/px4_sitl_default/sbom.spdx.json
  4. Test disable: PX4_SBOM_DISABLE=1 make px4_sitl_default (no SBOM generated)
  5. Update package_build_artifacts.sh to include SBOM in artifacts
  6. Update workflow YAML for release uploads
  7. Create docs/en/contribute/sbom.md documentation page
  8. Update docs/en/contribute/licenses.md, _sidebar.md, SUMMARY.md with links

Key Design Decisions

  • Always-on by default: SBOMs are part of the build, not a CI afterthought. Disable with PX4_SBOM_DISABLE=1 env var.
  • No CI script changes for generation: build_all_runner.sh is untouched. SBOM is a CMake build artifact like any other.
  • SPDX 2.3 over 3.0: 3.0 tooling is still experimental; 2.3 is stable and widely supported. Upgrade path is clear when 3.0 matures (~2027).
  • SPDX over CycloneDX: LF ecosystem alignment, license compliance strength, Zephyr consistency, ISO standard status, CRA readiness.
  • One per board target: Each firmware variant includes different components. Per-board SBOMs are accurate for compliance.
  • No new pip dependencies: SPDX 2.3 JSON is simple enough to construct with dicts + json.dumps
  • Hardcoded license map: More reliable than auto-detection for 33 known submodules; warns on unmapped entries
  • Version ranges kept as-is: requirements.txt specs like jinja2>=2.8 recorded verbatim (not resolved)
  • filesAnalyzed: false: Package-level only. Can add file-level entries later for deeper compliance.

NTIA/CISA Minimum Elements Coverage

All 7 NTIA fields mapped: Supplier (PackageSupplier), Component Name (PackageName), Version (PackageVersion), Unique ID (DocumentNamespace+SPDXID), Dependency Relationship (Relationship), Author (Creator), Timestamp (Created). Plus CISA 2025 additions: Hash (PackageChecksum), License (LicenseDeclared), Tool (Creator: Tool:).

Verification

# Build includes SBOM automatically:
make px4_sitl_default
cat build/px4_sitl_default/sbom.spdx.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{len(d[\"packages\"])} packages, {len(d[\"relationships\"])} relationships'); assert d['spdxVersion']=='SPDX-2.3'"

# Disable:
PX4_SBOM_DISABLE=1 make px4_sitl_default
# build/px4_sitl_default/sbom.spdx.json should not exist
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment