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)