#!/usr/bin/env python3 from __future__ import annotations import os from pathlib import Path import shutil import subprocess import sys import tempfile import unittest CHECKER = Path(__file__).with_name("framework-drift-check.py") REAL_RESOLVER = CHECKER.parents[2] / "_lib" / "manifest.sh" class FrameworkDriftCheckTests(unittest.TestCase): def setUp(self) -> None: self.temp = tempfile.TemporaryDirectory() root = Path(self.temp.name) self.framework = root / "framework" self.source = self.framework / "tools" self.installed = root / "home" / "tools" for directory in (self.source / "git", self.source / "_lib", self.installed / "git", self.installed / "_lib"): directory.mkdir(parents=True, exist_ok=True) shutil.copy2(REAL_RESOLVER, self.source / "_lib" / "manifest.sh") (self.source / "git" / "guard.sh").write_text("fixed\n") (self.source / "git" / "new-wrapper.sh").write_text("new\n") (self.source / "_lib" / "credentials.json").write_text("source-placeholder\n") self.write_manifest() def tearDown(self) -> None: self.temp.cleanup() def write_manifest(self, operator_extra: str = "") -> None: (self.framework / "framework-manifest.txt").write_text( "[framework]\ntools/**\n[operator]\ntools/_lib/credentials.json\n" + operator_extra ) def run_check(self, *extra: str) -> subprocess.CompletedProcess[str]: return subprocess.run( [sys.executable, str(CHECKER), "--source-root", str(self.framework), "--installed-root", str(self.installed), *extra], text=True, capture_output=True, check=False, env={**os.environ, "PYTHONDONTWRITEBYTECODE": "1"}, ) def install_matching(self) -> None: for relative in ("git/guard.sh", "git/new-wrapper.sh", "_lib/manifest.sh"): shutil.copy2(self.source / relative, self.installed / relative) (self.installed / "_lib" / "credentials.json").write_text("different-operator-secret\n") def test_fails_loudly_and_classifies_stale_missing_and_installed_only(self) -> None: (self.installed / "git" / "guard.sh").write_text("broken\n") shutil.copy2(self.source / "_lib" / "manifest.sh", self.installed / "_lib" / "manifest.sh") (self.installed / "local-helper.sh").write_text("operator\n") result = self.run_check("--verbose") self.assertEqual(result.returncode, 1) self.assertIn("STALE git/guard.sh", result.stdout) self.assertIn("NOT_INSTALLED git/new-wrapper.sh", result.stdout) self.assertIn("INSTALLED_ONLY operator-or-unknown local-helper.sh", result.stdout) self.assertIn("FAIL deployed framework tools", result.stderr) def test_passes_only_when_every_manifest_owned_source_file_matches(self) -> None: self.install_matching() result = self.run_check() self.assertEqual(result.returncode, 0, result.stderr) self.assertIn("stale=0 not-installed=0 unsafe-alias=0", result.stdout) def test_exact_operator_directory_does_not_hide_framework_drift_beneath_it(self) -> None: self.install_matching() (self.installed / "git" / "guard.sh").write_text("drift-hidden-by-directory-entry\n") self.write_manifest("tools/git\n") result = self.run_check() self.assertEqual(result.returncode, 1, result.stdout + result.stderr) self.assertIn("STALE git/guard.sh", result.stdout) def test_manifest_is_required_and_policy_changes_take_effect(self) -> None: self.install_matching() (self.installed / "git" / "guard.sh").write_text("operator-divergence\n") self.write_manifest("tools/git/guard.sh\n") self.assertEqual(self.run_check().returncode, 0) (self.framework / "framework-manifest.txt").unlink() result = self.run_check() self.assertEqual(result.returncode, 2) self.assertIn("CANNOT_ASSERT ownership manifest is missing", result.stderr) def test_empty_and_unreadable_source_census_cannot_assert(self) -> None: empty_framework = Path(self.temp.name) / "empty-framework" empty_source = empty_framework / "tools" empty_source.mkdir(parents=True) shutil.copy2(self.framework / "framework-manifest.txt", empty_framework / "framework-manifest.txt") # The canonical resolver is supplied outside the empty census solely so # this probe reaches the explicit minimum-population guard. result = subprocess.run([sys.executable, str(CHECKER), "--source-root", str(empty_framework), "--installed-root", str(self.installed)], text=True, capture_output=True) self.assertEqual(result.returncode, 2) self.assertIn("CANNOT_ASSERT", result.stderr) blocked = self.source / "blocked" blocked.mkdir(); (blocked / "hidden.sh").write_text("hidden\n"); blocked.chmod(0) try: result = self.run_check() finally: blocked.chmod(0o700) self.assertEqual(result.returncode, 2) self.assertIn("CANNOT_ASSERT", result.stderr) self.assertTrue("Permission denied" in result.stderr or "no readable/searchable mode" in result.stderr) def test_root_and_descendant_aliases_cannot_report_clean(self) -> None: result = subprocess.run([sys.executable, str(CHECKER), "--source-root", str(self.framework), "--installed-root", str(self.source)], text=True, capture_output=True) self.assertEqual(result.returncode, 2) self.assertIn("same filesystem object", result.stderr) shutil.copy2(self.source / "_lib" / "manifest.sh", self.installed / "_lib" / "manifest.sh") shutil.rmtree(self.installed / "git") (self.installed / "git").symlink_to(self.source / "git", target_is_directory=True) result = self.run_check() self.assertNotEqual(result.returncode, 0) self.assertTrue("symlinked directory" in result.stderr or "UNSAFE_ALIAS" in result.stdout) if __name__ == "__main__": unittest.main()