rein-aharness/tests/test_mailscan.py
tegwick f6930ad115 Rename package, CLI, and deploy artifacts to rein-aharness (HARNESS-WP-0002-T02)
agent_harness -> rein_aharness (package + all imports), CLI command
agent-harness -> rein-aharness, Docker image tag, k8s namespace/labels/
names, Makefile targets, deploy script env var/paths. In-repo identity
strings (hub event source, metrics harness field, default assignee,
argparse prog name, commit author identity) updated to match.

Historical documents left untouched on purpose: docs/adr/ADR-001-agent-harness-architecture.md,
docs/architecture.md (dated v0.1 snapshot), workplans/HARNESS-WP-0001
(completed under the old name), and the SSH host alias
"forgejo-agent-harness" (external ~/.ssh/config entry, not owned here).

Verified: 47/47 tests pass, CLI runs correctly from a fresh venv,
`make image` builds and the resulting container runs correctly.

deploy/README.md gained an explicit rename cutover checklist for what
this session cannot safely do unattended -- moving the host-side
secrets dir and checkout on railiance01, and not deleting the old k8s
namespace until the new one is confirmed working. The actual live
cutover (running that checklist against the real Railiance deployment)
is not attempted here -- real production surgery on binky-control's
live automation, needs the operator present.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 14:22:18 +02:00

117 lines
3.7 KiB
Python

from __future__ import annotations
import subprocess
from pathlib import Path
import pytest
from rein_aharness import mailscan
class FakeCompleted:
def __init__(self, returncode=0, stdout="", stderr=""):
self.returncode = returncode
self.stdout = stdout
self.stderr = stderr
def _repo_with_reports(tmp_path: Path, names: list[str]) -> Path:
repo = tmp_path / "binky-control"
(repo / "mailmeta" / "reports").mkdir(parents=True)
for name in names:
(repo / "mailmeta" / "reports" / name).write_text("header\nrow1\nrow2\n")
return repo
def test_mail_scan_approle_lane_and_new_report(tmp_path, monkeypatch) -> None:
repo = _repo_with_reports(tmp_path, ["old.csv"])
approle = tmp_path / "approle"
approle.mkdir()
(approle / "role_id").write_text("rid\n")
(approle / "secret_id").write_text("sid\n")
monkeypatch.setenv("EXECUTOR_APPROLE_DIR", str(approle))
calls: list[list[str]] = []
def fake_run(cmd, **kwargs):
calls.append(cmd)
if cmd[0] == "bao" and cmd[1] == "write":
assert "auth/approle/login" in cmd
return FakeCompleted(stdout="tok123\n")
if cmd[0] == "bao" and cmd[1] == "kv":
assert kwargs["env"]["BAO_TOKEN"] == "tok123"
return FakeCompleted(stdout="value\n")
if cmd[1] == "-m": # python3 -m email_connect.cli ...
env = kwargs["env"]
assert env["IMAP_USERNAME"] == "value"
assert env["IMAP_PASSWORD"] == "value"
(repo / "mailmeta" / "reports" / "new-report.csv").write_text(
"header\na\nb\nc\n"
)
return FakeCompleted()
raise AssertionError(f"unexpected command: {cmd}")
monkeypatch.setattr(subprocess, "run", fake_run)
events: list[dict] = []
monkeypatch.setattr(
mailscan.hub,
"post_progress_event",
lambda **kw: events.append(kw) or True,
)
result = mailscan.run_mail_scan(repo)
assert result.ok is True
assert result.auth_lane == "approle"
assert result.report_path == "new-report.csv"
assert result.new_messages == 3
assert events[0]["event_type"] == "binky_mail_intake"
# secret values must never appear in the hub event
assert "value" not in str(events[0]["detail"])
def test_mail_scan_failure_does_not_emit_intake_event(tmp_path, monkeypatch) -> None:
repo = _repo_with_reports(tmp_path, [])
monkeypatch.delenv("EXECUTOR_APPROLE_DIR", raising=False)
def fake_run(cmd, **kwargs):
if cmd[0] == "bao":
return FakeCompleted(stdout="value\n")
return FakeCompleted(returncode=3, stderr="imap connect refused")
monkeypatch.setattr(subprocess, "run", fake_run)
events: list[dict] = []
monkeypatch.setattr(
mailscan.hub,
"post_progress_event",
lambda **kw: events.append(kw) or True,
)
result = mailscan.run_mail_scan(repo)
assert result.ok is False
assert result.auth_lane == "ambient"
assert "exited 3" in result.reason
assert events[0]["event_type"] == "executor_run"
def test_mail_scan_reports_failure_when_bao_unavailable(tmp_path, monkeypatch) -> None:
repo = _repo_with_reports(tmp_path, [])
monkeypatch.delenv("EXECUTOR_APPROLE_DIR", raising=False)
def fake_run(cmd, **kwargs):
return FakeCompleted(returncode=2, stderr="permission denied")
monkeypatch.setattr(subprocess, "run", fake_run)
events: list[dict] = []
monkeypatch.setattr(
mailscan.hub,
"post_progress_event",
lambda **kw: events.append(kw) or True,
)
result = mailscan.run_mail_scan(repo)
assert result.ok is False
assert "bao kv failed" in result.reason
assert events[0]["event_type"] == "executor_run"