from __future__ import annotations import json import unittest from pathlib import Path from typing import Sequence from mais_humana.cli import main from mais_humana.repository_mesh import ( CommandResult, MeshActionKind, MeshEnvironment, MeshEnvironmentKind, MeshErrorKind, MeshPresence, MeshRiskLevel, RepositoryTarget, automation_markdown, build_mesh_report, classify_command_error, command_is_destructive, default_repository_targets, mesh_actions_csv, mesh_inventory_csv, mesh_markdown, mesh_orders_payload, mesh_summary_payload, normalize_remote_url, repository_mesh_artifact_records, run_repository_mesh, validate_report, ) from tests.helpers import make_tmp def make_repo(root: Path, name: str) -> Path: repo = root / name (repo / ".git").mkdir(parents=True) return repo class FakeGit: def __init__(self) -> None: self.calls: list[tuple[str, ...]] = [] self.status_by_repo: dict[str, tuple[str, ...]] = {} self.remote_by_repo: dict[str, str] = {} self.head_by_repo: dict[str, str] = {} self.branch_by_repo: dict[str, str] = {} self.upstream_by_repo: dict[str, str] = {} self.ahead_behind_by_repo: dict[str, str] = {} self.fetch_error_by_repo: dict[str, str] = {} def set_repo( self, repo: Path, *, branch: str = "main", head: str = "abc1230000000000000000000000000000000000", remote: str = "https://git.ami.app.br/admin/repo.git", status: Sequence[str] = (), upstream: str = "origin/main", ahead_behind: str = "0 0", fetch_error: str = "", ) -> None: key = str(repo) self.branch_by_repo[key] = branch self.head_by_repo[key] = head self.remote_by_repo[key] = remote self.status_by_repo[key] = tuple(status) self.upstream_by_repo[key] = upstream self.ahead_behind_by_repo[key] = ahead_behind if fetch_error: self.fetch_error_by_repo[key] = fetch_error def __call__(self, argv: Sequence[str], cwd: Path | None = None, timeout: int = 60) -> CommandResult: del cwd, timeout args = tuple(str(item) for item in argv) self.calls.append(args) try: repo = args[args.index("-C") + 1] except ValueError: repo = "" command = args[args.index(repo) + 1 :] if repo else args if command[:3] == ("fetch", "--all", "--prune"): if repo in self.fetch_error_by_repo: stderr = self.fetch_error_by_repo[repo] return CommandResult(args, 1, "", stderr, error_kind=classify_command_error(stderr, 1)) return CommandResult(args, 0, "", "") if command[:2] == ("branch", "--show-current"): return CommandResult(args, 0, self.branch_by_repo.get(repo, "main") + "\n", "") if command[:2] == ("rev-parse", "HEAD"): return CommandResult(args, 0, self.head_by_repo.get(repo, "abc123") + "\n", "") if command[:3] == ("remote", "get-url", "origin"): return CommandResult(args, 0, self.remote_by_repo.get(repo, "https://git.ami.app.br/admin/repo.git") + "\n", "") if command[:2] == ("status", "--short"): return CommandResult(args, 0, "\n".join(self.status_by_repo.get(repo, ())) + "\n", "") if command[:3] == ("log", "-1", "--oneline"): return CommandResult(args, 0, self.head_by_repo.get(repo, "abc123")[:7] + " test\n", "") if command[:4] == ("rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"): upstream = self.upstream_by_repo.get(repo, "origin/main") if upstream: return CommandResult(args, 0, upstream + "\n", "") return CommandResult(args, 1, "", "fatal: no upstream configured", error_kind=MeshErrorKind.UNKNOWN) if command[:3] == ("rev-list", "--left-right", "--count"): return CommandResult(args, 0, self.ahead_behind_by_repo.get(repo, "0 0") + "\n", "") return CommandResult(args, 1, "", "unexpected command", error_kind=MeshErrorKind.UNKNOWN) class RepositoryMeshTests(unittest.TestCase): def test_default_targets_include_nominal_reconciliation_cases(self) -> None: targets = default_repository_targets() names = {item.declared_name: item for item in targets} self.assertIn("tudo-para-ia-mais-humana-platform", names) self.assertEqual(names["tudo-para-ia-mais-humana-platform"].expected_local_name, "tudo-para-ia-mais-humana-platform") self.assertIn("tudo-para-ia-mais-humana", names["tudo-para-ia-mais-humana-platform"].aliases) self.assertIn("tudo-para-ia-mais-humana-plataform", names["tudo-para-ia-mais-humana-platform"].aliases) self.assertTrue(names["tudo-para-ia-mais-humana-platform"].requires_nominal_reconciliation) self.assertIn("tudo-para-ia-integracoes-platform", names) self.assertEqual(names["tudo-para-ia-integracoes-platform"].canonical_name, "tudo-para-ia-integracoes-plataform") def test_remote_normalization_ignores_git_suffix_and_slash(self) -> None: self.assertEqual( normalize_remote_url("https://git.ami.app.br/admin/repo.git/"), normalize_remote_url("https://git.ami.app.br/admin/repo"), ) def test_error_classifier_handles_dubious_credentials_auth_network_and_repo(self) -> None: self.assertEqual(classify_command_error("fatal: detected dubious ownership", 1), MeshErrorKind.DUBIOUS_OWNERSHIP) self.assertEqual(classify_command_error("SEC_E_NO_CREDENTIALS credenciais nao disponiveis", 1), MeshErrorKind.CREDENTIALS_MISSING) self.assertEqual(classify_command_error("Authentication failed for https://x", 1), MeshErrorKind.AUTHENTICATION) self.assertEqual(classify_command_error("Could not resolve host: git.ami.app.br", 1), MeshErrorKind.NETWORK) self.assertEqual(classify_command_error("fatal: not a git repository", 1), MeshErrorKind.NOT_A_REPOSITORY) self.assertEqual(classify_command_error("", 0), MeshErrorKind.NONE) def test_command_destructive_guard_allows_fetch_and_ff_only_but_blocks_reset_pull_clean(self) -> None: self.assertFalse(command_is_destructive("git fetch --all --prune")) self.assertFalse(command_is_destructive("git merge --ff-only @{u}")) self.assertTrue(command_is_destructive("git reset --hard HEAD")) self.assertTrue(command_is_destructive("git clean -fdx")) self.assertTrue(command_is_destructive("git pull origin main")) self.assertTrue(command_is_destructive("git checkout main")) self.assertTrue(command_is_destructive("git restore .")) def test_clean_repository_gets_safe_fetch_action(self) -> None: root = make_tmp() repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo( repo, remote="https://git.ami.app.br/admin/alpha.git", head="1111111111111111111111111111111111111111", ) target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=fake, fetch=True) self.assertEqual(report.ok_count, 1) self.assertEqual(report.blocked_count, 0) self.assertEqual(report.summaries[0].risk, MeshRiskLevel.OK) self.assertTrue(any(action.kind == MeshActionKind.FETCH for action in report.summaries[0].actions)) self.assertTrue(any("--prune" in " ".join(call) for call in fake.calls)) self.assertFalse(validate_report(report)) def test_dirty_repository_blocks_destructive_sync(self) -> None: root = make_tmp() repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo( repo, remote="https://git.ami.app.br/admin/alpha.git", status=(" M README.md", "?? src/new.py"), ) target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=fake, fetch=False) summary = report.summaries[0] self.assertEqual(summary.risk, MeshRiskLevel.BLOCKED) self.assertEqual(summary.dirty_count, 1) self.assertTrue(any(action.kind == MeshActionKind.BLOCK_DESTRUCTIVE_SYNC for action in summary.actions)) self.assertIn("working tree sujo", mesh_markdown(report)) def test_divergent_branch_blocks_automatic_reconciliation(self) -> None: root = make_tmp() repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo( repo, remote="https://git.ami.app.br/admin/alpha.git", ahead_behind="2 3", ) target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=fake, fetch=False) self.assertEqual(report.summaries[0].risk, MeshRiskLevel.BLOCKED) reasons = " ".join(action.reason for action in report.summaries[0].actions) self.assertIn("ahead/behind", reasons) self.assertIn("bloqueios contra sync destrutiva", mesh_markdown(report)) def test_remote_mismatch_creates_fix_remote_action_without_auto_execution(self) -> None: root = make_tmp() repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo(repo, remote="https://git.ami.app.br/admin/wrong.git") target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=fake, fetch=False) actions = report.summaries[0].actions self.assertEqual(report.summaries[0].remote_mismatch_count, 1) fix_actions = [item for item in actions if item.kind == MeshActionKind.FIX_REMOTE_URL] self.assertEqual(len(fix_actions), 1) self.assertFalse(fix_actions[0].can_execute_automatically) self.assertIn("git remote set-url origin", " ".join(fix_actions[0].command_preview)) def test_missing_repository_creates_clone_plan_but_not_success(self) -> None: root = make_tmp() target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=FakeGit(), fetch=False) summary = report.summaries[0] self.assertEqual(summary.risk, MeshRiskLevel.ATTENTION) self.assertEqual(summary.missing_count, 1) self.assertTrue(any(action.kind == MeshActionKind.CLONE_MISSING for action in summary.actions)) self.assertIn("espelho ausente", mesh_markdown(report)) def test_unreachable_environment_is_blocked_as_external_access(self) -> None: root = make_tmp() target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("server", MeshEnvironmentKind.CODEX_SERVER, str(root / "missing-root"), "remote", local=False) report = build_mesh_report(root, targets=(target,), environments=(env,), runner=FakeGit(), fetch=False) summary = report.summaries[0] self.assertEqual(summary.risk, MeshRiskLevel.BLOCKED) self.assertEqual(summary.observations[0].presence, MeshPresence.UNREACHABLE_ENVIRONMENT) self.assertTrue(any(action.kind == MeshActionKind.REQUIRE_ENVIRONMENT_ACCESS for action in summary.actions)) def test_present_non_git_directory_blocks_replace_or_clone(self) -> None: root = make_tmp() (root / "alpha").mkdir() target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=FakeGit(), fetch=False) summary = report.summaries[0] self.assertEqual(summary.risk, MeshRiskLevel.BLOCKED) self.assertEqual(summary.observations[0].presence, MeshPresence.PRESENT_NOT_GIT) self.assertTrue(any(action.destructive for action in summary.actions)) def test_alias_materialization_creates_nominal_rename_action(self) -> None: root = make_tmp() repo = make_repo(root, "alpha-old") fake = FakeGit() fake.set_repo(repo, remote="https://git.ami.app.br/admin/alpha.git") target = RepositoryTarget( "alpha-new", "admin/alpha", "alpha-new", "01_alpha", aliases=("alpha-old",), canonical_name="alpha-new", requires_nominal_reconciliation=True, ) env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=fake, fetch=False) summary = report.summaries[0] self.assertEqual(summary.nominal_mismatch_count, 1) self.assertTrue(any(action.kind == MeshActionKind.RENAME_LOCAL_FOLDER for action in summary.actions)) self.assertIn("materializado como alias", mesh_markdown(report)) def test_fetch_credential_error_is_reported_as_blocker_not_plugin_blocker(self) -> None: root = make_tmp() repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo( repo, remote="https://git.ami.app.br/admin/alpha.git", fetch_error="fatal: unable to access url: SEC_E_NO_CREDENTIALS", ) target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report( root, targets=(target,), environments=(env,), runner=fake, fetch=True, plugin_auth_attempt="user rejected MCP tool call", ) self.assertEqual(report.credential_errors, 1) self.assertEqual(report.summaries[0].risk, MeshRiskLevel.BLOCKED) md = mesh_markdown(report) self.assertIn("user rejected MCP tool call", md) self.assertIn("credentials_missing", json.dumps(mesh_summary_payload(report), ensure_ascii=False)) def test_inventory_and_actions_csv_include_required_columns(self) -> None: root = make_tmp() repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo(repo, remote="https://git.ami.app.br/admin/alpha.git") target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=fake, fetch=False) inventory = mesh_inventory_csv(report) actions = mesh_actions_csv(report) self.assertIn("nome_declarado,nome_esperado,repositorio_gitea", inventory) self.assertIn("ahead_behind", inventory) self.assertIn("action_id,nome_declarado,ambiente,tipo", actions) def test_automation_markdown_documents_five_minute_safe_cycle(self) -> None: root = make_tmp() target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, targets=(target,), environments=(env,), runner=FakeGit(), fetch=False) text = automation_markdown(report) self.assertIn("5 minutos", text) self.assertIn("New-ScheduledTaskAction", text) self.assertIn("*/5 * * * *", text) self.assertIn("nunca executar reset", text.lower()) def test_orders_payload_maps_central_active_orders(self) -> None: root = make_tmp() central_root = root / "central" / "projects" order_dir = central_root / "01_alpha" / "orders" / "executivas" order_dir.mkdir(parents=True) (order_dir / "0001_EXECUTIVA__teste.md").write_text("# teste\n", encoding="utf-8") repo = make_repo(root, "alpha") fake = FakeGit() fake.set_repo(repo, remote="https://git.ami.app.br/admin/alpha.git") target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(root), "test") report = build_mesh_report(root, central_root=central_root, targets=(target,), environments=(env,), runner=fake) payload = mesh_orders_payload(report) self.assertEqual(payload["repositories"][0]["centralFolder"], "01_alpha") self.assertEqual(len(payload["repositories"][0]["activeOrders"]), 1) def test_run_repository_mesh_writes_all_artifacts(self) -> None: tmp = make_tmp() ecosystem = tmp / "eco" project = tmp / "human" central = tmp / "central" / "projects" / "15_repo_tudo-para-ia-mais-humana-platform" ecosystem.mkdir() project.mkdir() central.mkdir(parents=True) repo = make_repo(ecosystem, "alpha") fake = FakeGit() fake.set_repo(repo, remote="https://git.ami.app.br/admin/alpha.git") target = RepositoryTarget("alpha", "admin/alpha", "alpha", "01_alpha") env = MeshEnvironment("primary", MeshEnvironmentKind.WINDOWS_PRIMARY, str(ecosystem), "test") report = build_mesh_report(ecosystem, targets=(target,), environments=(env,), runner=fake) self.assertFalse(validate_report(report)) records = repository_mesh_artifact_records(project, central) self.assertTrue(any("repository-mesh-inventory.json" in item["path"] for item in records)) report, written = run_repository_mesh( ecosystem, project, central_platform_folder=central, fetch=False, plugin_auth_attempt="user rejected MCP tool call", runner=fake, ) self.assertTrue((project / "dados" / "repository-mesh-inventory.json").exists()) self.assertTrue((project / "matrizes" / "repository-mesh-actions.csv").exists()) self.assertTrue((project / "ecossistema" / "REPOSITORY-MESH-SYNC.md").exists()) self.assertTrue((central / "reports" / "EXECUTADO__repository-mesh-sync.md").exists()) self.assertGreaterEqual(len(written), 8) def test_run_repository_mesh_records_central_write_failure_without_aborting_project_outputs(self) -> None: tmp = make_tmp() ecosystem = tmp / "eco" project = tmp / "human" central = tmp / "central" / "projects" / "15_repo_tudo-para-ia-mais-humana-platform" ecosystem.mkdir() project.mkdir() central.mkdir(parents=True) (central / "reports").write_text("not a directory\n", encoding="utf-8") repo = make_repo(ecosystem, "alpha") fake = FakeGit() fake.set_repo(repo, remote="https://git.ami.app.br/admin/alpha.git") report, written = run_repository_mesh( ecosystem, project, central_platform_folder=central, fetch=False, plugin_auth_attempt="user rejected MCP tool call", runner=fake, ) self.assertGreater(len(report.targets), 0) self.assertTrue((project / "dados" / "repository-mesh-inventory.json").exists()) self.assertTrue((project / "ecossistema" / "REPOSITORY-MESH-CENTRAL-WRITE-STATUS.md").exists()) status = json.loads((project / "dados" / "repository-mesh-central-write-status.json").read_text(encoding="utf-8")) self.assertFalse(status["ok"]) self.assertEqual(status["failureCount"], 1) self.assertFalse(any("EXECUTADO__repository-mesh-sync.md" in item.path for item in written)) def test_cli_repo_mesh_writes_payload(self) -> None: tmp = make_tmp() ecosystem = tmp / "eco" project = tmp / "human" central = tmp / "central" / "projects" / "15_repo_tudo-para-ia-mais-humana-platform" ecosystem.mkdir() project.mkdir() central.mkdir(parents=True) code = main( [ "repo-mesh", "--ecosystem-root", str(ecosystem), "--project-root", str(project), "--central-platform-folder", str(central), "--plugin-auth-attempt", "user rejected MCP tool call", ] ) self.assertEqual(code, 0) summary = json.loads((project / "dados" / "repository-mesh-summary.json").read_text(encoding="utf-8")) self.assertEqual(summary["pluginAuthAttempt"], "user rejected MCP tool call") self.assertEqual(summary["targets"], len(default_repository_targets())) def test_cli_repo_mesh_falls_back_when_central_write_probe_fails(self) -> None: tmp = make_tmp() ecosystem = tmp / "eco" project = tmp / "human" central = tmp / "central" / "projects" / "15_repo_tudo-para-ia-mais-humana-platform" ecosystem.mkdir() project.mkdir() central.mkdir(parents=True) (central / "reports").write_text("not a directory\n", encoding="utf-8") code = main( [ "repo-mesh", "--ecosystem-root", str(ecosystem), "--project-root", str(project), "--central-platform-folder", str(central), "--plugin-auth-attempt", "mcp_tool_call_rejected_before_router", ] ) self.assertEqual(code, 0) status = json.loads((project / "dados" / "repository-mesh-central-write-status.json").read_text(encoding="utf-8")) self.assertIn("error", status) self.assertTrue(status["error"]) self.assertEqual(status["used"], "") payload = json.loads((project / "dados" / "repository-mesh-readiness.json").read_text(encoding="utf-8")) self.assertIn("status", payload) if __name__ == "__main__": unittest.main()