Testland
Browse all skills & agents

spdx-format

Reference for the SPDX (Software Package Data Exchange) v2.3 + v3.0 SBOM specification - Linux Foundation-curated, license-focused format covering packages, files, snippets, relationships, license declarations, and (in 3.0) AI / dataset / build / security profiles; supports Tag-Value / JSON / YAML / RDF / Spreadsheet encodings; preferred by US Federal procurement (NIST guidance) and Linux distros. Use when the team's SBOM consumer requires SPDX format (federal procurement, Linux Foundation members, license-compliance focus).

spdx-format

Overview

SPDX is the Linux Foundation's SBOM standard, originally focused on license compliance. Per spdx.org/specifications:

Two active major versions:

VersionStatusNotable
SPDX 2.3Stable; broadly tooledTag-Value / JSON / YAML / RDF / Spreadsheet; ISO/IEC 5962:2021
SPDX 3.0Recent (2024); growing toolingProfile-based: core + software + AI + dataset + build + security; JSON-LD primary

This is a reference skill - defines the schema + tooling landscape; doesn't run scans. Pair with syft-generation to generate SPDX-format SBOMs.

When to use

  • US Federal procurement context (NIST SP 800-218 + EO 14028 guidance favor SPDX).
  • Linux Foundation member organization workflow.
  • License-compliance focused use case (SPDX has the richest license-expression vocabulary).
  • A consumer (regulator, customer) requires SPDX format specifically.

For security-focused use cases, cyclonedx-format has richer first-class vuln support.

Step 1 - SPDX 2.3 top-level structure (JSON)

{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "my-app-1.0.0-sbom",
  "documentNamespace": "https://example.com/spdx/my-app/1.0.0",
  "creationInfo": {
    "created": "2026-05-06T12:00:00Z",
    "creators": ["Tool: syft-1.16.0", "Organization: Acme Corp"]
  },
  "packages": [
    {
      "SPDXID": "SPDXRef-Package-myapp",
      "name": "my-app",
      "versionInfo": "1.0.0",
      "downloadLocation": "NOASSERTION",
      "filesAnalyzed": false,
      "licenseConcluded": "Apache-2.0",
      "licenseDeclared": "Apache-2.0"
    },
    {
      "SPDXID": "SPDXRef-Package-lodash",
      "name": "lodash",
      "versionInfo": "4.17.20",
      "downloadLocation": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
      "filesAnalyzed": false,
      "licenseConcluded": "MIT",
      "licenseDeclared": "MIT"
    }
  ],
  "relationships": [
    {
      "spdxElementId": "SPDXRef-DOCUMENT",
      "relationshipType": "DESCRIBES",
      "relatedSpdxElement": "SPDXRef-Package-myapp"
    },
    {
      "spdxElementId": "SPDXRef-Package-myapp",
      "relationshipType": "DEPENDS_ON",
      "relatedSpdxElement": "SPDXRef-Package-lodash"
    }
  ]
}

Step 2 - Required fields per SPDX 2.3

Per spdx-spec:

FieldRequired?Use
spdxVersionyesMust be "SPDX-2.3"
dataLicenseyes"CC0-1.0" (CC0 - the SBOM data itself)
SPDXIDyes"SPDXRef-DOCUMENT"
nameyesHuman-readable doc name
documentNamespaceyesUnique URI per BOM revision
creationInfo.createdyesISO 8601 timestamp
creationInfo.creatorsyesTool / org / person who created
packages[]required for non-empty BOMInventory
relationships[]required (at least DESCRIBES)Dep graph

Step 3 - License expressions

SPDX is the canonical source for license identifiers (cross-format standard - even CycloneDX uses SPDX license IDs).

"licenseConcluded": "Apache-2.0",
"licenseConcluded": "MIT OR Apache-2.0",
"licenseConcluded": "(MIT AND BSD-3-Clause) OR GPL-2.0-only WITH Classpath-exception-2.0"

Full list: spdx.org/licenses (current count ~600+).

The LicenseRef- prefix declares custom licenses:

"hasExtractedLicensingInfos": [{
  "licenseId": "LicenseRef-AcmeProprietary",
  "extractedText": "Acme Proprietary License Text..."
}],
"licenseConcluded": "LicenseRef-AcmeProprietary"

Step 4 - Relationships

The relationships[] block is the dep-graph (SPDX equivalent of CycloneDX's dependencies[]):

RelationshipTypeUse
DESCRIBES / DESCRIBED_BYDocument ↔ top-level package
DEPENDS_ON / DEPENDENCY_OFCompile-time / runtime dep
BUILD_DEPENDENCY_OFBuild-only dep
DEV_DEPENDENCY_OFTest/dev-only dep
RUNTIME_DEPENDENCY_OFRuntime-only dep
OPTIONAL_DEPENDENCY_OFOptional dep
CONTAINS / CONTAINED_BYContainer ↔ contained file/package
GENERATED_FROMSource-of-build
STATIC_LINK / DYNAMIC_LINKLinkage type

Step 5 - Tag-Value format (SPDX-native)

Some toolchains use the SPDX Tag-Value format (older but well-tooled):

SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: my-app-1.0.0-sbom
DocumentNamespace: https://example.com/spdx/my-app/1.0.0
Creator: Tool: syft-1.16.0
Creator: Organization: Acme Corp
Created: 2026-05-06T12:00:00Z

PackageName: my-app
SPDXID: SPDXRef-Package-myapp
PackageVersion: 1.0.0
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageLicenseConcluded: Apache-2.0
PackageLicenseDeclared: Apache-2.0

Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-myapp

JSON is preferred for new toolchains; Tag-Value persists for legacy integrations.

Step 6 - SPDX 3.0 profiles

SPDX 3.0 (2024 release) restructures into composable profiles:

ProfileUse
coreMinimum BOM model
softwareSoftware-specific extensions (≈ SPDX 2.3 packages)
licensingLicense identification + expressions
securityVulnerability + VEX statements
aiAI/ML models, datasets, hyperparameters
datasetDataset-specific metadata
buildBuild provenance (similar to in-toto attestations)

JSON-LD is the primary encoding; tooling support is growing but less mature than 2.3 as of 2026.

For most teams, stay on SPDX 2.3 unless 3.0 features are required - 2.3 has broader tooling.

Step 7 - Tooling

ToolUse
syftGenerates SPDX 2.3 (JSON / Tag-Value); cross-source
spdx-toolsReference impl (Python); validation + conversion
spdx-tools-javaJava reference impl
ORT (OSS Review Toolkit)License compliance scanning + SPDX reporting
spdx-sbom-generatorPer-language native generation
ternContainer image SPDX generation
TrivyCross-purpose scanner with SPDX output

Step 8 - Validation

# Python spdx-tools
pip install spdx-tools
pyspdxtools --infile sbom.spdx.json --version SPDX-2.3
# Validates structural conformance + license-expression syntax

# Validation via spdx online tool
# Upload to https://tools.spdx.org/app/

Step 9 - CI integration

jobs:
  spdx:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: anchore/sbom-action@v0
        with:
          format: spdx-json
          output-file: sbom.spdx.json
      - run: |
          pip install spdx-tools
          pyspdxtools --infile sbom.spdx.json --version SPDX-2.3
      - uses: actions/upload-artifact@v4
        with:
          name: spdx-sbom
          path: sbom.spdx.json

Anti-patterns

Anti-patternWhy it failsFix
Skip documentNamespaceCan't deduplicate across BOM revisionsGenerate unique URI per BOM
Use SPDX 3.0 with consumer expecting 2.3Tooling incompatStick to SPDX 2.3 unless 3.0 required (Step 6)
Manual license assignment without LicenseRef- for customLicense-expression validation failsUse proper SPDX license ID or LicenseRef- (Step 3)
Skip relationships[] (just packages)No dep-graph; downstream tools degradeAlways include DESCRIBES + DEPENDS_ON (Step 4)
Mix Tag-Value + JSON in same workflowToolchain confusionPick one format per workflow (Step 5)

Limitations

  • SPDX 2.3 vuln support is weaker than CycloneDX 1.6 (no first-class vulnerabilities block - relies on companion VEX docs).
  • License-expression validation is strict; non-standard licenses require LicenseRef- boilerplate.
  • SPDX 3.0 tooling is still maturing; many tools still produce 2.3.
  • Tag-Value parsing is whitespace-sensitive; subtle formatting bugs.

References