"""Every recognized evidence class, exercised through a real MTA. The harness accepts everything, so it cannot generate a bounce, complaint, or deferral on its own. Those classes are exercised by injecting the crafted fixtures and letting them travel through GreenMail, which adds the real `Received:` headers that a fixture read off disk never has — the difference that hid the reply-heuristic overclaim until EMAIL-WP-0005-T04. Classes that no local server can produce are listed in `tests/harness/README.md` under the provider-simulator tier. """ from __future__ import annotations from pathlib import Path import pytest import harness from email_connect.config import AppConfig, MailboxConfig, ReportsConfig, ScanConfig, SourceConfig, StorageConfig from email_connect.scanner import scan_mailbox FIXTURES = Path(__file__).parent / "fixtures" / "mailbox" requires_harness = pytest.mark.skipif( not harness.available(), reason="mail harness not running: docker compose -f tests/harness/docker-compose.yml up -d", ) #: The evidence each crafted fixture must still yield after passing through an #: MTA. Anything absent here is unreachable locally, not merely untested. EXPECTED_EVENTS = { "hard_bounce.eml": "notification.endpoint.rejected_permanent", "soft_bounce.eml": "notification.endpoint.rejected_temporary", "delayed_delivery.eml": "notification.endpoint.deferred", "complaint.eml": "notification.channel.complaint_received", "unsubscribe.eml": "notification.channel.unsubscribe_received", "out_of_office.eml": "interaction.out_of_office_received", "challenge_response.eml": "interaction.unverified_actor_interaction", "human_reply.eml": "interaction.reply_received", "final_failure.eml": "notification.endpoint.rejected_permanent", "unknown_return.eml": "notification.endpoint.unknown", } def scan_events(config) -> set[str]: result = scan_mailbox(config, full_rescan=True) rows = result.report_path.read_text(encoding="utf-8").splitlines() header = rows[0].split(",") index = header.index("normalized_event_type") return {line.split(",")[index] for line in rows[1:] if line.strip()} @pytest.mark.parametrize(("fixture", "expected"), sorted(EXPECTED_EVENTS.items())) @requires_harness def test_crafted_evidence_survives_a_real_mta(fixture, expected, tmp_path): harness.reset() recipient = harness.address(f"realism {Path(fixture).stem}") harness.deliver_raw(recipient, (FIXTURES / fixture).read_bytes()) config = harness.mailbox_config( recipient, storage_path=str(tmp_path / "state.sqlite"), reports_dir=str(tmp_path / "reports"), ) assert expected in scan_events(config) @requires_harness def test_injected_fixtures_match_the_offline_fixture_scan(tmp_path): """Delivery through an MTA must not change which evidence is produced.""" harness.reset() recipient = harness.address("realism parity") for fixture in EXPECTED_EVENTS: harness.deliver_raw(recipient, (FIXTURES / fixture).read_bytes()) delivered = scan_events( harness.mailbox_config( recipient, storage_path=str(tmp_path / "delivered.sqlite"), reports_dir=str(tmp_path / "delivered-reports"), ) ) offline_dir = tmp_path / "offline-fixtures" offline_dir.mkdir() for fixture in EXPECTED_EVENTS: (offline_dir / fixture).write_bytes((FIXTURES / fixture).read_bytes()) offline = scan_events( AppConfig( mailbox=MailboxConfig(id="offline", protocol="fixture"), scan=ScanConfig(), storage=StorageConfig(path=str(tmp_path / "offline.sqlite")), reports=ReportsConfig(output_dir=str(tmp_path / "offline-reports")), source=SourceConfig(fixture_dir=str(offline_dir)), ) ) assert delivered == offline def test_maildir_injection_is_byte_exact(tmp_path): """The offline injection path adds nothing to the message.""" raw = (FIXTURES / "hard_bounce.eml").read_bytes() path = harness.inject_maildir(tmp_path / "Maildir", raw) assert path.read_bytes() == raw assert path.parent.name == "new" def test_maildir_injection_feeds_the_scanner(tmp_path): maildir = tmp_path / "Maildir" harness.inject_maildir(maildir, (FIXTURES / "hard_bounce.eml").read_bytes(), name="1749000001.M1P1.harness") harness.inject_maildir(maildir, (FIXTURES / "complaint.eml").read_bytes(), name="1749000002.M2P2.harness") config = AppConfig( mailbox=MailboxConfig(id="injected", protocol="maildir"), scan=ScanConfig(), storage=StorageConfig(path=str(tmp_path / "state.sqlite")), reports=ReportsConfig(output_dir=str(tmp_path / "reports")), source=SourceConfig(maildir_dir=str(maildir)), ) events = scan_events(config) assert "notification.endpoint.rejected_permanent" in events assert "notification.channel.complaint_received" in events