174 lines
6.4 KiB
Python
174 lines
6.4 KiB
Python
import importlib.metadata
|
|
import importlib.util
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from gti_discovery import provenance
|
|
|
|
|
|
def _patch_environment(monkeypatch, tmp_path, *, origin=None, version="2.0.4"):
|
|
project_root = tmp_path / "project"
|
|
project_root.mkdir()
|
|
site_packages = tmp_path / "approved-site-packages"
|
|
site_packages.mkdir()
|
|
module_file = origin or site_packages / "fdb" / "__init__.py"
|
|
module_file.parent.mkdir(parents=True, exist_ok=True)
|
|
module_file.write_text("# fixture", encoding="ascii")
|
|
distribution = {
|
|
"Name": "fdb",
|
|
"Version": version,
|
|
"Location": str(site_packages),
|
|
}
|
|
monkeypatch.setattr(
|
|
importlib.util,
|
|
"find_spec",
|
|
lambda name: type("Spec", (), {
|
|
"origin": str(module_file),
|
|
"submodule_search_locations": [str(module_file.parent)],
|
|
})() if name == "fdb" else None,
|
|
)
|
|
monkeypatch.setattr(importlib.metadata, "version", lambda name: version)
|
|
monkeypatch.setattr(importlib.metadata, "distribution", lambda name: type(
|
|
"Distribution", (), {
|
|
"metadata": distribution,
|
|
"locate_file": lambda self, value: site_packages / value,
|
|
}
|
|
)())
|
|
monkeypatch.setattr(provenance, "PROJECT_ROOT", project_root)
|
|
monkeypatch.setattr(provenance, "APPROVED_SITE_PACKAGES_ROOT", site_packages)
|
|
monkeypatch.setattr(provenance.sys, "path", [str(site_packages)])
|
|
monkeypatch.setenv("PYTHONPATH", str(site_packages))
|
|
return site_packages, module_file
|
|
|
|
|
|
def test_inspection_correlates_module_and_distribution_without_importing_fdb(monkeypatch, tmp_path):
|
|
site_packages, module_file = _patch_environment(monkeypatch, tmp_path)
|
|
|
|
evidence = provenance.inspect_fdb_provenance()
|
|
|
|
assert evidence["module_file"] == str(module_file.resolve())
|
|
assert evidence["module_package"] == "fdb"
|
|
assert evidence["module_version"] == "2.0.4"
|
|
assert evidence["distribution_name"] == "fdb"
|
|
assert evidence["distribution_version"] == "2.0.4"
|
|
assert evidence["distribution_location"] == str(site_packages.resolve())
|
|
assert evidence["module_under_distribution"] is True
|
|
assert evidence["shadowing"] == []
|
|
assert evidence["status"] == "VALID"
|
|
|
|
|
|
def test_validation_accepts_matching_installed_provenance(monkeypatch, tmp_path):
|
|
_patch_environment(monkeypatch, tmp_path)
|
|
|
|
evidence = provenance.validate_fdb_provenance()
|
|
|
|
assert evidence["status"] == "VALID"
|
|
assert evidence["validated_version"] == "2.0.4"
|
|
|
|
|
|
@pytest.mark.parametrize("shadow", ["fdb.py", "fdb"])
|
|
def test_validation_rejects_project_local_shadowing(monkeypatch, tmp_path, shadow):
|
|
_patch_environment(monkeypatch, tmp_path)
|
|
local = provenance.PROJECT_ROOT / shadow
|
|
if shadow == "fdb":
|
|
local.mkdir()
|
|
(local / "__init__.py").write_text("# shadow", encoding="ascii")
|
|
else:
|
|
local.write_text("# shadow", encoding="ascii")
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="shadow"):
|
|
provenance.validate_fdb_provenance()
|
|
|
|
|
|
def test_validation_rejects_project_pth_candidate(monkeypatch, tmp_path):
|
|
_patch_environment(monkeypatch, tmp_path)
|
|
(provenance.PROJECT_ROOT / "unexpected.pth").write_text("evil", encoding="ascii")
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="shadow"):
|
|
provenance.validate_fdb_provenance()
|
|
|
|
|
|
def test_validation_blocks_mismatched_distribution(monkeypatch, tmp_path):
|
|
_patch_environment(monkeypatch, tmp_path, version="2.0.3")
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="version"):
|
|
provenance.validate_fdb_provenance()
|
|
|
|
|
|
def test_validation_blocks_ambiguous_origin(monkeypatch, tmp_path):
|
|
site_packages, module_file = _patch_environment(monkeypatch, tmp_path)
|
|
duplicate = site_packages / "fdb.py"
|
|
duplicate.write_text("# duplicate", encoding="ascii")
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="ambiguous"):
|
|
provenance.validate_fdb_provenance()
|
|
|
|
|
|
def test_validation_rejects_distribution_outside_approved_environment(monkeypatch, tmp_path):
|
|
_patch_environment(monkeypatch, tmp_path)
|
|
external = tmp_path / "unapproved-site-packages"
|
|
external.mkdir()
|
|
module_file = external / "fdb" / "__init__.py"
|
|
module_file.parent.mkdir()
|
|
module_file.write_text("# external", encoding="ascii")
|
|
monkeypatch.setattr(importlib.util, "find_spec", lambda name: type(
|
|
"Spec", (), {"origin": str(module_file), "name": "fdb"}
|
|
)())
|
|
monkeypatch.setattr(importlib.metadata, "distribution", lambda name: type(
|
|
"Distribution", (), {
|
|
"metadata": {"Name": "fdb", "Version": "2.0.4"},
|
|
"locate_file": lambda self, value: external / value,
|
|
}
|
|
)())
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="approved"):
|
|
provenance.validate_fdb_provenance()
|
|
|
|
|
|
def test_validation_rejects_shadowing_under_project_site_packages(monkeypatch, tmp_path):
|
|
_patch_environment(monkeypatch, tmp_path)
|
|
local = provenance.PROJECT_ROOT / "site-packages" / "fdb.py"
|
|
local.parent.mkdir(parents=True)
|
|
local.write_text("# shadow", encoding="ascii")
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="shadow"):
|
|
provenance.validate_fdb_provenance()
|
|
|
|
|
|
def test_post_import_validation_checks_actual_module_attributes(monkeypatch, tmp_path):
|
|
_patch_environment(monkeypatch, tmp_path)
|
|
imported = type("Fdb", (), {
|
|
"__file__": str(tmp_path / "wrong" / "fdb.py"),
|
|
"__package__": "wrong",
|
|
"__version__": "2.0.4",
|
|
})()
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="imported"):
|
|
provenance.validate_imported_fdb_provenance(imported)
|
|
|
|
|
|
def test_post_import_validation_accepts_matching_module_and_version(monkeypatch, tmp_path):
|
|
_, module_file = _patch_environment(monkeypatch, tmp_path)
|
|
imported = type("Fdb", (), {
|
|
"__file__": str(module_file),
|
|
"__package__": "fdb",
|
|
"__version__": "2.0.4",
|
|
})()
|
|
|
|
evidence = provenance.validate_imported_fdb_provenance(imported)
|
|
|
|
assert evidence["status"] == "VALID"
|
|
assert evidence["imported_module_file"] == str(module_file.resolve())
|
|
|
|
|
|
def test_post_import_validation_rejects_missing_version(monkeypatch, tmp_path):
|
|
_, module_file = _patch_environment(monkeypatch, tmp_path)
|
|
imported = type("Fdb", (), {
|
|
"__file__": str(module_file),
|
|
"__package__": "fdb",
|
|
})()
|
|
|
|
with pytest.raises(provenance.ProvenanceError, match="version"):
|
|
provenance.validate_imported_fdb_provenance(imported)
|