Warn on unmatched CLI paths; send Kafka failure/SMTP TLS reports per-report (#890)

Fixes the two remaining bugs and the nits uncovered during the review
session:

- The CLI logs a warning for each file_path argument that matches no
  files, instead of silently succeeding with empty results — a typo'd
  path in a cron job previously 'worked' forever while processing
  nothing (_expand_file_path_args dropped it as a zero-match glob).
  Deliberately a warning, not an error: a glob legitimately matching
  nothing must not break existing workflows, and mailbox-only runs
  stay silent.

- save_failure_reports_to_kafka and save_smtp_tls_reports_to_kafka now
  send one message per report, mirroring the aggregate saver's
  per-slice sends. Every released version documented per-record sends,
  but the code sent the whole list as one message, which a large batch
  — failure reports carry message samples — could push past Kafka's
  default 1MB message limit. Consumer-visible: these topics now carry
  individual report objects, not one JSON array per batch.

- The CLI module docstring and argparse description now mention SMTP
  TLS reports; usage.md's CLI-help mirror regenerated.

- The elastic/opensearch to_header display-name tests now assert the
  joined 'RT <rcpt@example.com>' string reaches the saved document
  (autospec save), plus the exactly-once call, instead of only that
  save ran.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sean Whalen
2026-08-28 18:23:07 -04:00
committed by GitHub
co-authored by Claude Fable 5
parent 2d76de9ca6
commit 07b00a931b
8 changed files with 180 additions and 43 deletions
+9 -2
View File
@@ -1200,16 +1200,23 @@ class TestSaveFailureReport(unittest.TestCase):
def test_to_header_with_non_empty_display_joins_with_brackets(self):
"""The other branch: non-empty display joins display+addr
with " <" and appends ">", e.g. 'RT <rcpt@example.com>'."""
with " <" and appends ">", e.g. 'RT <rcpt@example.com>'.
Asserts the joined string actually reaches the saved document
(see test_reply_to_header_flattened_and_indexed for the
autospec-save pattern), not merely that save ran."""
report = _failure_report()
report["parsed_sample"]["headers"]["To"] = [["RT", "rcpt@example.com"]]
with (
patch("parsedmarc.elastic.Search", return_value=_empty_search()),
patch("parsedmarc.elastic.Index"),
patch.object(elastic_module._FailureReportDoc, "save") as mock_save,
patch.object(
elastic_module._FailureReportDoc, "save", autospec=True
) as mock_save,
):
save_failure_report_to_elasticsearch(report)
mock_save.assert_called_once()
doc = mock_save.call_args.args[0]
self.assertEqual(doc.sample.headers["to"], "RT <rcpt@example.com>")
def test_sample_address_lists_indexed_for_reply_to_cc_bcc_attachments(self):
"""A failure report sample can carry reply_to / cc / bcc /