Skip to content

Support NOASSERTION and NONE as special SPDX license expression identifiers #29

Description

@bact

Background

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

Source: https://spdx.github.io/spdx-spec/v3.1-dev/annexes/spdx-license-expressions/#simple-license-expressions

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)

  1. 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.
  2. 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?
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions