meta_package_manager.sbom.vulnerabilities module¶
Vulnerability lookup against OSV.dev.
The scan_vulnerabilities() entry point takes the set of purls a
rendered SBOM holds and returns the advisories affecting each, normalized
into the source-agnostic Vulnerability dataclass. The SBOM
renderers consume that mapping in their finalize step (CycloneDX into
Bom.vulnerabilities, SPDX into per-package security externalRefs).
OSV is the single source for this first iteration because it indexes by ecosystem coordinates directly, sidestepping the fuzzy package-name to CPE matching that NVD would require. Coverage is strongest for language ecosystems (PyPI, npm, crates.io, RubyGems, Packagist); system package managers like Homebrew are not in OSV, so their packages come back with no advisories rather than an error.
Note
Covering system package managers (brew, apt, macports,
mas, …) means going through NVD, which indexes by CPE
(vendor/product plus version ranges) rather than by ecosystem
coordinate. That route is deliberately deferred: mapping a package
name to its CPE is fuzzy and the main source of false positives,
and NVD offers no batch coordinate lookup to match OSV’s
querybatch. Until that lands, system-package coverage means
pointing a CPE-based scanner (OSV-Scanner, Grype, Trivy, or Intel’s
cve-bin-tool) directly at the host. Feeding them the rendered
CycloneDX/SPDX is not enough: the exported components carry purls
but no CPEs, so a pkg:brew/... entry decodes as an
unknown-ecosystem package and silently matches nothing (verified
against Grype 0.115.0).
See also
VulnerableCode is the candidate second source: it aggregates OSV, GitHub and the Linux distro trackers (Debian, Arch, Gentoo, Red Hat, SUSE, Ubuntu) plus project-specific feeds behind a purl-keyed API, with a public instance at public.vulnerablecode.io. That would widen coverage beyond OSV’s language ecosystems without mpm taking on CPE mapping itself.
Two-stage protocol:
A batched
POST /v1/querybatchmaps each queried coordinate to a list of advisory IDs (the batch response carries IDs only).A per-ID
GET /v1/vulns/{id}fetches the full record. These records are immutable once published, so they cache effectively forever; the batch listings get a finite TTL since new advisories can appear.
Network transport, retries, and caching are handled by
meta_package_manager.sbom._network.NetworkClient.
- meta_package_manager.sbom.vulnerabilities.OSV_BASE_URL = 'https://api.osv.dev'¶
Base URL of the OSV.dev REST API.
- meta_package_manager.sbom.vulnerabilities.OSV_ADVISORY_URL = 'https://osv.dev/vulnerability'¶
Prefix of the human-facing OSV advisory page.
Deliberately the web host (
osv.dev), distinct from the API host (api.osv.dev) thatOSV_BASE_URLanchors.
- meta_package_manager.sbom.vulnerabilities.OSV_BATCH_LIMIT = 1000¶
Maximum number of queries OSV accepts in a single
querybatchcall.
- meta_package_manager.sbom.vulnerabilities.VULN_DETAIL_TTL = 2592000¶
Cache TTL for per-advisory detail records (30 days).
OSV advisory records are effectively immutable once published (the
modifiedfield changes rarely), so a long TTL avoids re-fetching the same record on every scan while still picking up the occasional correction within a month.
- meta_package_manager.sbom.vulnerabilities.OSV_ECOSYSTEMS: dict[str, str] = {'cargo': 'crates.io', 'composer': 'Packagist', 'gem': 'RubyGems', 'npm': 'npm', 'pip': 'PyPI', 'pipx': 'PyPI', 'yarn': 'npm'}¶
Maps mpm manager ids to OSV ecosystem names.
- class meta_package_manager.sbom.vulnerabilities.Vulnerability(id, source='OSV', summary=None, description=None, severity=None, cvss_vector=None, cwe_ids=(), aliases=(), references=(), fixed_versions=(), published_date=None, modified_date=None, advisory_url='')[source]¶
Bases:
objectNormalized vulnerability record, source-agnostic on its surface.
Populated from OSV today; the shape deliberately avoids OSV-specific fields so a future NVD or GHSA source can fill the same structure.
- severity: str | None = None¶
Coarse label:
low/medium/high/critical, orNonewhen the source provides no rating.
- meta_package_manager.sbom.vulnerabilities.scan_vulnerabilities(purls, client)[source]¶
Look up advisories for every supported purl, via OSV.
Returns a mapping from purl string to the tuple of vulnerabilities affecting it. Purls with no advisories (or no OSV coverage) are simply absent from the result. A network failure on the batch query propagates as
NetworkErrorfor the caller to handle; per-advisory detail failures are swallowed so a single bad record only drops itself.- Return type:
dict[str,tuple[Vulnerability,...]]