SBOM: Software Bill of Materials¶
Context
The Log4Shell vulnerability debacle was a wake-up call for the industry. This dependency was deeply embedded in the legacy stack of companies and administrations. They all had huge difficulty to identify its presence, writing custom detection scripts and scanning their software artifacts.
As a response to this crisis, SBOM tools have now became a category of their own. To the point that a US executive order has also been released to modernize cybersecurity practices and enforce the production of SBOM to track the software supply chain.
mpm can export the list of installed packages as a SBOM in two standards and multiple formats:
SBOM export is the compliance corner of mpm’s inventory exports: for re-installable snapshots see Snapshot and export, and for ad-hoc JSON or CSV piping of a listing see JSON & CSV exports.
For example:
$ mpm --brew --gem sbom --spdx --format yaml
291 packages total (brew: 229, gem: 62).
229/291 packages enriched with metadata.
SPDXID: SPDXRef-DOCUMENT
creationInfo:
created: '2024-07-30T15:48:45Z'
creators:
- 'Tool: meta-package-manager-5.18.0'
dataLicense: CC0-1.0
documentNamespace: https://github.com/kdeldycke/meta-package-manager/releases/tag/v5.18.0/dd72ff542938a2d40620dc249e91e35
name: macOS-Darwin-23.6.0-arm64
packages:
- SPDXID: SPDXRef-Package-brew-curl
downloadLocation: https://www.example.com
filesAnalyzed: false
name: curl
primaryPackagePurpose: INSTALL
supplier: 'Organization: Homebrew Formulae'
versionInfo: 8.9.0
- SPDXID: SPDXRef-Package-brew-ffmpeg
downloadLocation: https://www.example.com
filesAnalyzed: false
name: ffmpeg
primaryPackagePurpose: INSTALL
supplier: 'Organization: Homebrew Formulae'
versionInfo: 7.0.1
- SPDXID: SPDXRef-Package-brew-xz
downloadLocation: https://www.example.com
filesAnalyzed: false
name: xz
primaryPackagePurpose: INSTALL
supplier: 'Organization: Homebrew Formulae'
versionInfo: 5.6.2
(...)
- SPDXID: SPDXRef-Package-gem-bundler
downloadLocation: https://www.example.com
filesAnalyzed: false
name: bundler
primaryPackagePurpose: INSTALL
supplier: 'Organization: RubyGems'
versionInfo: 2.4.22
- SPDXID: SPDXRef-Package-gem-libxml-ruby
downloadLocation: https://www.example.com
filesAnalyzed: false
name: libxml-ruby
primaryPackagePurpose: INSTALL
supplier: 'Organization: RubyGems'
versionInfo: 4.1.2
(...)
relationships:
- relatedSpdxElement: SPDXRef-Package-brew-curl
relationshipType: DESCRIBES
spdxElementId: SPDXRef-DOCUMENT
- relatedSpdxElement: SPDXRef-Package-brew-ffmpeg
relationshipType: DESCRIBES
spdxElementId: SPDXRef-DOCUMENT
- relatedSpdxElement: SPDXRef-Package-brew-xz
relationshipType: DESCRIBES
spdxElementId: SPDXRef-DOCUMENT
(...)
- relatedSpdxElement: SPDXRef-Package-gem-bundler
relationshipType: DESCRIBES
spdxElementId: SPDXRef-DOCUMENT
- relatedSpdxElement: SPDXRef-Package-gem-libxml-ruby
relationshipType: DESCRIBES
spdxElementId: SPDXRef-DOCUMENT
(...)
spdxVersion: SPDX-2.3
To export only a subset of the installed packages, filter with --query. The match is fuzzy by default (case-insensitive, tokenized), the same semantics as mpm search; pass --exact for a verbatim match on the package ID or name:
$ mpm --brew sbom --query openssl > openssl.spdx.json
Scan mode: --bundled vs --minimal¶
mpm sbom defaults to bundled mode: every manager that knows how is queried for richer per-package metadata (license, supplier, homepage, declared dependencies, source URL, checksums), per-package upstream SBOM documents are merged into the aggregate, and the result lands in the rendered SPDX or CycloneDX document. Bundled mode is the default because the magic of mpm sbom is collapsing N different manager APIs into one self-contained file.
When I only need a fast inventory pass, the --minimal flag short-circuits the metadata extractors and produces today’s bare output (name, version, purl):
$ mpm --brew sbom --minimal > inventory.spdx.json
Use --minimal for snapshot-style runs (cron jobs, drift detection) and --bundled (the default) for compliance, supply-chain audit, and vulnerability-scanner ingestion.
Layered SBOMs: aggregate + per-package upstream¶
Some package managers now publish their own per-package SBOM documents. Homebrew, for example, writes <prefix>/Cellar/<formula>/<version>/sbom.spdx.json when a formula is installed under HOMEBREW_SBOM=1 (added in 5.2.0). These are full SPDX 2.3 documents with the formula’s complete dependency closure, real download URLs, and bottle checksums.
mpm sbom --bundled discovers those files, splices them into the aggregate document, and records each one in externalDocumentRefs with its SHA1 so the merge is auditable. Transitive packages from the upstream document are renamed under a SPDXRef-brew-<formula>-<dep> namespace to avoid collisions across formulae that share dependencies.
For the same data in CycloneDX, the per-formula file is attached to its component via an externalReferences[type=bom] entry.
If HOMEBREW_SBOM=1 was never set, the file does not exist and mpm falls back silently to brew info --json=v2 for the same fields.
To get the deepest data possible:
$ HOMEBREW_SBOM=1 brew reinstall <formula>
$ mpm --brew sbom > deep.spdx.json
Coverage matrix¶
Manager |
License |
Homepage |
Download URL |
Checksums |
Dependency graph |
Per-package SBOM |
Vulnerabilities |
|---|---|---|---|---|---|---|---|
Homebrew |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ (opt-in) |
|
pip |
✓ |
✓ |
✓ |
✓ ( |
|||
npm |
✓ ( |
||||||
cargo |
✓ ( |
||||||
gem |
✓ ( |
||||||
composer |
✓ ( |
||||||
Others |
Coverage will expand: every manager exposes its metadata differently, and richer extractors land per manager over time. The vulnerability column tracks OSV.dev’s indexed ecosystems; a manager OSV does not index (Homebrew, mas, the distro managers OSV needs a release qualifier for) gets no advisories rather than an error.
For the license column specifically, Tern is a useful reference: a Python tool that derives per-package licenses across OS package managers and integrates ScanCode for file-level license detection, the data mpm would need to fill licenses beyond Homebrew and pip.
How mpm compares to other SBOM tools¶
mpm is not the only tool that emits an SBOM. The widely-used ones each occupy a different spot in the supply-chain landscape:
Tool |
By |
Language |
License |
What it reads |
SPDX |
CycloneDX |
purl |
|---|---|---|---|---|---|---|---|
this project |
Python |
GPL-2.0-or-later |
the live package managers on a host, queried directly |
✓ 2.3 |
✓ 1.7 |
✓ |
|
Anchore |
Go |
Apache-2.0 |
container images and filesystems (package DBs, lockfiles) |
✓ 2.3 |
✓ 1.6 |
✓ |
|
Aqua Security |
Go |
Apache-2.0 |
images, filesystems, repositories, VMs, clusters |
✓ 2.3 |
✓ 1.5 |
✓ |
|
tern-tools |
Python |
BSD-2-Clause |
container image layers (runs package managers in a chroot) |
✓ |
✓ |
||
OWASP CycloneDX |
JavaScript |
Apache-2.0 |
project manifests and lockfiles; a live host via |
✓ 3.0 |
✓ 1.7 |
✓ |
|
Microsoft |
C# |
MIT |
source-tree manifests and lockfiles (~30 detectors) |
via sbom-tool |
own schema |
||
Microsoft |
C# |
MIT |
build output and source tree (wraps component-detection) |
✓ 2.2, 3.0 |
Versions shown are each tool’s current default; Syft and cdxgen can also emit older spec revisions on request. mpm is on the newest CycloneDX (1.7), and cdxgen and sbom-tool reach the newest SPDX (3.0). Tern’s README states no spec versions or purl support for its output.
mpm differs from these tools in its data source, not its output format. Syft and Trivy read packages at rest: they parse the package databases already written into a container image or filesystem (the dpkg, apk, or rpm database, or a committed lockfile). cdxgen, component-detection, and sbom-tool parse a project’s declared manifests and lockfiles.
mpm invokes the package managers’ own command-line tools. It shells out to brew, apt, pip, npm, cargo, and the rest, and records what they report on the running host. That covers managers the file scanners do not model: Homebrew casks, mas, flatpak, snap, mise, and the others listed in Benchmark. The trade-off is symmetric: mpm needs the managers installed and runnable, while Syft or Trivy can scan an image or directory the host never executed.
This invoke-the-real-tool approach is not unique to mpm. CycloneDX’s own cargo-cyclonedx invokes Cargo rather than only parsing Cargo.lock, and Tern runs each container layer’s package manager in a chroot rather than reading its on-disk database. Both reflect what the manager itself resolves. mpm applies that principle across every manager it drives, on the live host.
The tools are complementary. Reach for Syft, Trivy, or cdxgen to inventory a build artifact, container, or source repository; reach for mpm sbom to inventory the software actually installed on a machine.
Vulnerability scanning¶
By default mpm sbom works entirely offline. Pass the global --network flag to enrich the document with known vulnerabilities, looked up against OSV.dev:
$ mpm --network sbom --cyclonedx > inventory.cdx.json
In CycloneDX output each advisory lands in the document’s vulnerabilities array, described once and pointing (through affects) at every component it impacts, with its severity rating, CVSS vector, CWE ids, aliases (the CVE behind a GHSA, for instance), and advisory links. SPDX 2.3 has no first-class vulnerability section, so each advisory is attached to its package as a SECURITY-category external reference of type advisory, with the severity and fixed-version facts folded into the reference comment.
Coverage tracks OSV’s ecosystems: language managers like pip, npm, cargo, gem, and composer resolve to OSV ecosystems and get scanned; system managers like Homebrew are not indexed by OSV, so their packages simply come back without advisories. Responses are cached on disk (under the OS user-cache directory) so repeat scans are fast and stay within OSV’s rate limits.
Network failures degrade gracefully: a missing extra, an unreachable OSV, or an unwritable cache logs a warning and still produces the SBOM, just without vulnerability data.
Caution
Running --network transmits the ecosystem coordinates of your installed packages (name, version, ecosystem) to OSV.dev. The offline default never makes network calls.
Installation¶
SBOM export is gated behind optional extras, split by usage:
[sbom-offline]pulls the CycloneDX and SPDX writer libraries needed to render documents from local data. This is whatmpm sbomneeds for its default offline operation.[sbom-online]adds the HTTP client and cache used bympm --network sbomfor the OSV.dev vulnerability lookups described above.
$ pip install meta-package-manager[sbom-offline]
For vulnerability scanning, install both:
$ uv tool install 'meta-package-manager[sbom-offline,sbom-online]'
Without [sbom-offline], mpm sbom exits with an explanatory error pointing at this install step. Without [sbom-online], the --network flag logs a warning and falls back to an offline document.
See also¶
JSON & CSV exports — JSON and CSV table exports for ad-hoc piping of
installed,outdated, andsearchresults.Snapshot and export — TOML manifest and Brewfile snapshots for re-installation workflows.
Cooldown — release-age gates that complement the SBOM workflow on the install side.
meta_package_manager.sbom API¶
Format-agnostic SBOM base class and export-format enum.
Kept deliberately free of SPDX or CycloneDX dependencies: instantiating
SBOM directly is meaningless, but importing the symbols here
is safe even when the optional [sbom-offline] extra is not installed.
- class meta_package_manager.sbom.base.ExportFormat(*values)[source]¶
Bases:
StrEnumA user-friendly version of
spdx_tools.spdx.formats.FileFormat.Map format to user-friendly IDs.
- JSON = 'json'¶
- XML = 'xml'¶
- YAML = 'yaml'¶
- TAG_VALUE = 'tag'¶
- RDF_XML = 'rdf'¶
- class meta_package_manager.sbom.base.SBOM(export_format=ExportFormat.JSON)[source]¶
Bases:
objectUtilities shared by all SBOM classes.
See also
Anchore’s Syft and Microsoft’s sbom-tool are mature SPDX and CycloneDX emitters, useful references for field-population conventions. Both inventory packages by parsing on-disk databases and lockfiles, whereas
mpmqueries the live managers directly.Defaults to JSON export format.
- vulnerabilities_by_purl: dict[str, tuple[Vulnerability, ...]]¶
- all_purls()[source]¶
Yield every package purl present in the document.
Powers the vulnerability scan: the network layer queries OSV once with the full purl set rather than once per package. Subclasses implement this against their own component index.
- attach_vulnerabilities(vulnerabilities)[source]¶
Bind cross-package vulnerability data to the document.
Called by the CLI between the per-package
add_packageloop andfinalize, only in--networkmode. Renderers read the stored data in theirfinalizeoverride and project it into the format-native vulnerability surface (CycloneDXvulnerabilitiesarray, SPDX securityexternalRefs).- Return type:
- stats()[source]¶
Return a summary of what landed in the document.
Format-agnostic counters live in the base implementation; SPDX and CycloneDX subclasses extend the returned dict with their own merged-documents, dependency-graph, and any other format-specific counts. Surfaced by the CLI as a post-run INFO-level summary and usable by tests or programmatic consumers without re-parsing the rendered document.
- finalize()[source]¶
Resolve any deferred state before
export().Some constructs cannot be emitted at
add_package()time because they reference packages that may not have been added yet: a Homebrew formula’s runtime dependency on another formula listed later in the scan, for example. Subclasses queue those duringadd_packageand flush them here. The base implementation is a no-op so subclasses can rely on it being called exactly once.- Return type:
CycloneDX 1.7 writer.
Heavy cyclonedx-python-lib imports are guarded behind a try/except
block; cyclonedx_support reports whether the
CycloneDX class can actually be used.
The license-normalization helper is shared with spdx and is
imported from there rather than duplicated: SPDX license expressions are
the lingua franca CycloneDX builds on, so the dependency direction is
intentional and acyclic.
- class meta_package_manager.sbom.cyclonedx.CycloneDX(export_format=ExportFormat.JSON)[source]¶
Bases:
SBOMGenerates a CycloneDX document from a list of packages.
Defaults to JSON export format.
- document: Bom¶
- init_doc()[source]¶
CycloneDX document metadata specifications.
- Return type:
- add_package(manager, package, metadata=PackageMetadata(download_url=None, homepage=None, vcs_url=None, issue_tracker_url=None, distribution_url=None, license_declared=None, license_concluded=None, copyright_text=None, supplier=None, originator=None, description=None, summary=None, cpe=None, dependencies=(), checksums=(), files=(), files_analyzed=False, install_date=None, build_date=None, release_date=None, external_sbom_path=None, extra_purls=(), extras={}))[source]¶
CycloneDX package metadata specifications.
- Return type:
- all_purls()[source]¶
Yield every component purl in insertion order.
Each component’s
bom_refis its purl string, so the same values double as the vulnerabilityaffectstargets infinalize().- Return type:
- finalize()[source]¶
Resolve queued dependency edges and attach vulnerability records.
Mirrors
meta_package_manager.sbom.spdx.SPDX.finalize(). Dangling references (the dependency target is not in the inventory) are dropped silently.Vulnerability data bound via
meta_package_manager.sbom.base.SBOM.attach_vulnerabilities()is projected into the CycloneDXvulnerabilitiesarray. Each advisory is described once at the document level with anaffectslist pointing at every component (bybom_ref, which equals the purl) it impacts.- Return type:
- stats()[source]¶
Extend the base stats with CycloneDX-specific counters.
CycloneDX has no merge-content equivalent: per-package upstream SBOMs are linked through
externalReferences[type=bom]rather than spliced in. The merged-document count therefore reports the number of components carrying a BOM external reference. The dependency-edge total walks the registered dependency graph and sums thedependsOncollection size across every entry.
- export()[source]¶
Serialize the document to its string representation.
Note
Unlike
meta_package_manager.sbom.spdx.SPDX.export(), the generated document is not validated against its schema here. CycloneDX schema validation relies oncyclonedx-python-lib’s[validation]extra, which pulls injsonschemaand, transitively,rfc3987-syntax,lark, andlxml. To keep that stack out ofmpm’s runtime dependencies, the validation runs in the test suite instead. Seetests/test_cli_sbom.py.- Return type:
SPDX 2.3 writer plus the per-package upstream-SBOM merge logic.
Heavy spdx_tools imports are guarded behind a try/except block so
this module is importable even when the optional [sbom-offline] extra is
not installed; in that case spdx_support is False and the
SPDX class is still defined for type-hint compatibility but
will not function (every public method depends on the missing imports).
_parse_license_expression and _coerce_spdx_string live here
because they both touch spdx_tools types; cyclonedx
imports the former for its own license normalization, which is one-way
and acyclic.
- class meta_package_manager.sbom.spdx.SPDX(export_format=ExportFormat.JSON)[source]¶
Bases:
SBOMGenerates an SPDX document from a list of packages.
Defaults to JSON export format.
- DOC_ID = 'SPDXRef-DOCUMENT'¶
Document root ID.
- document: Document¶
- classmethod normalize_spdx_id(value)[source]¶
SPDX IDs must only contain letters, numbers,
.and-.- Return type:
- init_doc()[source]¶
SPDX document metadata specifications.
- Return type:
- add_package(manager, package, metadata=PackageMetadata(download_url=None, homepage=None, vcs_url=None, issue_tracker_url=None, distribution_url=None, license_declared=None, license_concluded=None, copyright_text=None, supplier=None, originator=None, description=None, summary=None, cpe=None, dependencies=(), checksums=(), files=(), files_analyzed=False, install_date=None, build_date=None, release_date=None, external_sbom_path=None, extra_purls=(), extras={}))[source]¶
SPDX package metadata specifications.
- Return type:
- all_purls()[source]¶
Yield every inventory package purl in insertion order.
Only the directly-installed packages carry a purl in
purl_index; transitive packages spliced in from merged upstream SBOMs are not queried for vulnerabilities (their own upstream document already carries that provenance, and they are not what the user installed).- Return type:
- finalize()[source]¶
Emit pending dependency relationships and vulnerability refs.
Walks the queue built by
add_package()and emits each relationship only when both ends resolve to packages we actually included in the document. Dangling references (the target package is not installed) are dropped silently: the SBOM only describes what is on the system, not what could be.Then attaches any vulnerability data bound via
attach_vulnerabilities(). SPDX 2.3 has no first-class vulnerability section, so each advisory becomes a SECURITY-categoryExternalPackageRefof typeadvisoryon the affected package, pointing at the advisory URL.- Return type:
- stats()[source]¶
Extend the base stats with SPDX-specific counters.
Adds the number of upstream documents merged into the aggregate, the count of transitive packages those upstream documents contributed (over and above the inventory pass), and the total relationship count partitioned into dependency vs descriptive edges.
packages_totalfrom the base reports inventory packages only;packages_in_documenthere is the full count after merge, which is what consumers of the file actually see.
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, the rendered document is standard
CycloneDX/SPDX, so anyone needing system-package coverage can feed
it to an external CPE-based scanner (OSV-Scanner, Grype, Trivy, or
Intel’s cve-bin-tool).
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_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,...]]
HTTP client and on-disk response cache for the opt-in online SBOM mode.
This is the shared plumbing behind mpm --network sbom. The
NetworkClient wraps httpx with a filesystem cache and a
bounded retry/backoff policy, so the higher-level adapters (currently
just meta_package_manager.sbom.vulnerabilities, which queries
OSV.dev) stay free of transport concerns.
Heavy imports (httpx, platformdirs) are guarded behind a
try/except exactly like the SPDX and CycloneDX writers: a default
install does not pull them, so this module is importable but
network_support reports False until the user installs the
[sbom-online] extra.
The cache is mandatory rather than optional. The online mode is only
worth using with a warm cache: vulnerability records are immutable once
published, batch queries are large, and remote services rate-limit. The
cache lives under the OS-appropriate user cache directory (resolved via
platformdirs) so repeat runs hit disk instead of the network.
- meta_package_manager.sbom._network.DEFAULT_TTL = 86400¶
Default cache time-to-live in seconds (24 hours).
Vulnerability listings (which advisories affect a package) can change as new advisories are published, so the batch-query responses get this finite TTL. Immutable per-advisory detail records are cached with a far longer TTL by their callers.
- meta_package_manager.sbom._network.DEFAULT_TIMEOUT = 30.0¶
Per-request timeout in seconds.
OSV batch queries over a few hundred purls comfortably answer within this window; the value is generous enough to absorb a slow link without hanging a scan indefinitely.
- meta_package_manager.sbom._network.MAX_RETRIES = 3¶
Number of retry attempts on transient failures before giving up.
- meta_package_manager.sbom._network.CACHE_SIZE_CEILING = 1000000000¶
Soft ceiling (1 GB) past which the cache directory is pruned.
The cache is keyed by unique request payloads the user has ever issued, so in practice it stays tiny (a few MB of JSON). The ceiling is a runaway backstop, not an expected operating point.
- exception meta_package_manager.sbom._network.NetworkError[source]¶
Bases:
ExceptionRaised when a network operation cannot complete.
The CLI catches this at the orchestration layer and degrades gracefully: the SBOM still renders, just without the data the failed call would have contributed.
- class meta_package_manager.sbom._network.NetworkClient(*, cache_dir=None, default_ttl=86400, timeout=30.0, trust_env=True)[source]¶
Bases:
objectCaching HTTP client for the online SBOM adapters.
Construct one per
mpm sbomrun and pass it to the adapter functions. The same instance reuses a singlehttpx.Client(connection pooling) and one cache directory for the whole run.Warning
Instantiating requires the
[sbom-online]extra. Callers must checknetwork_supportbefore constructing, mirroring thespdx_support/cyclonedx_supportguards used by the renderers.Set up the cache directory and the underlying HTTP client.
cache_dirdefaults to<user-cache>/meta-package-manager/sbomwhen not supplied. The directory is created if missing.trust_envis forwarded tohttpx.Client: leftTrueso a user’sHTTP(S)_PROXY/ALL_PROXYenvironment is honored. The test suite sets itFalseto bypass any ambient proxy.- property client: Client¶
The underlying HTTP client, constructed on first access.
A construction failure (notably a configured SOCKS proxy with no
socksioinstalled) is converted toNetworkErrorso the caller degrades gracefully rather than surfacing a rawImportErrorfrom deep in httpx.