diff --git a/docs/sbom.md b/docs/sbom.md index 73b00cb..b2308cc 100644 --- a/docs/sbom.md +++ b/docs/sbom.md @@ -448,7 +448,7 @@ Container Images are also linked to one or more upstream sources that were used { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": "pkg:generic/kernel-model-management@d027509b6861d8a9f923cc99dd3e15d9b209e63e?download_url=https://github.com/rh-ecosystem-edge/kernel-module-management#d027509b6861d8a9f923cc99dd3e15d9b209e63e" + "referenceLocator": "pkg:github/rh-ecosystem-edge/kernel-module-management@d027509b6861d8a9f923cc99dd3e15d9b209e63e" } ] }, @@ -598,8 +598,25 @@ source can be represented by a package object using the following data: purl identifiers : In cases where the upstream source is a package in a registry such as PyPI or NPM, the purl identifier will use the respective package type. For components that are distributed as standalone bundles (such as OpenSSL in the - example above), `generic` purls should be used with an exact download URL from where a specific bundle of source - code was fetched from, including a checksum (which should also be specified in the `checksums` field). + example above), use `generic` purls with an exact download URL from where a specific bundle of source code was + fetched from, including a checksum (which should also be specified in the `checksums` field). When the source + `downloadLocation` is a `github.com` URL, use the [`github` purl type](https://github.com/package-url/purl-spec/blob/main/types-doc/github-definition.md) + and emit `pkg:github//@` only — do not also emit a `generic` purl whose `download_url` + points at the same GitHub location. When a separate non-GitHub fetch URL is also known (for example an upstream + tarball mirror alongside a GitHub repository), add a second purl: + `pkg:generic/@?download_url=...` (and `checksum=...` when known). + + Example for a GitHub-hosted source archive (`delve` `Source0`): + + ```json + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:github/go-delve/delve@1.7.2" + } + ] + ``` To associate a set of source archives with the SRPM that includes them, use: @@ -659,6 +676,7 @@ Use a typed purl when the provide name indicates the ecosystem: | Language prefix in provide | purl type | Example provide | Example purl | |----------------------------|-----------|-----------------|--------------| | *(none)* / generic bundled | `generic` | `bundled(libvterm)` | `pkg:generic/libvterm` | +| generic bundled + GitHub URL | `github` | `bundled(libvterm)` | `pkg:github/neovim/libvterm@0.3.3` | | `golang(...)` | `golang` | `golang(github.com/foo/bar)` | `pkg:golang/github.com/foo/bar@1.2.3` | | `bundled(python(...))` | `pypi` | `bundled(python(requests))` | `pkg:pypi/requests@2.31.0` | | `bundled(nodejs(...))` | `npm` | `bundled(nodejs(lodash))` | `pkg:npm/lodash@4.17.21` | @@ -666,21 +684,33 @@ Use a typed purl when the provide name indicates the ecosystem: | `bundled(crate(...))` | `cargo` | `bundled(crate(serde))` | `pkg:cargo/serde@1.0.0` | | `bundled(mvn(...))` | `maven` | `bundled(mvn(org/foo))` | `pkg:maven/org/foo@1.0.0` | +When upstream provenance is known (for example from the embedded copy in the build tree), +use the [`github` purl type](https://github.com/package-url/purl-spec/blob/main/types-doc/github-definition.md) +if `vcs_url` or `download_url` is a `github.com` URL. Parse `owner` and `repo` from the URL +and emit `pkg:github//@`. When a non-GitHub upstream URL is also known, +add a second purl on the same package: `pkg:generic/@?download_url=...` +(or `vcs_url=...`). Do not attach non-GitHub URLs as qualifiers on the `github` purl. + === "SPDX 2.3" ```json { - "SPDXID": "SPDXRef-Bundled-11cdd6f19dc1", - "name": "libvterm (generic)", - "versionInfo": "NOASSERTION", - "downloadLocation": "NOASSERTION", + "SPDXID": "SPDXRef-Bundled-b33d2447bd15", + "name": "neovim/libvterm (github) 0.3.3", + "versionInfo": "0.3.3", + "downloadLocation": "git+https://github.com/neovim/libvterm", "filesAnalyzed": false, "primaryPackagePurpose": "LIBRARY", "externalRefs": [ { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": "pkg:generic/libvterm" + "referenceLocator": "pkg:github/neovim/libvterm@0.3.3" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:generic/libvterm@0.3.3?download_url=http%3A%2F%2Fwww.leonerd.org.uk%2Fcode%2Flibvterm" } ] } @@ -690,7 +720,7 @@ Use a typed purl when the provide name indicates the ecosystem: ```json { - "spdxElementId": "SPDXRef-Bundled-11cdd6f19dc1", + "spdxElementId": "SPDXRef-Bundled-b33d2447bd15", "relationshipType": "DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-SRPM" } diff --git a/sbom/examples/rpm/build/README.md b/sbom/examples/rpm/build/README.md index 0ce3b6c..fd610ed 100644 --- a/sbom/examples/rpm/build/README.md +++ b/sbom/examples/rpm/build/README.md @@ -31,8 +31,8 @@ Bundled dependencies Build-time SBOMs may include packages for `bundled()` / `golang()` Provides from the RPM spec (see [Understanding SBOMs — Bundled dependencies](../../../../docs/sbom.md#bundled-dependencies)). -The `vim-9.1.083-5.el10` example includes `bundled(libvterm)` linked to the -SRPM with `DEPENDENCY_OF`. +The `vim-9.1.083-5.el10` example includes `bundled(libvterm)` enriched to +`pkg:github/neovim/libvterm@0.3.3`, linked to the SRPM with `DEPENDENCY_OF`. When a container image is built including RPMs, the SBOM for the container image should refer to the RPMs using external references both with and without diff --git a/sbom/examples/rpm/build/bundled_provides.py b/sbom/examples/rpm/build/bundled_provides.py index a100dec..37dc5f4 100644 --- a/sbom/examples/rpm/build/bundled_provides.py +++ b/sbom/examples/rpm/build/bundled_provides.py @@ -7,8 +7,10 @@ from __future__ import annotations import hashlib +import re from dataclasses import dataclass from typing import Any +from urllib.parse import quote LANG_TO_PURL_TYPE: dict[str, str] = { "golang": "golang", @@ -20,6 +22,11 @@ "generic": "generic", } +_GITHUB_OWNER_REPO_RE = re.compile( + r"(?:git\+)?https?://(?:www\.)?github\.com/([^/\s)>\"']+)/([^/\s)>\"'#]+)", + re.IGNORECASE, +) + @dataclass class RpmDep: @@ -37,12 +44,138 @@ class BundledDep: path: str version: str lang: str # "generic", "golang", "python", ... + vcs_url: str = "" + download_url: str = "" -def _bundled_purl(dep: BundledDep) -> str: - purl_type = LANG_TO_PURL_TYPE.get(dep.lang, "generic") +def _github_owner_repo(url: str) -> tuple[str, str] | None: + """Parse ``(owner, repo)`` from a github.com URL, or return ``None``.""" + if not url: + return None + match = _GITHUB_OWNER_REPO_RE.search(url) + if not match: + return None + owner = match.group(1).lower().rstrip(".") + repo = match.group(2).lower().rstrip(".") + if repo.endswith(".git"): + repo = repo[:-4] + return owner, repo + + +def _bundled_purls(dep: BundledDep) -> list[str]: + """Return one or more purls for a bundled dependency.""" ver = f"@{dep.version}" if dep.version else "" - return f"pkg:{purl_type}/{dep.path}{ver}" + purl_type = LANG_TO_PURL_TYPE.get(dep.lang, "generic") + + if purl_type != "generic": + base = f"pkg:{purl_type}/{dep.path}{ver}" + qualifiers: list[str] = [] + if dep.vcs_url: + qualifiers.append(f"vcs_url={quote(dep.vcs_url, safe='')}") + if dep.download_url: + qualifiers.append(f"download_url={quote(dep.download_url, safe='')}") + if qualifiers: + return [f"{base}?{'&'.join(qualifiers)}"] + return [base] + + github_coords = _github_owner_repo(dep.vcs_url) or _github_owner_repo(dep.download_url) + non_github_vcs = dep.vcs_url if dep.vcs_url and not _github_owner_repo(dep.vcs_url) else "" + non_github_download = ( + dep.download_url if dep.download_url and not _github_owner_repo(dep.download_url) else "" + ) + + if github_coords: + owner, repo = github_coords + purls = [f"pkg:github/{owner}/{repo}{ver}"] + generic_quals: list[str] = [] + if non_github_vcs: + generic_quals.append(f"vcs_url={quote(non_github_vcs, safe='')}") + if non_github_download: + generic_quals.append(f"download_url={quote(non_github_download, safe='')}") + if generic_quals: + purls.append(f"pkg:generic/{dep.path}{ver}?{'&'.join(generic_quals)}") + return purls + + base = f"pkg:generic/{dep.path}{ver}" + qualifiers: list[str] = [] + if dep.vcs_url: + qualifiers.append(f"vcs_url={quote(dep.vcs_url, safe='')}") + if dep.download_url: + qualifiers.append(f"download_url={quote(dep.download_url, safe='')}") + if qualifiers: + return [f"{base}?{'&'.join(qualifiers)}"] + return [base] + + +def _bundled_purl(dep: BundledDep) -> str: + """Primary purl for a bundled dependency (first entry from ``_bundled_purls``).""" + return _bundled_purls(dep)[0] + + +def source_purls( + name: str, + version: str, + download_url: str, + *, + checksum: str = "", +) -> list[str]: + """Return one or more purls for an upstream source archive (``Source0``, ``Source-origin``, …).""" + ver = f"@{version}" if version else "" + github_coords = _github_owner_repo(download_url) + + if github_coords: + owner, repo = github_coords + return [f"pkg:github/{owner}/{repo}{ver}"] + + base = f"pkg:generic/{name}{ver}" + qualifiers: list[str] = [] + if download_url: + qualifiers.append(f"download_url={quote(download_url, safe='')}") + if checksum: + qualifiers.append(f"checksum={checksum}") + if qualifiers: + return [f"{base}?{'&'.join(qualifiers)}"] + return [base] + + +def source_purl( + name: str, + version: str, + download_url: str, + *, + checksum: str = "", +) -> str: + """Primary purl for a source archive (first entry from ``source_purls``).""" + return source_purls(name, version, download_url, checksum=checksum)[0] + + +def _bundled_display_lang(dep: BundledDep) -> str: + if dep.lang != "generic": + return dep.lang + if _github_owner_repo(dep.vcs_url) or _github_owner_repo(dep.download_url): + return "github" + return dep.lang + + +def _bundled_display_name(dep: BundledDep) -> str: + if _bundled_display_lang(dep) == "github": + coords = _github_owner_repo(dep.vcs_url) or _github_owner_repo(dep.download_url) + label = f"{coords[0]}/{coords[1]}" if coords else dep.path + else: + label = dep.path + lang = _bundled_display_lang(dep) + name = f"{label} ({lang})" + if dep.version: + name = f"{name} {dep.version}" + return name + + +def _download_location(dep: BundledDep) -> str: + if dep.vcs_url: + return dep.vcs_url + if dep.download_url: + return dep.download_url + return "NOASSERTION" def _dep_lang_from_inner(name_inner: str) -> tuple[str, str]: @@ -138,25 +271,26 @@ def bundled_provides_to_spdx_fragments( packages: list[dict[str, Any]] = [] rels: list[dict[str, Any]] = [] for b in bundled: - pid = _ref_id(f"{b.path}\0{b.version}\0{b.lang}") - name = f"{b.path} ({b.lang})" - if b.version: - name = f"{name} {b.version}" + purls = _bundled_purls(b) + purl = purls[0] + pid = _ref_id(purl) + external_refs = [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": locator, + } + for locator in purls + ] packages.append( { "SPDXID": pid, - "name": name, + "name": _bundled_display_name(b), "versionInfo": b.version or "NOASSERTION", - "downloadLocation": "NOASSERTION", + "downloadLocation": _download_location(b), "filesAnalyzed": False, "primaryPackagePurpose": "LIBRARY", - "externalRefs": [ - { - "referenceCategory": "PACKAGE-MANAGER", - "referenceType": "purl", - "referenceLocator": _bundled_purl(b), - } - ], + "externalRefs": external_refs, } ) rels.append( @@ -174,14 +308,11 @@ def bundled_provides_to_cdx_components(bundled: list[BundledDep]) -> list[dict[s components: list[dict[str, Any]] = [] for b in bundled: purl = _bundled_purl(b) - name = f"{b.path} ({b.lang})" - if b.version: - name = f"{name} {b.version}" components.append( { "bom-ref": purl, "type": "library", - "name": name, + "name": _bundled_display_name(b), "version": b.version or None, "purl": purl, } diff --git a/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json b/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json index bed81f7..80d748b 100644 --- a/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json +++ b/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json @@ -1508,11 +1508,11 @@ "pedigree": { "ancestors": [ { - "bom-ref": "pkg:generic/delve@1.7.2?download_url=https://github.com/go-delve/delve/archive/v1.7.2.tar.gz#/delve-1.7.2.tar.gz", + "bom-ref": "pkg:github/go-delve/delve@1.7.2", "type": "library", "name": "delve", "version": "1.7.2", - "purl": "pkg:generic/delve@1.7.2?download_url=https://github.com/go-delve/delve/archive/v1.7.2.tar.gz#/delve-1.7.2.tar.gz", + "purl": "pkg:github/go-delve/delve@1.7.2", "hashes": [ { "alg": "SHA-256", diff --git a/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json b/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json index 06dc82e..eac6a1a 100644 --- a/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json +++ b/sbom/examples/rpm/build/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json @@ -492,7 +492,7 @@ { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": "pkg:generic/delve@1.7.2?download_url=https://github.com/go-delve/delve/archive/v1.7.2.tar.gz#/delve-1.7.2.tar.gz" + "referenceLocator": "pkg:github/go-delve/delve@1.7.2" } ] }, diff --git a/sbom/examples/rpm/build/from-koji.py b/sbom/examples/rpm/build/from-koji.py index 8fcdb75..f7ad588 100755 --- a/sbom/examples/rpm/build/from-koji.py +++ b/sbom/examples/rpm/build/from-koji.py @@ -13,6 +13,8 @@ bundled_golang_from_provides, bundled_provides_to_cdx_components, bundled_provides_to_spdx_fragments, + source_purl, + source_purls, ) # Script requires these RPMs: brewkoji, rpmdevtools, rpm-build @@ -220,12 +222,14 @@ def run_syft_cdx(self, builddir): @staticmethod def mock_midstream_cdx(digest, sname, sver, url): + checksum = f"sha256:{digest}" if digest else "" + purl = source_purl(sname, sver, url, checksum=checksum) return { - "bom-ref": f"pkg:generic/{sname}@{sver}?download_url={url}", + "bom-ref": purl, "type": "library", "name": sname, "version": sver, - "purl": f"pkg:generic/{sname}@{sver}?download_url={url}", + "purl": purl, "hashes": [{"alg": "SHA-256", "content": digest}], } @@ -247,8 +251,14 @@ def mock_midstream_spdx(self, digest, alg, source, sname, sver, url, ext): { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": f"pkg:generic/{sname}@{sver}?download_url={url}", + "referenceLocator": locator, } + for locator in source_purls( + sname, + sver, + url, + checksum=f"{alg.lower()}:{digest}", + ) ], } if ext: @@ -415,13 +425,18 @@ def handle_srpm(self, filename, name, version): del spackage["versioninfo"] if url != "NOASSERTION": - purl = f"pkg:generic/{name}@{version}?download_url={url}" spackage["externalRefs"] = [ { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": purl, + "referenceLocator": locator, } + for locator in source_purls( + sname, + sver, + url, + checksum=f"sha256:{digest}", + ) ] cdx_pedigree = self.mock_midstream_cdx(digest, sname, sver, url) diff --git a/sbom/examples/rpm/build/vim-9.1.083-5.el10.cdx.json b/sbom/examples/rpm/build/vim-9.1.083-5.el10.cdx.json index 52f5f99..970cb31 100644 --- a/sbom/examples/rpm/build/vim-9.1.083-5.el10.cdx.json +++ b/sbom/examples/rpm/build/vim-9.1.083-5.el10.cdx.json @@ -44,10 +44,11 @@ }, "components": [ { - "bom-ref": "pkg:generic/libvterm", + "bom-ref": "pkg:github/neovim/libvterm@0.3.3", "type": "library", - "name": "libvterm (generic)", - "purl": "pkg:generic/libvterm" + "name": "neovim/libvterm (github) 0.3.3", + "version": "0.3.3", + "purl": "pkg:github/neovim/libvterm@0.3.3" }, { "bom-ref": "pkg:rpm/redhat/vim-X11-debuginfo@9.1.083-5.el10?arch=aarch64&epoch=2", @@ -1200,7 +1201,7 @@ "pkg:rpm/redhat/xxd@9.1.083-5.el10?arch=x86_64&epoch=2" ], "dependsOn": [ - "pkg:generic/libvterm" + "pkg:github/neovim/libvterm@0.3.3" ] } ] diff --git a/sbom/examples/rpm/build/vim-9.1.083-5.el10.spdx.json b/sbom/examples/rpm/build/vim-9.1.083-5.el10.spdx.json index 986f447..df2f0e0 100644 --- a/sbom/examples/rpm/build/vim-9.1.083-5.el10.spdx.json +++ b/sbom/examples/rpm/build/vim-9.1.083-5.el10.spdx.json @@ -69,17 +69,22 @@ ] }, { - "SPDXID": "SPDXRef-Bundled-11cdd6f19dc1", - "name": "libvterm (generic)", - "versionInfo": "NOASSERTION", - "downloadLocation": "NOASSERTION", + "SPDXID": "SPDXRef-Bundled-b33d2447bd15", + "name": "neovim/libvterm (github) 0.3.3", + "versionInfo": "0.3.3", + "downloadLocation": "git+https://github.com/neovim/libvterm", "filesAnalyzed": false, "primaryPackagePurpose": "LIBRARY", "externalRefs": [ { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": "pkg:generic/libvterm" + "referenceLocator": "pkg:github/neovim/libvterm@0.3.3" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:generic/libvterm@0.3.3?download_url=http%3A%2F%2Fwww.leonerd.org.uk%2Fcode%2Flibvterm" } ] }, @@ -1752,7 +1757,7 @@ "relatedSpdxElement": "SPDXRef-Source0" }, { - "spdxElementId": "SPDXRef-Bundled-11cdd6f19dc1", + "spdxElementId": "SPDXRef-Bundled-b33d2447bd15", "relationshipType": "DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-SRPM" }, diff --git a/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json b/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json index 38cd242..9c3dc13 100644 --- a/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json +++ b/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.cdx.json @@ -1556,11 +1556,11 @@ "pedigree": { "ancestors": [ { - "bom-ref": "pkg:generic/delve@1.7.2?download_url=https://github.com/go-delve/delve/archive/v1.7.2.tar.gz#/delve-1.7.2.tar.gz", + "bom-ref": "pkg:github/go-delve/delve@1.7.2", "type": "library", "name": "delve", "version": "1.7.2", - "purl": "pkg:generic/delve@1.7.2?download_url=https://github.com/go-delve/delve/archive/v1.7.2.tar.gz#/delve-1.7.2.tar.gz", + "purl": "pkg:github/go-delve/delve@1.7.2", "hashes": [ { "alg": "SHA-256", diff --git a/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json b/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json index 7adcfe2..4a7e762 100644 --- a/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json +++ b/sbom/examples/rpm/release/delve-1.7.2-1.module+el8.6.0+12972+ebab5911.spdx.json @@ -512,7 +512,7 @@ { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": "pkg:generic/delve@1.7.2?download_url=https://github.com/go-delve/delve/archive/v1.7.2.tar.gz#/delve-1.7.2.tar.gz" + "referenceLocator": "pkg:github/go-delve/delve@1.7.2" } ] }, diff --git a/sbom/examples/rpm/release/vim-9.1.083-5.el10.cdx.json b/sbom/examples/rpm/release/vim-9.1.083-5.el10.cdx.json index 34bcefa..48c6769 100644 --- a/sbom/examples/rpm/release/vim-9.1.083-5.el10.cdx.json +++ b/sbom/examples/rpm/release/vim-9.1.083-5.el10.cdx.json @@ -1942,17 +1942,18 @@ } }, { - "bom-ref": "pkg:generic/libvterm", + "bom-ref": "pkg:github/neovim/libvterm@0.3.3", "type": "library", - "name": "libvterm (generic)", - "purl": "pkg:generic/libvterm" + "name": "neovim/libvterm (github) 0.3.3", + "version": "0.3.3", + "purl": "pkg:github/neovim/libvterm@0.3.3" } ], "dependencies": [ { "ref": "pkg:rpm/redhat/vim@9.1.083-5.el10?arch=src&epoch=2", "dependsOn": [ - "pkg:generic/libvterm" + "pkg:github/neovim/libvterm@0.3.3" ], "provides": [ "pkg:rpm/redhat/vim-X11-debuginfo@9.1.083-5.el10?arch=aarch64&epoch=2", diff --git a/sbom/examples/rpm/release/vim-9.1.083-5.el10.spdx.json b/sbom/examples/rpm/release/vim-9.1.083-5.el10.spdx.json index b17a9f4..76690b8 100644 --- a/sbom/examples/rpm/release/vim-9.1.083-5.el10.spdx.json +++ b/sbom/examples/rpm/release/vim-9.1.083-5.el10.spdx.json @@ -139,17 +139,22 @@ ] }, { - "SPDXID": "SPDXRef-Bundled-11cdd6f19dc1", - "name": "libvterm (generic)", - "versionInfo": "NOASSERTION", - "downloadLocation": "NOASSERTION", + "SPDXID": "SPDXRef-Bundled-b33d2447bd15", + "name": "neovim/libvterm (github) 0.3.3", + "versionInfo": "0.3.3", + "downloadLocation": "git+https://github.com/neovim/libvterm", "filesAnalyzed": false, "primaryPackagePurpose": "LIBRARY", "externalRefs": [ { "referenceCategory": "PACKAGE-MANAGER", "referenceType": "purl", - "referenceLocator": "pkg:generic/libvterm" + "referenceLocator": "pkg:github/neovim/libvterm@0.3.3" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:generic/libvterm@0.3.3?download_url=http%3A%2F%2Fwww.leonerd.org.uk%2Fcode%2Flibvterm" } ] }, @@ -2282,7 +2287,7 @@ "relatedSpdxElement": "SPDXRef-Source0" }, { - "spdxElementId": "SPDXRef-Bundled-11cdd6f19dc1", + "spdxElementId": "SPDXRef-Bundled-b33d2447bd15", "relationshipType": "DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-SRPM" },