You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Per the SPDX License Expressions spec, "Simple license expressions" section (v3.1-dev):
A simple <license-expression> is composed one of the following:
An SPDX License List Short Form Identifier. For example: CDDL-1.0
An SPDX License List Short Form Identifier with a unary "+" operator suffix to represent the current version of the license or any later version. For example: CDDL-1.0+
One of the special identifiers "NONE" or "NOASSERTION"
A user defined license reference: ["DocumentRef-"(idstring)":"]"LicenseRef-"(idstring). For example: LicenseRef-23, LicenseRef-MIT-Style-1, and DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2
NOASSERTION/NONE are not part of the ABNF grammar shown on main for the annex (simple-expression = license-id / license-id"+" / license-ref), but the v3.1-dev "Simple license expressions" prose explicitly lists them as one of the four valid simple-expression forms.
Semantics (from the SPDX 3.x Licensing model)
NOASSERTION (NoAssertionLicense) = "no information about license". Used when:
the SPDX creator has attempted to but cannot reach a reasonable objective determination;
the SPDX creator has made no attempt to determine this field; or
the SPDX creator has intentionally provided no information (no meaning shall be implied by doing so).
NONE (NoneLicense) = "no license". Used when the SPDX creator determines there is no license available for the artifact.
These are genuinely common in the wild — e.g. SPDX-License-Identifier: NOASSERTION, or a PackageLicenseConcluded: NONE field — and are distinct from "unrecognized/invalid license text."
Current behavior (unimplemented)
Neither string is special-cased anywhere in the identification/normalization/matching pipeline. Confirmed by direct testing against identifiers.normalize_identifier and matcher.AggregatedLicenseMatcher:
normalize_identifier("NOASSERTION"/"NONE", db) — tokenizes as a plain single identifier, no DB/deprecated-ID match, passed through unchanged (harmless, but not recognized as anything special; casing isn't canonicalized, e.g. "noassertion" stays lowercase).
matcher.match(license_id="NOASSERTION"/"NONE") — no DB row, not a WITH expression → returns [], indistinguishable from any other unrecognized garbage string.
matcher.match(text="NOASSERTION"/"NONE") — also returns [] (does not get fuzzy-matched against a real license, which is good, but also isn't recognized as the special SPDX construct it is).
is_spdx(license_id="NOASSERTION"/"NONE") → False.
py_spdx_license (the parser used for expression canonicalization, see Bump actions/checkout from 6 to 7.0.0 #26 / the spdx-license-parsing work) also does not special-case these — they only parse at all under allow_unknown=True, becoming a generic UnknownId node with no special semantics. Confirmed via direct testing.
The only existing occurrence of the literal string "NOASSERTION" in the codebase is unrelated: spdx_source.py filters "NOASSERTION" rows out of GitHub's license-popularity CSV data source — nothing to do with expression parsing.
Proposed direction (not yet implemented — for discussion before starting)
identifiers.py: recognize NOASSERTION/NONE case-insensitively (matching how real license IDs already get canonical-cased) and normalize to the canonical uppercase form, rather than passing through whatever casing was given.
matcher.py: match(license_id="NOASSERTION"/"NONE") should probably return a distinct, recognizable result (e.g. a LicenseMatch with the canonical id, score=1.0, is_spdx=False since they're not on the SPDX License List) instead of [], so callers can tell "explicitly no license / no assertion" apart from "nothing found at all." Open question: is is_spdx=False the right signal, or should LicenseMatch/LicenseDetails gain a distinguishing flag (e.g. is_special) instead of overloading existing fields?
Decide whether NOASSERTION/NONE should be accepted as leaf tokens inside compound expressions (AND/OR/WITH) or only as bare/whole values — the spec's ABNF for simple-expression doesn't cleanly reconcile with the "Simple license expressions" prose on this point, so compound usage like NOASSERTION AND MIT is semantically dubious in practice even if grammatically permitted.
Filed as documentation of the research so this can be picked up as a scoped follow-up rather than implemented ad hoc.
Background
Per the SPDX License Expressions spec, "Simple license expressions" section (v3.1-dev):
Source: https://spdx.github.io/spdx-spec/v3.1-dev/annexes/spdx-license-expressions/#simple-license-expressions
NOASSERTION/NONEare not part of the ABNF grammar shown onmainfor the annex (simple-expression = license-id / license-id"+" / license-ref), but the v3.1-dev "Simple license expressions" prose explicitly lists them as one of the four valid simple-expression forms.Semantics (from the SPDX 3.x Licensing model)
NOASSERTION(NoAssertionLicense) = "no information about license". Used when:NONE(NoneLicense) = "no license". Used when the SPDX creator determines there is no license available for the artifact.These are genuinely common in the wild — e.g.
SPDX-License-Identifier: NOASSERTION, or aPackageLicenseConcluded: NONEfield — and are distinct from "unrecognized/invalid license text."Current behavior (unimplemented)
Neither string is special-cased anywhere in the identification/normalization/matching pipeline. Confirmed by direct testing against
identifiers.normalize_identifierandmatcher.AggregatedLicenseMatcher:normalize_identifier("NOASSERTION"/"NONE", db)— tokenizes as a plain single identifier, no DB/deprecated-ID match, passed through unchanged (harmless, but not recognized as anything special; casing isn't canonicalized, e.g."noassertion"stays lowercase).matcher.match(license_id="NOASSERTION"/"NONE")— no DB row, not aWITHexpression → returns[], indistinguishable from any other unrecognized garbage string.matcher.match(text="NOASSERTION"/"NONE")— also returns[](does not get fuzzy-matched against a real license, which is good, but also isn't recognized as the special SPDX construct it is).is_spdx(license_id="NOASSERTION"/"NONE")→False.py_spdx_license(the parser used for expression canonicalization, see Bump actions/checkout from 6 to 7.0.0 #26 / thespdx-license-parsingwork) also does not special-case these — they only parse at all underallow_unknown=True, becoming a genericUnknownIdnode with no special semantics. Confirmed via direct testing."NOASSERTION"in the codebase is unrelated:spdx_source.pyfilters"NOASSERTION"rows out of GitHub's license-popularity CSV data source — nothing to do with expression parsing.Proposed direction (not yet implemented — for discussion before starting)
identifiers.py: recognizeNOASSERTION/NONEcase-insensitively (matching how real license IDs already get canonical-cased) and normalize to the canonical uppercase form, rather than passing through whatever casing was given.matcher.py:match(license_id="NOASSERTION"/"NONE")should probably return a distinct, recognizable result (e.g. aLicenseMatchwith the canonical id,score=1.0,is_spdx=Falsesince they're not on the SPDX License List) instead of[], so callers can tell "explicitly no license / no assertion" apart from "nothing found at all." Open question: isis_spdx=Falsethe right signal, or shouldLicenseMatch/LicenseDetailsgain a distinguishing flag (e.g.is_special) instead of overloading existing fields?NOASSERTION/NONEshould be accepted as leaf tokens inside compound expressions (AND/OR/WITH) or only as bare/whole values — the spec's ABNF forsimple-expressiondoesn't cleanly reconcile with the "Simple license expressions" prose on this point, so compound usage likeNOASSERTION AND MITis semantically dubious in practice even if grammatically permitted.Filed as documentation of the research so this can be picked up as a scoped follow-up rather than implemented ad hoc.