Files

166 lines
5.7 KiB
Python

"""Final deletion-backed gate for the detection-core v1 migration."""
from __future__ import annotations
import ast
import hashlib
import json
import subprocess
import sys
from pathlib import Path
from core_migration_boundary import BoundaryPhase, boundary_python, inspect_legacy_boundary, require_cutover_ready
from core_migration_inventory import load_migration_inventory, validate_historical_artifacts
REPO = Path(__file__).resolve().parents[1]
CORE = REPO / "src/openultrasast/core"
INVENTORY = REPO / "tests/fixtures/detection_core/v1/migration_inventory.json"
REMOVED_PATHS = (
CORE / "legacy_v1",
CORE / "trace.py",
CORE / "_legacy_factpack.py",
CORE / "consumer_v2.py",
CORE / "verdict_v2.py",
)
CANONICAL_V2_MODULES = ("admission", "consumer", "verdict")
OLD_TOP_LEVEL = (
"AdmissionManifest",
"Budget",
"Coverage",
"FactPack",
"PushRequest",
"PushVerdict",
"TraceRecord",
)
def _module_exports(path: Path) -> tuple[str, ...]:
content = path.read_bytes()
assert content, f"public-surface instrument must read nonzero bytes from {path}"
tree = ast.parse(content, filename=path.relative_to(REPO).as_posix())
declarations = [
node
for node in tree.body
if isinstance(node, ast.Assign) and any(isinstance(target, ast.Name) and target.id == "__all__" for target in node.targets)
]
assert len(declarations) == 1
value = declarations[0].value
assert isinstance(value, (ast.List, ast.Tuple))
assert all(isinstance(item, ast.Constant) and isinstance(item.value, str) for item in value.elts)
return tuple(item.value for item in value.elts)
def _fresh_import_probe(*module_names: str) -> dict[str, object]:
program = """
import importlib
import json
import sys
core = importlib.import_module("openultrasast" + ".core")
result = {
"all": tuple(core.__all__),
"old_top_level": tuple(name for name in sys.argv[1].split(",") if hasattr(core, name)),
"modules": {},
}
for name in sys.argv[2:]:
try:
module = importlib.import_module(name)
except ModuleNotFoundError:
result["modules"][name] = None
else:
result["modules"][name] = tuple(module.__all__)
print(json.dumps(result, sort_keys=True))
"""
completed = subprocess.run(
[sys.executable, "-c", program, ",".join(OLD_TOP_LEVEL), *module_names],
cwd=REPO,
check=True,
capture_output=True,
text=True,
env={"PYTHONPATH": str(REPO / "src")},
)
assert completed.stdout, "fresh import probe must produce nonzero output"
value = json.loads(completed.stdout)
assert isinstance(value, dict)
return value
def test_cutover_deletes_every_v1_write_and_temporary_shim_path() -> None:
for path in REMOVED_PATHS:
assert not path.exists(), f"cutover residue remains: {path.relative_to(REPO)}"
for name in CANONICAL_V2_MODULES:
path = CORE / f"{name}.py"
assert path.is_file()
assert path.stat().st_size > 0
def test_fresh_interpreter_rejects_old_imports_and_loads_canonical_v2() -> None:
old_modules = (
"openultrasast.core.legacy_v1",
"openultrasast.core.trace",
"openultrasast.core._legacy_factpack",
"openultrasast.core." + "consumer_v2",
"openultrasast.core." + "verdict_v2",
)
canonical = tuple(f"openultrasast.core.{name}" for name in CANONICAL_V2_MODULES)
result = _fresh_import_probe(*old_modules, *canonical)
assert result["old_top_level"] == []
assert set(CANONICAL_V2_MODULES) <= set(result["all"])
modules = result["modules"]
assert isinstance(modules, dict)
assert all(modules[name] is None for name in old_modules)
assert "AdmissionManifestV2" in modules[canonical[0]]
assert "consume_records" in modules[canonical[1]]
assert "derive_verdict_outputs" in modules[canonical[2]]
def test_public_v2_surface_has_no_frozen_v1_names() -> None:
exports = _module_exports(CORE / "__init__.py")
assert set(CANONICAL_V2_MODULES) <= set(exports)
assert set(OLD_TOP_LEVEL).isdisjoint(exports)
def test_repository_post_deletion_boundary_is_nonzero_and_exact_zero() -> None:
paths = boundary_python()
inventory = load_migration_inventory(INVENTORY)
report = inspect_legacy_boundary(
paths,
frozen_inventory=inventory,
candidate_inventory=inventory,
expected_scope=paths,
root=REPO,
phase=BoundaryPhase.POST_DELETION,
)
assert report.files_read == len(paths) > 0
assert report.bytes_read > 0
assert report.open_inventory_entries == ()
assert report.legacy_import_sites == ()
assert report.legacy_writer_sites == ()
assert report.consumer_legacy_import_sites == ()
assert report.consumer_legacy_writer_sites == ()
assert report.compatibility_implementation_sites == ()
assert report.forbidden_dynamic_sites == ()
require_cutover_ready(
report,
frozen_inventory=inventory,
candidate_inventory=inventory,
root=REPO,
)
def test_historical_decoder_remains_exact_read_only_and_outside_public_v2() -> None:
inventory_bytes = INVENTORY.read_bytes()
assert inventory_bytes, "historical gate must read nonzero inventory bytes"
inventory = load_migration_inventory(INVENTORY)
artifacts = validate_historical_artifacts(inventory, root=REPO)
assert len(artifacts) == 2
assert all(artifact.content for artifact in artifacts)
assert all(hashlib.sha256(artifact.content).hexdigest() == artifact.content_digest for artifact in artifacts)
legacy_exports = _module_exports(CORE / "legacy.py")
assert {"write", "serialize", "to_v2", "compare_identity"}.isdisjoint(legacy_exports)
assert "legacy" not in _module_exports(CORE / "__init__.py")