Source code for tests.test_sbom_base

# Copyright Kevin Deldycke <[email protected]> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

from __future__ import annotations

import subprocess
import sys
from collections import Counter
from textwrap import dedent

import pytest

from meta_package_manager.sbom.base import SBOM, writer_unavailable_reason
from meta_package_manager.summary import sbom_summary

# No module-level `importorskip` here on purpose, unlike every other SBOM test
# module: what this covers is the message shown when a writer library is missing or
# too old, so skipping it exactly when that is true would cover nothing.


[docs] def test_writer_unavailable_reason_separates_absent_from_outdated(): """The two failure modes need opposite remedies, so they cannot share a message. A distribution shipping a writer library below the floor already satisfies `[sbom-offline]`, so telling its user to install that extra strands them: they install it again, nothing changes, and the only clue left is a symbol name belonging to no package they can name. NixOS carries exactly such a `cyclonedx-python-lib`. """ absent = writer_unavailable_reason( "no-such-distribution", ImportError("No module named 'nope'") ) assert "is not installed" in absent assert "--upgrade" not in absent # Any installed distribution stands in for the outdated case: the branch # turns on the distribution being present, not on which one it is. pytest is # installed wherever the suite runs, unlike mpm in a distribution's test phase. outdated = writer_unavailable_reason( "pytest", ImportError("cannot import name 'PredefinedLifecycle'"), ) assert "is installed but too old" in outdated assert "PredefinedLifecycle" in outdated assert "--upgrade" in outdated
[docs] def test_spdx_names_a_missing_packageurl_python(): """A missing packageurl-python disables the SPDX writer under its own name. spdx-tools does not depend on it, so an install can carry spdx-tools alone. A message calling spdx-tools too old would send the user to upgrade the wrong package. Runs in a fresh interpreter, where a blocked `packageurl` import and a hidden distribution stand for the missing one. """ pytest.importorskip("spdx_tools") probe = dedent(""" import sys from importlib import metadata sys.modules["packageurl"] = None installed_version = metadata.version def version(name): if name == "packageurl-python": raise metadata.PackageNotFoundError(name) return installed_version(name) metadata.version = version from meta_package_manager.sbom import spdx print(spdx.spdx_unavailable_reason) """) result = subprocess.run( (sys.executable, "-c", probe), capture_output=True, text=True, encoding="UTF-8", check=True, ) assert result.stdout.startswith("packageurl-python is not installed."), ( result.stdout )
[docs] class CannedStatsSBOM(SBOM): """A document reporting fixed statistics, to drive the summary adapter.""" def __init__(self, stats: dict[str, object]) -> None: super().__init__() self.canned_stats = stats
[docs] def stats(self) -> dict[str, object]: return self.canned_stats
[docs] @pytest.mark.parametrize( ("stats", "bundled", "notes"), ( pytest.param( {"packages_per_manager": {"brew": 3}, "enriched_per_manager": {"brew": 2}}, True, ["2/3 packages enriched with metadata."], id="enriched", ), pytest.param( {"packages_per_manager": {"brew": 3}, "enriched_per_manager": {"brew": 2}}, False, [], id="minimal", ), pytest.param( {"merged_documents": 2, "transitive_packages_merged": 5}, False, ["2 upstream SBOM documents merged, adding 5 transitive packages."], id="merged-with-transitive-packages", ), pytest.param( {"merged_documents": 1}, False, ["1 upstream SBOM documents merged."], id="merged", ), pytest.param( {"external_bom_references": 4}, False, ["4 per-package upstream SBOMs attached by reference."], id="bom-references", ), pytest.param( {"dependency_relationships": 6, "dependency_edges": 7}, False, ["6 dependency relationships emitted.", "7 dependency edges emitted."], id="dependencies", ), pytest.param( {"vulnerabilities_total": 2, "vulnerable_packages": 1}, False, ["2 vulnerabilities found across 1 packages."], id="vulnerabilities", ), ), ) def test_sbom_summary_notes(stats, bundled, notes): """Each note appears when the run produced what it counts, and only then.""" counts, rendered = sbom_summary(CannedStatsSBOM(stats), bundled) assert counts == Counter(stats.get("packages_per_manager", {})) assert rendered == notes
[docs] def test_all_purls_is_left_to_each_renderer(): with pytest.raises(NotImplementedError): SBOM().all_purls()
[docs] def test_an_alias_equal_to_its_own_purl_is_not_indexed(): """A coordinate cannot be an alias of itself.""" sbom = SBOM() purl = "pkg:pypi/[email protected]" sbom.register_purl_aliases(purl, (purl,)) assert sbom.primary_purls == {purl} assert sbom.purl_aliases == {}
[docs] def test_a_package_is_counted_once(): """A renderer that records one package twice still counts it once.""" sbom = SBOM() sbom._track_addition("pip", "yt-dlp", None) sbom._track_addition("pip", "yt-dlp", None) assert sbom.packages_per_manager == {"pip": 1}