Design for PURL type for software without a registry #841
Replies: 15 comments 4 replies
-
How do you validate the vendor name and domain combination?Why is validation needed?
|
Beta Was this translation helpful? Give feedback.
-
What are the namespace constraints for the scid PURL type?
|
Beta Was this translation helpful? Give feedback.
-
Is the sid PURL type intended to replace CPE?
|
Beta Was this translation helpful? Give feedback.
-
Who is responsible for software naming under the sid PURL type?
|
Beta Was this translation helpful? Give feedback.
-
Is TEA a solution for verifying a sid PURL?
|
Beta Was this translation helpful? Give feedback.
-
What are some alternatives for discovering the location of a package?
|
Beta Was this translation helpful? Give feedback.
-
Is a download location required in a sid PURL?
|
Beta Was this translation helpful? Give feedback.
-
What should be the method of metadata distribution for the sid PURL type?
|
Beta Was this translation helpful? Give feedback.
-
Do we really need a registry for sid PURLs?
|
Beta Was this translation helpful? Give feedback.
-
|
@stevespringett |
Beta Was this translation helpful? Give feedback.
-
|
This post by Mark Nottingham - "one of the authors of the Well-Known URI specification and current Designated Expert for the registry - seems relevant to the proposed use of |
Beta Was this translation helpful? Give feedback.
-
|
FYI, I synthesized a PURL
|
| Level | Form | Meaning |
|---|---|---|
| Component | pkg:sid/example.com/acme/beancooler |
The asserted component identity without a pinned release. A proprietary product is one example of such a component. |
| Release | pkg:sid/example.com/acme/beancooler@1.2.3 |
The asserted component at a supplier, distributor, or CNA release version. |
| Distribution build | pkg:sid/example.com/acme/beancooler@1.2.3?arch=x86_64&edition=enterprise&target=windows |
A specific release distribution narrowed by artifact-selecting facets. |
| Subcomponent | pkg:sid/example.com/acme/beancooler@1.2.3#drivers/filter |
A subcomponent or file path inside the named software distribution. |
Rationale (P2). This is the unavoidable tradeoff for non-registry
software. With npm or PyPI, the registry is the naming authority. With
commercial and standalone software, the closest observable authority is the
supplier or another party publishing a product assertion. Encoding that
authority in the namespace makes the trust boundary visible rather than
pretending that the name is globally registry-verified.
Supplier and third-party assertions
The supplier should be the canonical authority when it publishes a sid or
equivalent product metadata. Consumers should prefer supplier-authored sid
PURLs over third-party or inferred sid PURLs.
When the supplier has not published one, a distributor, CNA, customer, or other
party may mint a sid PURL as its own assertion. Such a PURL is still valid,
but its authority is the asserting domain. If a supplier later publishes a
canonical sid, the third-party sid should be linked to it with an alias,
equivalent, or successor relationship at the BOM, advisory, or catalog layer.
Components
| Component | Requirement | Definition |
|---|---|---|
type |
required | Literal sid, lowercase. |
namespace |
required | Assertion namespace. The first segment is the authority: a self-asserted domain when it contains a dot, or a registered registry namespace when it does not. A vendor identifier and additional namespace segments may follow. |
name |
required | Stable component, project, application, or distribution name. A proprietary product is one example of such a component. |
version |
optional | Supplier, distributor, or asserter release, tag, build, or snapshot version. |
qualifiers |
optional | Artifact-selecting distribution facets such as arch, edition, target, and locale; resolver hints such as download_url are non-identity-bearing. |
subpath |
optional | Standard PURL subpath inside the named software distribution. |
Namespace
The namespace identifies the assertion authority and the software vendor:
pkg:sid/{asserter_domain}/{vendor_identifier}[/{vendor_namespace...}]/{name}
Rules:
- The first namespace segment serves as the authority. It should be a
domain-qualified namespace: a DNS-order internet domain controlled by the
party making or publishing the assertion, self-asserted and requiring no
registration. - The first segment may instead be a registry-based namespace, identified by
the absence of a dot. A registry-based namespace shall be registered in the
PURL registry; an unregistered registry-based namespace is invalid. - The namespace should continue with a vendor, project, or component-owner
identifier as a stable URL-safe token. - Additional namespace segments may be used for vendor-specific component
families, divisions, suites, or other supplier-defined grouping. - Empty namespace segments are invalid.
- The domain segment should be lowercase.
- Vendor and vendor-specific namespace segments should be lowercase URL-safe
slugs unless the supplier publishes a different canonical token. - The namespace is not a URL authority and shall not include a scheme,
credentials, path, query, or fragment.
Examples:
example.com/acme
oracle.com/oracle
microsoft.com/microsoft
kernel.org/linux
distributor.example/acme
Rationale (P2). The original
scidproposal required both a domain and a
vendor because either one alone is weak. Domains can expire, transfer, or
change meaning; vendor names can collide. A domain-qualified authority plus a
vendor token still gives the strongest practical anchor and a
human-recognizable creator label, so this draft recommends that form. It does
not mandate it: aligning with the working group's decision, the first segment
may instead be a registered registry namespace, and the vendor segment is a
recommendation rather than a validity gate. Allowing additional namespace
segments captures the discussion request for vendor-specific namespaces.
A rebrand, acquisition, domain transfer, or domain loss may yield a new sid
PURL. Continuity belongs in catalog relationships, not in identifier mutation.
Where archival verification matters, the metadata distribution mechanism should
preserve old assertions independently of current DNS ownership.
Name
The name is the stable component, project, or application identifier. A
proprietary product is one example of such a component.
Rules:
- If the supplier publishes a canonical
sid, component metadata object, SWID
tag, release manifest, or equivalent component id, use the supplier's
canonical component token. - Otherwise use the common component or project name normalized to a lowercase
URL-safe slug. - Do not include version, edition, architecture, target environment, locale, or
download location innamewhen the corresponding PURL component or
qualifier exists. - Do not use customer-specific labels, internal asset names, contract ids, or
scanner display strings as the component name.
Examples:
beancooler
windows-10
java-se
linux-kernel
analytics-suite
Version
The version is optional and opaque. It should be the supplier, distributor, or
asserting authority's own release, product version, tag, build, date, or
snapshot identifier.
1.2.3
22H2
8u411
6.10.2
2026.04
Omitting version denotes the product identity without a pinned release.
Producers should not move version-like tokens into name when the token is a
separable release identifier.
Qualifiers
sid requires no qualifiers. The following qualifiers are defined. The
Identity column states whether the qualifier is part of component identity,
because the type-definition schema has no field to express this and consumers
need to be told.
| Qualifier | Requirement | Identity | Meaning |
|---|---|---|---|
arch |
optional | identity-bearing | CPU or hardware architecture for the distributed artifact, such as x86_64, arm64, or a supplier-published architecture token. |
edition |
optional | identity-bearing | Product edition or SKU when it selects a distinct product distribution, such as community, enterprise, or professional. |
target |
optional | identity-bearing | Target operating system, runtime, or platform environment, such as windows, linux, android, java, or macos. |
locale |
optional | identity-bearing | Locale or language distribution when the vendor ships a distinct localized artifact. |
download_url |
optional | not identity-bearing | Current download, landing, or customer portal URL, when safe to publish. May require authentication. |
Runtime state, installation path, license key, contract id, tenant, customer,
detected vulnerability state, remediation state, and scanner confidence shall not
be encoded as qualifiers.
arch
arch is used only when the architecture selects a different artifact or
distribution. It should use common normalized architecture tokens when those are
unambiguous (x86_64, arm64) and may use the supplier's own architecture
token when that is the published discriminator.
edition
edition is used only when the edition changes the referent: different bits,
different feature set, different license family, or a supplier-recognized SKU.
It should not encode a customer's contract terms or entitlement state.
target
target is used when the same product release is distributed separately for a
target software environment or platform. It maps to the role CPE calls
target_sw and the original scid proposal called target.
locale
locale is used only when locale selects a distinct software distribution. It
shall not encode runtime configuration, user preference, or a locale setting that
does not change the artifact.
The value should be a BCP 47 language tag when the supplier's distribution is
identified by a standard locale. BCP 47 extensions may be used when they are
actually part of the distribution identity. When the vendor publishes a
non-standard but stable locale token, producers should use the vendor token
rather than invent a lossy conversion.
Examples:
locale=ja-JP
locale=th-TH
locale=ja-JP-u-ca-japanese
locale=international
Rationale (P4). The discussion around PR #857 surfaced the important
boundary: locale matters for separate localized software packages, not for
runtime locale configuration. The qualifier exists for the former only.
download_url
download_url is a resolver hint, not identity. It may point to a public
download, vendor landing page, customer portal, or authenticated distribution
location. It shall not contain credentials, bearer tokens, customer secrets, or
one-time URLs. Changing download_url shall not change the sid identity.
Producers should prefer BOM external references, TEA metadata, SCITT/Product
Trust Registry records, vendor catalogs, or other metadata channels over putting
large or sensitive resolver data in the PURL itself. The qualifier exists only
for small, safe resolver hints.
Subpath
subpath has the standard PURL fragment meaning: a relative path inside the
named software distribution.
Use subpath when identifying a subcomponent, module, or file within the
broader software product:
pkg:sid/example.com/acme/beancooler@1.2.3#drivers/filter
Use qualifiers for distribution facets and subpath only for a path inside the
distribution. Do not use subpath for download URLs, installation paths, or
customer deployment locations.
Construction
Given a software component or release to describe, a producer mints the PURL as
follows:
- Choose type. If an existing ecosystem, service, private, app store, or
VCS PURL applies, stop and use that type instead. - Choose assertion authority. Prefer a supplier-published
sidor supplier
metadata. If minting a third-party assertion, use the domain of the party
making that assertion. - namespace segment 1 (authority) := the assertion authority's DNS-order
domain, lowercase, when using the recommended domain-qualified form; or a
registered registry namespace when using the registry-based form. - namespace segment 2 := the vendor, project, or component owner identifier
published by the supplier or normalized from the vendor name. Recommended,
not required. - additional namespace segments := supplier-defined component family,
division, suite, or namespace only when needed and observable. - name := the supplier's stable component token, or a normalized component
slug when no token is published. - version := the release, build, tag, date, or snapshot identifier, when
known. - qualifiers := artifact-selecting facets (
arch,edition,target,
locale) only when they narrow the referent. - subpath := only when identifying a path inside the named software
distribution.
Equality and propagation
PURL equality is defined on decoded components, so equivalent percent-encodings
of the same value are equal.
Identity narrowing handles the vertical axis:
- A finding against a product-level
sidcan apply directionally to releases
and distribution builds below it. - A finding against a versioned
sidcan apply directionally to builds narrowed
by architecture, edition, target, or locale. - A finding against a fully-qualified distribution build applies only to that
build unless catalog evidence says otherwise.
Relationships carried in the BOM, advisory, or catalog layer handle the
horizontal axis:
- alias / equivalent links CPE, SWID, supplier
sid, distributorsid, and
third-partysididentifiers that are believed to name the same referent. - successor links rebrands, acquisitions, product renames, and domain
changes. - variant-of links related distributions, forks, or vendor-specific builds
when they share lineage but are not the same referent.
Rationale (P2, P3).
sidintentionally makes assertion provenance
visible. That means two parties may mint different valid PURLs for what later
proves to be the same product. The identifier should not hide that uncertainty;
equivalence belongs on a relationship asserted by a catalog, advisory, or BOM.
Relationship to CycloneDX and SPDX
In CycloneDX, a pkg:sid identifier attaches to a component for commercial,
proprietary, standalone, or other non-ecosystem software dependencies. It is
especially useful where existing inventories would otherwise carry CPEs, vendor
strings, or unstructured software names. In SPDX, it is an external package
identifier on the corresponding element.
SBOM producers should keep ecosystem dependencies on ecosystem PURLs, first-
party repository components on pkg:private, hosted services on pkg:service,
and non-packaged distributed software on pkg:sid.
Resolution and metadata distribution
There is no mandatory public registry for pkg:sid. Base validation is syntax
validation plus type-specific normalization. Advanced validation may check an
optional namespace registry, supplier catalog, TEA service, SCITT/Product Trust
Registry, vendor website, signed customer notice, or other supplier-controlled
metadata.
Resolution is therefore layered:
- Parse and normalize the PURL.
- Determine the assertion authority from the first namespace segment.
- Determine vendor and product identity from the remaining namespace and name.
- Apply version and distribution facets.
- If supplier metadata exists, validate the PURL against that metadata.
- If TEA discovery exists for the domain, use it for richer product and release
metadata. - If a future
purl-locatormechanism exists, treat it as optional metadata,
not as a requirement for PURL validity. - If
download_urlis present, use it only as a resolver hint; expect
authentication or access control for commercial and internal software.
Package-collection tooling should treat pkg:sid as valid PURL syntax but not
automatically collectable without a product catalog, supplier metadata source,
or user-provided resolver.
TEA and well-known resources
TEA is a natural companion for sid, but not a requirement. A domain-bound TEA
service can publish product and release metadata, validate canonical names, and
provide download or provenance information without centralizing the sid type.
This proposal does not define a new /.well-known/ resource. If the working
group chooses to define a PURL locator resource, it should be specified
separately, should follow the IANA well-known URI registration process, and
should not make sid validity depend on resolution.
Anticipated objections
"PURLs are supposed to be deterministic and self-validating." That is true
for registry-backed types, and the design should preserve it where possible.
sid exists because this class of software has no package registry. The
deterministic source of truth is therefore a supplier or asserter's product
metadata, not a global registry. That is weaker than npm-style verification but
stronger than unstructured vendor/product strings.
"This recreates CPE." It overlaps CPE's use case, but not its governance
model. sid is decentralized and PURL-shaped. It can carry CPE-like facets, and
catalogs can map CPEs to SIDs, but it does not require NVD to allocate names.
"A central registry is required for consistency." A registry can help, but
it should not be required for base validity. The discussion split syntax from
resolution for this reason: a registry of thousands of commercial and standalone
software namespaces is unlikely to scale as a mandatory gate. Optional registries
can document namespace policies, early adopters, or mappings.
"Download location should be required." No. A sid is primarily an
identifier. Commercial downloads may require payment, customer approval, or
authentication; internal downloads may be unreachable to outsiders; and many
SBOM or advisory uses need matching, not download. Location belongs in metadata
or a non-identity resolver hint.
"Why not pkg:generic?" generic has no authority model, no required
domain/vendor structure, no CPE-like distribution facets, and no clear
validation story. Adding all of that as conventions on generic would create a
hidden type with less discoverability.
"Why not pkg:private?" private names first-party repository software
owned by the organization minting the PURL and carries repository coordinates.
sid names distributed software a party obtained, supplied, or asserts for
vulnerability and inventory matching. The same SBOM can use both.
"Why not pkg:service?" service names hosted service referents with no
downloaded artifact. sid names distributed software products and installable
releases.
"Locale is too complicated." It is complicated when treated as language
metadata. This proposal treats it as an artifact discriminator only. If locale
does not select a distinct distribution, omit it.
Candidate type-definition JSON
{
"$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json",
"$id": "https://packageurl.org/types/sid-definition.json",
"type": "sid",
"type_name": "Software Identifier",
"description": "Distributed software with no authoritative package ecosystem PURL: commercial and proprietary products, standalone open source releases, binary-only/installable software, and CPE-like product identifiers. Use an existing package ecosystem, VCS, app store, service, or private type when one applies.",
"repository": {
"use_repository": false,
"note": "There is no mandatory repository or registry for SID. Resolution uses supplier, asserter, catalog, TEA, SCITT, or other metadata when available."
},
"namespace_definition": {
"requirement": "required",
"case_sensitive": false,
"permitted_characters": "^[a-z0-9.-]+(/[a-z0-9][a-z0-9._-]*)*$",
"native_name": "assertion authority plus optional vendor namespace",
"normalization_rules": [
"The first namespace segment is the authority. When it contains a dot it is a self-asserted DNS-order domain controlled by the party making or publishing the assertion and requires no registration. When it contains no dot it is a registry-based namespace that shall be registered in the PURL registry; an unregistered registry-based namespace is invalid.",
"The namespace should continue with a stable vendor, project, or component-owner identifier.",
"Additional namespace segments may be used for supplier-defined component families, divisions, suites, or namespaces.",
"The namespace is not a URL authority and does not contain a scheme, credentials, query, or fragment."
],
"note": "The namespace binds the assertion authority and, where present, the vendor identity; it is not a download location."
},
"name_definition": {
"requirement": "required",
"case_sensitive": false,
"permitted_characters": "^[a-z0-9][a-z0-9._-]*$",
"native_name": "software product or component name",
"normalization_rules": [
"Use the supplier-published component token when one exists; otherwise use a lowercase URL-safe slug of the common component name.",
"Do not encode version, edition, architecture, target environment, locale, customer, or download location in the name."
]
},
"version_definition": {
"requirement": "optional",
"case_sensitive": true,
"native_name": "release, tag, build, date, or snapshot version",
"note": "An opaque version string from the supplier, distributor, or assertion authority."
},
"qualifiers_definition": [
{
"key": "arch",
"requirement": "optional",
"description": "CPU or hardware architecture for the distributed artifact. Identity-bearing when it selects a different artifact."
},
{
"key": "edition",
"requirement": "optional",
"description": "Product edition or SKU. Identity-bearing when it selects a distinct product distribution."
},
{
"key": "target",
"requirement": "optional",
"description": "Target operating system, runtime, or platform environment. Identity-bearing when it selects a different artifact."
},
{
"key": "locale",
"requirement": "optional",
"description": "Locale or language distribution. Identity-bearing only when the vendor ships a distinct localized artifact; do not use for runtime locale configuration."
},
{
"key": "download_url",
"requirement": "optional",
"description": "Current download, landing, or customer portal URL, when safe to publish. Not identity-bearing and may require authentication."
}
],
"subpath_definition": {
"requirement": "optional",
"case_sensitive": true,
"native_name": "path inside the software distribution",
"normalization_rules": [
"Use subpath only for paths inside the named software distribution.",
"Do not use subpath for download URLs, installation paths, or customer deployment locations."
]
},
"examples": [
"pkg:sid/example.com/acme/beancooler@1.2.3",
"pkg:sid/microsoft.com/microsoft/windows-10@22H2?arch=x86_64&edition=enterprise&locale=ja-JP&target=windows",
"pkg:sid/oracle.com/oracle/java-se@8u411?arch=x86_64&target=windows",
"pkg:sid/kernel.org/linux/linux-kernel@6.10.2",
"pkg:sid/distributor.example/acme/appsuite@1.0.0",
"pkg:sid/example.com/acme/beancooler@1.2.3#drivers/filter"
],
"note": "Identity is the first-segment authority (a self-asserted domain or a registered registry namespace) plus an optional vendor segment plus the component name, narrowed by version, artifact-selecting qualifiers, and subpath. Download location and metadata distribution are optional and not identity-bearing."
}Summary of key decisions
| Decision | Reason |
|---|---|
Use sid only when no existing ecosystem, service, private, VCS, or app store type applies. |
Avoids turning sid into a generic fallback and preserves ecosystem self-validation. |
| First namespace segment is the authority: a self-asserted domain or a registered registry namespace; a vendor identifier should follow. | Aligns with the working group's decision while still recommending the domain-plus-vendor form for human/vendor disambiguation from the original scid proposal. |
| Additional namespace segments are allowed after the authority/vendor segments. | Incorporates the discussion request for vendor-specific namespaces without weakening the leading authority semantics. |
| Supplier-authored identifiers are preferred; third-party identifiers are assertion-scoped. | The supplier is normally authoritative, but consumers and CNAs may need identifiers before suppliers publish them. |
arch, edition, target, and locale are identity-bearing only when they select different artifacts/distributions. |
Mirrors CPE's useful axes while preventing runtime configuration from polluting identity. |
download_url is optional and not identity-bearing. |
PURL identity needs to work even when download requires authorization or no public location exists. |
| TEA, SCITT, purl-registry, and well-known locators are optional metadata/resolution layers. | Keeps syntax and identity separate from resolution, and avoids mandating a central registry. |
| CPE/SWID continuity lives in relationships, not in the SID string. | sid can coexist with legacy identifiers and be mapped by BOM/advisory/catalog data. |
| Locale uses BCP 47 when appropriate, but only for distinct localized artifacts. | Captures the PR #857 point without mistaking runtime locale configuration for package identity. |
References
- ECMA-427 Package-URL specification:
https://ecma-tc54.github.io/ECMA-427/ - Ecma International ECMA-427 page:
https://ecma-international.org/publications-and-standards/standards/ecma-427/ - Package URL type definitions:
https://github.com/package-url/purl-spec/tree/main/types - Package URL type-definition schema:
https://raw.githubusercontent.com/package-url/purl-spec/main/schemas/purl-type-definition.schema-1.0.json - purl-spec discussion #841 "Design for PURL type for software without a
registry":https://github.com/package-url/purl-spec/discussions/841 - purl-spec #516 "Add new PURL type for non-packaged software":
https://github.com/package-url/purl-spec/issues/516 - purl-spec PR #857 "SID: locale qualifier: Add Extension U example to BCP
47":https://github.com/package-url/purl-spec/pull/857 - purl-spec #690 "Schema change / purl-type-definition: Add enum for
namespace values":https://github.com/package-url/purl-spec/issues/690 - package-url
purl-registryexperiment:
https://github.com/package-url/purl-registry - Mark Nottingham, "So You Want To Define a Well-Known URI":
https://mnot.net/blog/2026/well_known_uris - ISO/IEC Directives, Part 2 (verbal forms for the expression of provisions)
- BCP 47 and RFC 6067 for locale extension discussion
Beta Was this translation helpful? Give feedback.
-
|
@mjherzog I have a question about the proper applicability of pkg:sid. Take this case:
For this sort of situation , would pkg:sid or pkg:gitlab be preferable? |
Beta Was this translation helpful? Give feedback.
-
|
@VanL I would recommend the pkg:gitlab formulation because it provides additional information in the 'gitlab' PURL type, but we do not currently have a gitlab type. We will, however, have the new 'git' *type very soon so the PURL string for that would be: |
Beta Was this translation helpful? Give feedback.
-
|
So the git PURL type would be preferable to the sid type? Why? That is the
root of my question.
Thanks,
Van
Van Lindberg
***@***.***
…On Mon, Jul 6, 2026 at 11:38 AM Michael Herzog ***@***.***> wrote:
@VanL <https://github.com/VanL> I would recommend the pkg:gitlab
formulation because it provides additional information in the 'gitlab' PURL
*type*, but we do not currently have a gitlab *type*. We will, however,
have the new 'git' **type* very soon so the PURL string for that would be:
pkg:git/gitlab.isc.org/isc-projects/kea
The PR to add the 'git' PURL *type* is: #823
<#823> for reference
—
Reply to this email directly, view it on GitHub
<#841?email_source=notifications&email_token=AABUNKWY7H2DAYIM6PHBUDD5DPIY7A5CNFSNUABIM5UWIORPF5TWS5BNNB2WEL2ENFZWG5LTONUW63SDN5WW2ZLOOQXTCNZVGUYDGNBZUZZGKYLTN5XKO3LFNZ2GS33OUVSXMZLOOSWGM33PORSXEX3DNRUWG2Y#discussioncomment-17550349>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABUNKQNVXDBQIBVUODNZAL5DPIY7AVCNFSNUABHKJSXA33TNF2G64TZHMYTCMBTGM4TCNZXHNCGS43DOVZXG2LPNY5TSNZTGQZDOMFBOYBA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This Discussion item captures the historical commentary from:
Note that the commentary for these topics does not include the author of each post in order to keep the commentary succinct.
Please comment by topic or create a new comment thread for a new topic.
Beta Was this translation helpful? Give feedback.
All reactions