Skip to main content

SBOM conversion mapping

When a workflow reads an SBOM, it converts it into the canonical format; when it writes one, it converts back. This page documents how the fields correspond and what to expect from a round trip.

Useful when you need to explain why an exported SBOM is not byte-identical to the one that went in, or where a particular field ended up.

The structural idea

Different formats model components differently. The canonical format reduces them all to a flat list of elements plus a flat list of relationships, and the converters do the reshaping.

Source conceptCanonical representation
SPDX packages[], files[], snippets[]One elements[] array, tagged PACKAGE / FILE / SNIPPET
CycloneDX components, services, toolselements[] tagged PACKAGE / APPLICATION / FRAMEWORK / SERVICE / TOOL
CycloneDX metadata.componentAn element, plus a DESCRIBES relationship from the document
CycloneDX nested componentsFlattened into CONTAINS relationships
CycloneDX dependencies[]Flattened into DEPENDS_ON relationships
SPDX relationships[]Passed through nearly one to one
External and cross-referencesConsolidated into document-level references[]
SPDX extractedLicensingInfo, CycloneDX named licensescustomLicenses[]

Element types

CycloneDX typeCanonical typeSPDX equivalent
libraryPACKAGEpackages[]
applicationAPPLICATIONpackages[] on export
framework, containerFRAMEWORKpackages[] on export
fileFILEfiles[]
serviceSERVICEpackages[] on export
from metadata.toolsTOOLcreator or packages[]
SNIPPETsnippets[]

Exporting to SPDX turns every package-like type back into packages[]; only FILE and SNIPPET become SPDX files and snippets.

CycloneDX

Document level

CycloneDXCanonicalNotes
serialNumberidThe urn:uuid: prefix is stripped on the way in and restored on the way out.
metadata.component.namenameFalls back to the document id when there is no metadata component.
versionversion
specVersionformatRecorded as CycloneDX-<specVersion>.
metadata.timestampcreated
metadata.tools[]creators[] and TOOL elementsSurfaced both ways.
vulnerabilities[]vulnerabilities[]

Components

CycloneDXCanonical elementNotes
bom-refid
name, version, descriptionSame
typetypelibraryPACKAGE, containerFRAMEWORK; anything unrecognized becomes library on export.
purl, cpe, copyrightSame
hashes[]checksums[]Algorithm names normalized, e.g. SHA_512SHA-512.
licenses[]licensesConcluded[]Expressions are kept as expressions; unknown names become custom licenses.
suppliersupplier, plus a supplier participant
author, publisherAuthor and publisher participants
swidswid
group, scope, pedigree.notesproperties[]Restored on export.
externalReferences[]Document-level references[]Each tagged with the component it belongs to.

SPDX

Document level

SPDXCanonical
creationInfo.spdxVersionformat and version
SPDXIDid
namename
documentNamespacenamespace
creationInfo.creatorscreators[] — actor type becomes PERSON, ORG, or TOOL
creationInfo.createdcreated
dataLicenselicense
creationInfo.licenseListVersionlicenseNamespace
externalDocumentRefsreferences[]

Packages

SPDXCanonical elementNotes
SPDXIDidRewritten to a valid SPDXRef-… on export.
name, versionInfoname, version
filesAnalyzedgranularitytrueFILE, falseNONE.
downloadLocationdownload
packageFileNamefile
supplier, originatorSameNOASSERTION and NONE are dropped.
checksums[]checksums[]
packageVerificationCodeA synthetic checksum entrySplit back out on export.
homepage, sourceInfohome, origin
licenseConcludedlicensesConcluded[]Joined into a single expression on export.
licenseDeclaredlicenseDeclared
licenseInfoFromFileslicenseFromFiles[]
licenseCommentslicenseComment
copyrightTextcopyright
summary, description, commentSame
attributionTextsattribution[]
primaryPackagePurposepurposeSPDX 2.3 only.
releaseDate, builtDate, validUntilDatereleased, built, expirationSPDX 2.3 only.

Files, snippets, and the rest

SPDXCanonical
File SPDXIDElement id with type FILE
fileTypes[]types[]
fileContributorscontributors[]
noticeTextnotice
Snippet snippetFromFilefile, with type SNIPPET
Snippet byte and line rangesrange.characters, range.lines
relationships[]relationships[] (from, to, type)
annotations[]annotations[]
extractedLicensingInfo[]customLicenses[]

What to expect from a round trip

A conversion out and back preserves content faithfully, but not always byte-for-byte. Specifically:

  • Identifiers may change. Exporting to SPDX rewrites every id to a valid SPDXRef-…. CycloneDX preserves bom-ref.
  • Structure may be reshaped. Roots are inferred rather than stored, nesting is rebuilt from relationships, and dependency references pointing at things that are not emitted as CycloneDX components are dropped so the output stays valid.
  • Licenses are parsed, not copied. Compound and comma-separated license names are turned into SPDX expressions, exceptions are joined with WITH, and anything unrecognized becomes a custom license reference.
  • Targeting an older version drops newer fields. Emitting SPDX 2.2 removes 2.3-only fields and fills mandatory license and copyright fields with NOASSERTION where they are absent.