Skip to content

Fix SPDX profile resolution: split lookup_table onto its own node - #174

Merged
kurtseifried merged 1 commit into
mainfrom
fix/spdx-profile-lookup-table
Aug 21, 2026
Merged

Fix SPDX profile resolution: split lookup_table onto its own node#174
kurtseifried merged 1 commit into
mainfrom
fix/spdx-profile-lookup-table

Conversation

@kurtseifried

Copy link
Copy Markdown
Collaborator

Follow-up to #173. The KV upload after that merge failed on one generated fixture, so the live resolver did not pick up either entry.

The failure

FAIL  registry example fixtures > resolves secid:reference/spdx.dev/spdx#ai
AssertionError: expected [ Array(1) ] to include 'https://spdx.github.io/spdx-spec/v3.0.1/model/AI/AI/'

The profile node accepted both spellings the source uses — the capitalised model/documentation path (AI) and the lowercase core:ProfileIdentifierType value written into a document's profileConformance field (ai) — and relied on lookup_table taking priority over the {profile} URL template for the lowercase set, as REGISTRY-JSON-FORMAT.md describes.

The deployed resolver builds from the template first, so ai was substituted verbatim and produced .../model/ai/ai/, which does not exist.

The fix

Split into two sibling nodes, matching the shape already proven by weakness/owasp.org:

Node Pattern Resolution
Documentation spelling ^(AI|Build|...|Licensing|...)$ {profile} template
ProfileIdentifierType spelling ^(ai|build|...|software)$ lookup_table only, {url, title} values, no template

Patterns stay case-sensitive, so the two are mutually exclusive — verified across all enumerated values. Licensing stays on the capitalised node only: it has a /model/Licensing/ page but is not a ProfileIdentifierType value, so it never appears in profileConformance.

Worth noting the documented precedence rule (lookup_table wins over url on the same node) does not hold in the deployed resolver. This PR routes around it rather than depending on it; whether the resolver or the doc should change is a separate question.

Verification

Rather than guess twice, I regenerated SecID-Service's src/registry.ts from this working tree and ran its suite locally:

  • 388/388 pass (was 386 passed / 1 failed), including all 28 spdx.dev and cyclonedx.org fixtures — #ai, #AI, #dataset, #Dataset all resolve to the correct capitalised URL
  • check-pattern-breadth.py PASS, no new exceptions
  • validate-subtypes.py PASS
  • Validates against schemas/registry-namespace.schema.json

The KV deploy after #173 failed one generated fixture:
secid:reference/spdx.dev/spdx#ai resolved to .../model/ai/ai/ instead
of .../model/AI/AI/.

The profile node accepted both spellings — the capitalised model path
(AI) and the lowercase core:ProfileIdentifierType value written into
profileConformance (ai) — and relied on lookup_table taking priority
over the {profile} URL template for the lowercase set. The deployed
resolver builds from the template first, so the lowercase input was
substituted verbatim into a path that does not exist.

Split into two sibling nodes, matching the shape already proven by
weakness/owasp.org: the capitalised node keeps the template, and the
ProfileIdentifierType node carries lookup_table alone with {url, title}
values and no template. Patterns stay case-sensitive, so the two remain
mutually exclusive. Licensing appears only on the capitalised node — it
has a /model/Licensing/ page but is not a ProfileIdentifierType value.

Verified by regenerating SecID-Service's src/registry.ts from this
working tree and running its suite: 388/388 pass, including all 28
spdx.dev and cyclonedx.org fixtures. Previously 386 passed, 1 failed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant