90 lines
3.6 KiB
Python
90 lines
3.6 KiB
Python
"""Keep the Kustomize-local HUX hook package identical to its canonical source."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ast
|
|
import importlib.util
|
|
import inspect
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
CANONICAL = ROOT / "dockerfiles" / "hermes-worker-hux" / "hux_hook"
|
|
VENDORED = ROOT / "services" / "hermes" / "plugins" / "hux-runtime" / "hux_hook"
|
|
FILES = ("__init__.py", "client.py", "hooks.py")
|
|
|
|
|
|
def _canonical_bytes(path: Path, vendored: bool) -> bytes:
|
|
"""Normalize only the package relocation imports before byte comparison."""
|
|
value = path.read_bytes()
|
|
if vendored:
|
|
value = value.replace(b"from .client import", b"from hux_hook.client import")
|
|
value = value.replace(b"from .hooks import", b"from hux_hook.hooks import")
|
|
return value
|
|
|
|
|
|
class _CanonicalImports(ast.NodeTransformer):
|
|
"""Normalize the same relative imports for structural comparison."""
|
|
|
|
def visit_ImportFrom(self, node: ast.ImportFrom): # noqa: N802
|
|
if node.level == 1 and node.module in {"client", "hooks"}:
|
|
node.level = 0
|
|
node.module = f"hux_hook.{node.module}"
|
|
return node
|
|
|
|
|
|
def _canonical_ast(value: bytes) -> str:
|
|
tree = _CanonicalImports().visit(ast.parse(value))
|
|
return ast.dump(ast.fix_missing_locations(tree), include_attributes=False)
|
|
|
|
|
|
def _load(name: str, root: Path):
|
|
"""Load one package under a unique name so both copies coexist."""
|
|
spec = importlib.util.spec_from_file_location(
|
|
name,
|
|
root / "__init__.py",
|
|
submodule_search_locations=[str(root)],
|
|
)
|
|
assert spec and spec.loader
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def test_vendored_hook_bytes_and_ast_match_canonical_source():
|
|
"""Any canonical change requires an intentional vendor refresh in the same diff."""
|
|
for name in FILES:
|
|
canonical = _canonical_bytes(CANONICAL / name, False)
|
|
vendored = _canonical_bytes(VENDORED / name, True)
|
|
assert vendored == canonical, f"refresh vendored hux_hook/{name}"
|
|
assert _canonical_ast((VENDORED / name).read_bytes()) == _canonical_ast(
|
|
(CANONICAL / name).read_bytes()
|
|
)
|
|
|
|
|
|
def test_vendored_hook_exports_and_signatures_match_canonical_api():
|
|
"""Protect the runtime from a byte-equal but incorrectly loaded package surface."""
|
|
for name in tuple(sys.modules):
|
|
if name == "hux_hook" or name.startswith("hux_hook."):
|
|
sys.modules.pop(name)
|
|
canonical = _load("hux_hook", CANONICAL)
|
|
vendored = _load("vendored_hux_hook", VENDORED)
|
|
assert vendored.__all__ == canonical.__all__
|
|
for name in canonical.__all__:
|
|
canonical_value = getattr(canonical, name)
|
|
vendored_value = getattr(vendored, name)
|
|
assert type(vendored_value).__name__ == type(canonical_value).__name__
|
|
assert inspect.signature(vendored_value) == inspect.signature(canonical_value)
|
|
|
|
|
|
def test_runtime_uses_only_its_kustomize_local_hook_package():
|
|
"""A rendered plugin must not depend on the Docker build-context path."""
|
|
source = (VENDORED.parent / "runtime.py").read_text(encoding="utf-8")
|
|
tree = ast.parse(source)
|
|
imports = [node for node in ast.walk(tree) if isinstance(node, ast.ImportFrom)]
|
|
assert any(node.level == 1 and node.module == "hux_hook" for node in imports)
|
|
assert not any(node.level == 0 and node.module == "hux_hook" for node in imports)
|
|
for path in (*CANONICAL.glob("*.py"), *VENDORED.glob("*.py")):
|
|
assert len(path.read_text(encoding="utf-8").splitlines()) <= 500
|