From 8a4ee4cf5add45a633cf362e801efd856e972ae3 Mon Sep 17 00:00:00 2001 From: abiba-bot Date: Thu, 10 Sep 2026 10:18:38 +0000 Subject: [PATCH] no-mistakes(review): Pin Mumuni removal behaviorally and fix digest import bug --- scripts/daily-infra-report.py | 6 +- tests/test_mumuni_monitor_removal.py | 152 +++++++++++++++++++-------- 2 files changed, 113 insertions(+), 45 deletions(-) diff --git a/scripts/daily-infra-report.py b/scripts/daily-infra-report.py index 310e433..08f149e 100755 --- a/scripts/daily-infra-report.py +++ b/scripts/daily-infra-report.py @@ -679,6 +679,6 @@ if __name__ == "__main__": print(f" Zulip Ext: {'✅' if report.get('zulip_ext',{}).get('connected') else '❌'}") print(f" LiteLLM: {sum(1 for c in report.get('litellm',{}).get('checks',[]) if c['status']=='pass')}/{len(report.get('litellm',{}).get('checks',[]))} checks pass") agent_parts = [] -for k,v in report.get('agents',{}).items(): - agent_parts.append(f"{k}:{v.get('gateway_state',v.get('pm2_status','?'))}") -print(f" Agents: {', '.join(agent_parts)}") + for k,v in report.get('agents',{}).items(): + agent_parts.append(f"{k}:{v.get('gateway_state',v.get('pm2_status','?'))}") + print(f" Agents: {', '.join(agent_parts)}") diff --git a/tests/test_mumuni_monitor_removal.py b/tests/test_mumuni_monitor_removal.py index e9bf0b5..5f9b9eb 100644 --- a/tests/test_mumuni_monitor_removal.py +++ b/tests/test_mumuni_monitor_removal.py @@ -21,10 +21,13 @@ CONTRACT UNDER TEST: * `zulip-health.prose.md` retires the Mumuni-only steps and says explicitly that Mumuni is not monitored from this host. -HOW: structural greps plus a behavioral sandbox. The sandbox copies the shipped -script verbatim and rewrites only its LOG constant, then runs it with stub -ssh/curl on PATH. The ssh stub records every host it is asked to reach, so -"never probes .24" is asserted from observed behavior, not from source text. +HOW: behavioral execution plus one named deliverable-text contract. The sandbox +copies the shipped monitor verbatim and rewrites only its LOG constant, then +runs it with stub ssh/curl on PATH; the ssh stub records every host it is asked +to reach, so "never probes .24" and "no Mumuni notify" are asserted from +observed behavior. The daily digest is pinned by importing it and exercising +collect() and build_html() directly. The single source-text assertion is the +deliverable-text contract the captain acceptance names for the shipped monitor. Usage: python3 -m pytest tests/test_mumuni_monitor_removal.py """ @@ -50,26 +53,19 @@ TANKO_VANTAGE = "192.168.68.15" # amdpve — Tanko CT 112 via pct exec AGENT_ZERO_HOST = "192.168.68.14" # kagentz host, Agent Zero docker -# ── scripts/zulip-monitor.sh: structural guards ────────────────────── +# ── scripts/zulip-monitor.sh: deliverable-text contract ───────────── -def test_zulip_monitor_has_no_mumuni_reference(): +def test_zulip_monitor_deliverable_text_contract(): + """Owned deliverable-text contract for scripts/zulip-monitor.sh. + + Captain acceptance requires the shipped monitor to contain no Mumuni probe + identifier and no 192.168.68.24 literal. Behavioral proof that the monitor + never contacts that host and never emits a Mumuni notify lives in the + sandbox tests below; this only pins the named text contract. + """ text = ZULIP_MONITOR.read_text() assert "mumuni" not in text.lower() - assert "gateway_state.json" not in text - - -def test_zulip_monitor_has_no_24_reference(): - assert MUMUNI_IP not in ZULIP_MONITOR.read_text() - - -def test_zulip_monitor_keeps_bridge_tanko_and_agent_zero_legs(): - text = ZULIP_MONITOR.read_text() - assert "Platform A: pi (Abiba)" in text # the Zulip bridge - assert "Platform B: Tanko" in text - assert "Platform C: Agent Zero" in text - assert TANKO_VANTAGE in text - assert AGENT_ZERO_HOST in text - assert "kagentz" in text + assert MUMUNI_IP not in text # ── scripts/zulip-monitor.sh: behavioral sandbox ───────────────────── @@ -218,26 +214,104 @@ def test_failing_run_alerts_on_tanko_but_never_on_mumuni(tmp_path): assert "Result: 🔴 1 issue(s) found" in log -# ── scripts/daily-infra-report.py: no Mumuni agent probe ───────────── +# ── scripts/daily-infra-report.py: behavioral digest checks ────────── -def test_daily_report_has_no_mumuni_agent_probe(): - text = DAILY_REPORT.read_text() - assert 'report["agents"]["mumuni"]' not in text - assert f'ssh("{MUMUNI_IP}"' not in text - assert "hermes --version" not in text +@pytest.fixture(scope="module") +def daily(): + spec = importlib.util.spec_from_file_location("daily_infra_report", DAILY_REPORT) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module -def test_daily_report_keeps_abiba_and_tanko_agent_legs(): - text = DAILY_REPORT.read_text() - assert 'report["agents"]["abiba"]' in text - assert 'report["agents"]["tanko"]' in text +DAILY_AGENTS = { + "abiba": { + "platform": "pi", "ct": 100, "ip": MUMUNI_IP, + "zulip_connected": True, "zulip_processed": 5, + "pm2_status": "online", "pm2_restarts": "0", "pm2_uptime": "1h", + }, + "tanko": { + "platform": "dsh", "ct": 112, "ip": "192.168.68.122", + "gateway_state": "n/a (DSH)", "zulip_state": "connected", + "telegram_state": "unknown", "gateway_pid": None, "updated_at": "", + }, +} -def test_daily_report_still_describes_abiba_at_its_own_ct100_ip(): - # .24 is abiba's own CT 100 address — the IP itself is legitimate; only a - # Mumuni gateway probe against it was the fault. - assert '"platform": "pi", "ct": 100, "ip": "192.168.68.24"' in \ - DAILY_REPORT.read_text() +def _fabricated_report(agents): + return { + "nodes": {}, + "node_count": 1, + "nodes_online": 1, + "total_vms": 0, + "running_vms": 0, + "stopped_vms": [], + "vms_by_node": {n: [] for n in + ["amdpve", "minipve", "storepve", "acerpve", "ocupve"]}, + "storage": [], + "docker_vm": {"total": 0, "running": 0, "unhealthy": [], + "containers": [], "reclaimable": "", "disk_used": "1%"}, + "docker_syslog": {"total": 0, "running": 0, "containers": []}, + "docker_netbird": {"total": 0, "running": 0, "containers": []}, + "endpoints": [], + "litellm": {"checks": []}, + "nfs": [], + "zulip_ext": { + "connected": True, "queue_id": "queue", "last_error": None, + "messages_processed": 0, "retry_count": 0, "pm2": {}, + "pm2_healthy": True, "bot_skipped_15min": 0, "finalized_1h": 0, + "failed_finalize_1h": 0, "finalize_fail_pct": 0, + "server_status": "200", + }, + "agents": agents, + } + + +def _agent_status_card(html): + start = html.index("🤖 Agent Status") + end = html.index("💬 Zulip Extension") + return html[start:end] + + +def test_daily_report_renders_only_abiba_and_tanko_agents(daily): + """build_html() over a Mumuni-free agent set must render no Mumuni row and + no Mumuni gateway-unknown issue, while abiba and tanko rows still render.""" + html = daily.build_html(_fabricated_report(dict(DAILY_AGENTS))) + card = _agent_status_card(html) + assert "mumuni" not in card.lower() + assert "abiba" in card + assert "tanko" in card + assert "mumuni" not in html.lower() + + +def test_daily_report_collect_never_probes_mumuni(monkeypatch, daily): + """collect() with ssh stubbed must add no mumuni agent and must never ssh + its decommissioned .24 host.""" + probed = [] + + class _NoSubprocess: + @staticmethod + def check_output(*args, **kwargs): + return b"" + + def fake_ssh(host, cmd): + probed.append(host) + return "" + + monkeypatch.setattr(daily, "pve_get", lambda path: []) + monkeypatch.setattr(daily, "ssh_jerome", lambda host, cmd: "") + monkeypatch.setattr(daily, "ssh", fake_ssh) + monkeypatch.setattr(daily, "http_get", + lambda url, auth=None, timeout=10: "200") + monkeypatch.setattr(daily, "http_get_body", + lambda url, auth=None, timeout=10: "") + monkeypatch.setattr(daily, "count_in_log", lambda *a, **k: 0) + monkeypatch.setattr(daily, "subprocess", _NoSubprocess) + + report = daily.collect() + assert "mumuni" not in report["agents"] + assert MUMUNI_IP not in probed # ── scripts/agent-health-check.py: roster pin ─────────────────────── @@ -255,12 +329,6 @@ def test_agent_health_roster_has_no_mumuni_entry(ahc): assert "mumuni" not in ahc.AGENTS -def test_agent_health_roster_comment_no_longer_places_mumuni_at_24(): - text = AHC.read_text() - assert "mumuni (.24" not in text - assert "mumuni (.24, inside abiba CT100)" not in text - - # ── zulip-health.prose.md: contract reconciliation ────────────────── def test_health_contract_retires_mumuni_only_steps():