SPDX 3.0 for Embedded Builds: Packages, Files, and Relationships Engineers Actually Use

Practical guide to SPDX 3.0 for embedded Linux, covering the data model, package and file elements, relationship types, and how to produce useful SPDX documents from Yocto and Buildroot builds.

Digital Ocean free trial – Cloud VPS Solutions
SPDX 3.0 for Embedded Builds: Packages, Files, and Relationships Engineers Actually Use

SPDX 3.0 is a significant revision of the Software Package Data Exchange standard. For embedded Linux engineers, the relevant changes are a new data model, a richer relationship system, and profiles for build provenance and security. This guide focuses on the parts of SPDX 3.0 that matter for embedded builds—skip the spec language and see what the documents actually look like.

SPDX 3.0 data model

SPDX 3.0 uses an element-based model. Everything is an "Element" with a unique identifier (SPDX ID). The main element types:

  • Package: A software component (e.g., "busybox 1.36.1")
  • File: An individual file within a package
  • Snippet: A portion of a file (rarely used in embedded)
  • Relationship: A typed link between two elements
  • Annotation: A comment or review note on any element

JSON-LD serialization

SPDX 3.0 uses JSON-LD as its primary serialization. A minimal document:

{
  "@context": "https://spdx.org/rdf/3.0.0/spdx-context.jsonld",
  "@graph": [
    {
      "type": "SpdxDocument",
      "spdxId": "urn:spdx:doc-firmware-v2.1.0",
      "name": "firmware-v2.1.0-sbom",
      "creationInfo": {
        "created": "2026-03-15T11:00:00Z",
        "createdBy": ["urn:spdx:agent-build-system"],
        "specVersion": "3.0.0"
      },
      "rootElement": ["urn:spdx:pkg-firmware-image"]
    },
    {
      "type": "software_Package",
      "spdxId": "urn:spdx:pkg-firmware-image",
      "name": "firmware-image",
      "software_packageVersion": "2.1.0",
      "software_downloadLocation": "https://releases.example.com/v2.1.0/",
      "software_primaryPurpose": "install"
    }
  ]
}

Packages in embedded context

Source packages

The upstream source as fetched by the build system:

{
  "type": "software_Package",
  "spdxId": "urn:spdx:pkg-busybox-src",
  "name": "busybox",
  "software_packageVersion": "1.36.1",
  "software_downloadLocation": "https://busybox.net/downloads/busybox-1.36.1.tar.bz2",
  "software_primaryPurpose": "source",
  "software_declaredLicense": "GPL-2.0-only"
}

Built packages

The compiled output installed into the rootfs:

{
  "type": "software_Package",
  "spdxId": "urn:spdx:pkg-busybox-bin",
  "name": "busybox",
  "software_packageVersion": "1.36.1",
  "software_primaryPurpose": "install",
  "software_declaredLicense": "GPL-2.0-only"
}

The firmware image

The top-level artifact:

{
  "type": "software_Package",
  "spdxId": "urn:spdx:pkg-firmware-image",
  "name": "firmware-image",
  "software_packageVersion": "2.1.0",
  "software_primaryPurpose": "install",
  "verifiedUsing": [{
    "type": "Hash",
    "algorithm": "sha256",
    "hashValue": "a1b2c3d4..."
  }]
}

Relationships engineers use

Relationships are the most useful part of SPDX for embedded builds. They describe how components relate to each other.

CONTAINS

The firmware image contains packages:

{
  "type": "Relationship",
  "spdxId": "urn:spdx:rel-001",
  "from": "urn:spdx:pkg-firmware-image",
  "relationshipType": "contains",
  "to": ["urn:spdx:pkg-busybox-bin", "urn:spdx:pkg-openssl-bin"]
}

BUILD_TOOL_OF

The toolchain that built a package:

{
  "type": "Relationship",
  "spdxId": "urn:spdx:rel-002",
  "from": "urn:spdx:pkg-gcc-aarch64",
  "relationshipType": "buildToolOf",
  "to": ["urn:spdx:pkg-busybox-bin"]
}

GENERATED_FROM

Binary package generated from source:

{
  "type": "Relationship",
  "spdxId": "urn:spdx:rel-003",
  "from": "urn:spdx:pkg-busybox-bin",
  "relationshipType": "generatedFrom",
  "to": ["urn:spdx:pkg-busybox-src"]
}

DEPENDS_ON

Runtime dependencies:

{
  "type": "Relationship",
  "spdxId": "urn:spdx:rel-004",
  "from": "urn:spdx:pkg-myapp-bin",
  "relationshipType": "dependsOn",
  "to": ["urn:spdx:pkg-libc-bin", "urn:spdx:pkg-openssl-bin"]
}

Files within packages

For detailed auditing, list individual files within packages:

{
  "type": "software_File",
  "spdxId": "urn:spdx:file-busybox-binary",
  "name": "/usr/bin/busybox",
  "verifiedUsing": [{
    "type": "Hash",
    "algorithm": "sha256",
    "hashValue": "e5f6a7b8..."
  }],
  "software_filePurpose": ["executable"]
}

For embedded images with thousands of files, include file-level detail for key binaries (executables, shared libraries) and list the rest at the package level.

Build profile (SPDX 3.0)

The Build profile captures how artifacts were produced. This is the SPDX-native equivalent of SLSA provenance:

{
  "type": "build_Build",
  "spdxId": "urn:spdx:build-001",
  "build_buildType": "https://yoctoproject.org/build/v1",
  "build_configSourceUri": ["https://git.example.com/layers.git"],
  "build_parameters": {
    "MACHINE": "product-board",
    "DISTRO": "poky"
  },
  "build_buildStartTime": "2026-03-15T10:00:00Z",
  "build_buildEndTime": "2026-03-15T11:23:00Z"
}

Link it to the output:

{
  "type": "Relationship",
  "from": "urn:spdx:build-001",
  "relationshipType": "generates",
  "to": ["urn:spdx:pkg-firmware-image"]
}

The SLSA provenance guide covers the in-toto format alternative for build provenance.

Security profile (VEX in SPDX)

SPDX 3.0's Security profile can express VEX statements inline:

{
  "type": "security_VexAffectedVulnAssessmentRelationship",
  "spdxId": "urn:spdx:vex-001",
  "security_assessedElement": "urn:spdx:pkg-openssl-bin",
  "security_publishedTime": "2026-03-20T00:00:00Z",
  "security_vexVersion": "1",
  "from": "urn:spdx:vuln-cve-2026-1234",
  "relationshipType": "affects",
  "security_actionStatement": "Update to OpenSSL 3.2.2"
}

Or for "not affected":

{
  "type": "security_VexNotAffectedVulnAssessmentRelationship",
  "spdxId": "urn:spdx:vex-002",
  "security_assessedElement": "urn:spdx:pkg-libxml2-bin",
  "from": "urn:spdx:vuln-cve-2026-5678",
  "relationshipType": "doesNotAffect",
  "security_justificationType": "vulnerableCodeNotPresent",
  "security_impactStatement": "XPath support not compiled into this build"
}

The VEX guide covers VEX workflows in detail.

Generating SPDX 3.0 from Yocto

Yocto 5.2 generates SPDX 3.0 natively. Enable it:

INHERIT += "create-spdx"
SPDX_VERSION = "3.0"

The output appears in tmp/deploy/spdx/ with per-recipe and per-image documents.

For earlier Yocto versions, generate SPDX 2.3 and convert with the SPDX tools:

spdx-convert --from spdx2 --to spdx3 sbom-2.3.json > sbom-3.0.json

Practical tips

  1. Start simple: Package-level SPDX with CONTAINS relationships is sufficient for regulatory compliance. Add file-level detail and build profiles incrementally.
  2. Automate everything: SBOM generation must be part of CI, not a manual step. Manual SBOMs become stale immediately.
  3. Validate before publishing: Run the SPDX validator on every generated document. A syntactically invalid SBOM is worse than no SBOM.
  4. Keep SPDX IDs stable: Use deterministic ID generation (based on package name + version) so IDs are consistent across builds. This allows tools to diff SBOMs between releases.
  5. Store alongside releases: Archive SBOMs with the same retention policy as firmware binaries (minimum 5 years for CRA compliance).

Integration with ProteanOS

ProteanOS's package control files contain the metadata needed for SPDX Package elements: name, version, license, upstream source URL, and dependencies. The ProKit build tools can generate SPDX 3.0 documents from these control files as part of the build process.

For compliance documentation, the CRA evidence pack guide shows where SPDX documents fit into the broader evidence package, and the firmware SBOM comparison helps choose between SPDX and CycloneDX.

Summary

SPDX 3.0 is the most comprehensive SBOM format available for embedded Linux in 2026. The new data model, build profile, and security profile address real needs for firmware teams. Start with packages and CONTAINS relationships, automate generation in CI, and add build provenance and VEX data as your compliance requirements demand. The tooling is ready; the regulation requires it; the time to implement is now.