- 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)
One SBOM per board target, always generated as part of every build.
- Each of the 60+ board targets gets its own
sbom.spdx.jsonin its build directory, reflecting exactly which components are compiled into that firmware variant. - SBOM generation is part of the default CMake build (
ALLtarget). Everymake px4_fmu-v6x_defaultautomatically producesbuild/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.jsonalongside.px4files. 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 packageCONTAINS: PX4 firmware contains submodules and internal modulesBUILD_DEPENDENCY_OF: Python packages are build dependencies of PX4
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
- Add a section or link pointing to
sbom.mdfor machine-readable license data
- Add
sbom.mdentry under the Contribute section
- Parse
.gitmodulesfor submodule name, path, URL - Run
git ls-tree HEADfor commit hashes (works even with uninitialized submodules) - Parse
Tools/setup/requirements.txtfor Python deps - Hardcoded
SUBMODULE_LICENSESdict mapping submodule path to SPDX license identifier - Accept
--modules-filefor board-specific module list - Accept
--board,--compiler,--outputflags - Output valid SPDX 2.3 JSON with:
spdxVersion: "SPDX-2.3"dataLicense: "CC0-1.0"documentNamespaceusing UUID5 from git hash + board (deterministic/reproducible)- PX4 as primary package with
primaryPackagePurpose: FIRMWARE - Submodules as packages with
CONTAINSrelationships - Python deps as packages with
BUILD_DEPENDENCY_OFrelationships - Board-specific modules as packages with
CONTAINSrelationships filesAnalyzed: falseon all packages (skip file-level entries)externalRefwith Package URLs (purls) for each component
- Zero external dependencies (stdlib only)
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_listto${PX4_BINARY_DIR}/config_module_list.txt add_custom_commandproducing${PX4_BINARY_DIR}/sbom.spdx.jsonadd_custom_target(sbom ALL ...)-- part of default build
- Write
- When OFF: no targets created, zero overhead
- Add
include(sbom)after existinginclude(metadata)(~line 486)
- Copy
sbom.spdx.jsoninto artifact directory alongside.px4files
- Add
**/*.spdx.jsonto GitHub Release upload glob - Add S3 upload path for SBOMs alongside firmware
- 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 - Create
cmake/sbom.cmake+ addinclude(sbom)to root CMakeLists.txt - Test:
make px4_sitl_default(SBOM generated automatically), verifybuild/px4_sitl_default/sbom.spdx.json - Test disable:
PX4_SBOM_DISABLE=1 make px4_sitl_default(no SBOM generated) - Update
package_build_artifacts.shto include SBOM in artifacts - Update workflow YAML for release uploads
- Create
docs/en/contribute/sbom.mddocumentation page - Update
docs/en/contribute/licenses.md,_sidebar.md,SUMMARY.mdwith links
- Always-on by default: SBOMs are part of the build, not a CI afterthought. Disable with
PX4_SBOM_DISABLE=1env var. - No CI script changes for generation:
build_all_runner.shis 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.8recorded verbatim (not resolved) filesAnalyzed: false: Package-level only. Can add file-level entries later for deeper compliance.
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:).
# 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