A supplier's SPDX BOM declares a compound license expression; your ingestion stores one license name — what breaks?
answer
- it parses, it is not a label
- and, or, with, plus
- the choice is the licensor's to offer
- an exception is not decoration
- both formats carry the string fine
basics
~20 sAn SPDX license expression is a grammar, not a label: AND means all apply, OR means a choice, WITH attaches an exception. Storing one name picks a branch and drops the exception, so your record no longer matches the supplier's.
solid answer
~50 sSPDX license expressions have syntax. `AND` means every named license applies together, `OR` means the recipient may choose between them, `WITH` attaches a named exception to a license, and a trailing `+` means that version or a later one. A supplier of an embedded control unit may ship a component declared as one license with an exception, or that license, and the exception is the whole reason the component is usable in that product. If ingestion normalises the expression into a single license-name column, the choice collapses to whichever branch the parser saw first and the exception vanishes. The failure is not really a format gap — both SPDX and CycloneDX can carry the expression verbatim, since CycloneDX licenses entries accept either a license object or an `expression` string. The loss happens in the consumer's data model, which is where the fix belongs too.
code
json · 7 lines{ "licenses": [
{ "expression": "GPL-2.0-only WITH Classpath-exception-2.0 OR Apache-2.0" }
] }
...
{ "licenses": [
{ "license": { "name": "GPL-2.0-only" } }
] }go deeper
Recognise that a licensing field in an SBOM can hold an expression with operators rather than a single name, and that it should be stored as received.
Explain what AND, OR, WITH and the plus suffix each mean, and why flattening an expression into one name changes the statement rather than shortening it.
Show that you would model the supplier's declared expression, your parsed form and any selection as three separate fields, so the record of who claimed what survives.
Frame it as evidence integrity across a supplier estate: the ingestion schema decides whether you can still prove, years later, what a supplier stated at delivery time.
## An expression is a grammar The most common misreading of an SBOM licensing field is that it holds a label. It does not: SPDX defines a **license expression** language, and expressions built with it are what both SPDX and CycloneDX documents carry. The pieces are small and worth knowing exactly: - A **license identifier** from the SPDX License List, a short stable string naming one specific set of terms. - **`AND`** — every named license applies simultaneously. A recipient must satisfy all of them. - **`OR`** — the recipient may choose which of the named licenses to take the component under. This is a genuine choice offered by the licensor, not an ambiguity in the document. - **`WITH`** — attaches a named exception to a license, producing terms that are the license as modified by the exception. - **`+`** — a suffix meaning that version of the license or a later one. - **`LicenseRef-` identifiers** — used when the terms are not on the SPDX License List; the document itself carries the extracted text under that reference. - Parentheses, which matter as soon as `AND` and `OR` appear together. Read as a grammar, `A WITH E OR B` is a precise statement. Read as a label, it is a long string that a naive importer will truncate, split on the first space, or map to its best-matching known license name. ## The collapse, and why it is a security-adjacent problem Consider a supplier delivering an electronic control unit for a vehicle, sending an SPDX document in which one component's terms are expressed as a license with an exception, or an alternative license. The customer's pipeline ingests it into an internal inventory whose schema has one license-name column per component. Three things happen at once: 1. The `OR` branch is decided by the parser rather than by anyone with authority to decide it. 2. The `WITH` exception is discarded, so the stored terms are strictly different from the terms declared. 3. Nothing errors. The row looks populated and confident. Months later, the customer's record of what the supplier said and the supplier's actual signed statement disagree, and there is no artifact that shows where they diverged. That is an audit-truth failure: the record of a claim has been quietly rewritten by an ingestion step, in a product line where the physical process the software controls makes any surprise expensive. Which legal obligations follow from any given expression is a question for counsel and is outside the scope here; the engineering defect is that the document no longer says what the supplier said. ## Both formats can carry it — the consumer is the problem This is the point that separates a good answer from a rote one. It is tempting to file this under *format incompatibility*, but: - SPDX defined the expression language and uses it in its declared and concluded license fields. - CycloneDX `licenses` entries accept **either** a license object with an identifier or name, **or** an `expression` string holding an SPDX expression. So an expression can travel from one format to the other intact. The loss almost always occurs at the boundary where a pipeline flattens a document into rows — a spreadsheet, a table with a `license` column, a dashboard that groups by license name. The fix therefore belongs in the consumer's data model: store the expression verbatim as the supplier's assertion, parse it into structure if you need to query it, and never overwrite the source string with a derived selection. A workable shape is three fields rather than one: the declared expression exactly as received; a parsed representation for querying; and, if someone chooses a branch of an `OR`, a separate field recording the selection with who made it and when. Those are three different claims by three different parties, and collapsing them into one column is what destroys the distinction. ## Watch the direction of the claim SPDX separates what a package **declares** from what an analyst **concludes** after examining it. An ingestion pipeline that writes a conclusion into the declared field, or vice versa, commits the same class of error at a different layer: it changes the identity of the party making the claim. When you are asked in an interview how you would model licensing data from supplier BOMs, saying *keep the supplier's string untouched and record our interpretation separately* is the answer that shows you have thought about provenance rather than about schema convenience. ## Quick self-check Given an expression joining a license with an exception on one side of an `OR`: how many distinct sets of terms are on offer, and which of them mention the exception? If your inventory cannot answer that from what it stored, it has already lost the information.
- What do the plus suffix and a LicenseRef identifier mean inside an SPDX license expression?A trailing `+` means that version of the named license or any later version. A `LicenseRef-` identifier names terms that are not on the SPDX License List, with the extracted text carried in the document itself. Dropping either turns a precise statement into an unresolvable one — the reference in particular becomes a dangling name once the document it was defined in is gone.
- Both formats can carry the expression, so where does the loss actually happen?In the consumer's data model, not the format. CycloneDX licenses entries accept an SPDX expression string directly, and SPDX defined the language. The loss comes from pipelines that flatten a document into rows with one license column, so the correction is schema work on your side rather than a conversion tool change.
- Your supplier's expression offers a choice. How should the inventory record it?Keep the expression verbatim as the supplier's assertion, and record any selection your organisation makes as a separate, attributed field with a timestamp. They are two claims by two parties. Overwriting the first with the second destroys the evidence of what the supplier actually stated.
It is the difference between recording a menu and recording one dish. Once you write down the dish someone happened to point at first, the menu is gone and nobody can tell it ever offered a choice.
saying these in an interview costs you the question
- Treats AND and OR in an expression as interchangeable
- Drops a WITH exception as a formatting detail
- Calls the expression free text to be normalised
- Assumes CycloneDX cannot carry an SPDX license expression
- Overwrites the declared value with an analyst's conclusion