diff options
Diffstat (limited to 'tests/test_report.py')
| -rw-r--r-- | tests/test_report.py | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/tests/test_report.py b/tests/test_report.py index 9a19d00..c8c39f8 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -961,19 +961,51 @@ class FeedbackPart(unittest.TestCase): self.lookup = dict(self.fields) def test_the_three_rfc5965_required_fields_are_present(self): - self.assertEqual(self.lookup["Feedback-Type"], "abuse") + self.assertEqual(self.lookup["Feedback-Type"], "fraud") self.assertEqual(self.lookup["Version"], "1") self.assertTrue(self.lookup["User-Agent"].startswith("abusectl/")) - def test_the_xarf_report_type_is_phishing(self): - self.assertEqual(self.lookup["Report-Type"], "phishing") + def test_the_feedback_type_is_the_registered_value_naming_phishing(self): + """Checked against the IANA MARF registry, not a worked example. + + RFC 5965 registers fraud as "indicates some kind of fraud or + phishing activity" and abuse as "unsolicited email or some other + kind of email abuse". This tool reports phishing. + """ + self.assertEqual(self.lookup["Feedback-Type"], "fraud") + + def test_no_unregistered_field_is_emitted(self): + """Every name here appears in the IANA MARF registry. + + Report-Type: phishing used to be emitted and is NOT registered. It + was harmless, since RFC 5965 section 6 makes ignoring an unknown + field a MUST, but that same section requires an extension field be + registered, and a desk should be able to look up every field in a + document this tool sends. + """ + registered = { + "Arrival-Date", "Auth-Failure", "Authentication-Results", + "Delivery-Result", "DKIM-ADSP-DNS", "DKIM-Canonicalized-Body", + "DKIM-Canonicalized-Header", "DKIM-Domain", "DKIM-Identity", + "DKIM-Selector", "DKIM-Selector-DNS", "Feedback-Type", + "Identity-Alignment", "Incidents", "Original-Mail-From", + "Original-Rcpt-To", "Received-Date", "Reported-Domain", + "Reported-URI", "Reporting-MTA", "Source-IP", "Source-Port", + "SPF-DNS", "User-Agent", "Version", + } + # Source is x-arf's, deliberately: RFC 5965 has no field for "this + # host is the thing being reported", which is why the envelope + # carries x-arf fields at all. It is the one exception and is named + # here so a NEW unregistered field cannot slip in unnoticed. + emitted = {name for name, _ in self.fields} + self.assertEqual(emitted - registered - {"Source"}, set()) def test_source_is_the_primary_indicator(self): self.assertEqual(self.lookup["Source"], "203.0.113.42") self.assertEqual(self.lookup["Source-IP"], "203.0.113.42") def test_every_url_appears_as_a_reported_uri(self): - uris = [value for name, value in self.fields if name == "Reported-Uri"] + uris = [value for name, value in self.fields if name == "Reported-URI"] self.assertEqual( uris, ["http://login.sender.invalid/verify?id=REDACTED"] ) @@ -1048,11 +1080,11 @@ class FeedbackPart(unittest.TestCase): seen: dict[str, int] = {} for name, _ in fields: seen[name] = seen.get(name, 0) + 1 - repeatable = {"Reported-Uri", "Reported-Domain"} + repeatable = {"Reported-URI", "Reported-Domain"} for name, count in seen.items(): if name not in repeatable: self.assertEqual(count, 1, f"{name} appeared {count} times") - self.assertEqual(seen["Reported-Uri"], 2) + self.assertEqual(seen["Reported-URI"], 2) self.assertEqual(seen["Reported-Domain"], 2) def test_an_ipv6_indicator_fills_source_ip_too(self): @@ -1086,7 +1118,7 @@ class FeedbackPart(unittest.TestCase): self.assertNotIn("Source", lookup) self.assertNotIn("Source-IP", lookup) # The envelope is still well formed: a desk gets a valid part. - self.assertEqual(lookup["Feedback-Type"], "abuse") + self.assertEqual(lookup["Feedback-Type"], "fraud") self.assertEqual(lookup["Version"], "1") def test_a_type_this_module_does_not_place_is_not_invented_into_one(self): @@ -1133,7 +1165,7 @@ class FeedbackPart(unittest.TestCase): "target": "abuse@host.invalid", "body": None, "status": "pending"} lookup = dict(report.feedback_fields(MANIFEST, destination)) - self.assertEqual(lookup["Feedback-Type"], "abuse") + self.assertEqual(lookup["Feedback-Type"], "fraud") def test_arrival_date_is_not_taken_from_the_senders_date_header(self): """RFC 5965: Arrival-Date is when the generating ADMD's MTA received @@ -1189,7 +1221,7 @@ class FeedbackInjection(unittest.TestCase): destination = report.email_destinations(manifest["contacts"])[0] fields = report.feedback_fields(manifest, destination) for name, out in fields: - if name == "Reported-Uri": + if name == "Reported-URI": return out return None @@ -1386,7 +1418,7 @@ class FeedbackInjection(unittest.TestCase): fields = report.feedback_fields(manifest, destination) self.assertEqual( {name for name, _ in fields}, - {"Feedback-Type", "User-Agent", "Version", "Report-Type"}) + {"Feedback-Type", "User-Agent", "Version"}) def test_a_non_string_value_does_not_crash_the_report(self): """A manifest is edited by hand and JSON has numbers. @@ -1800,7 +1832,7 @@ class Writing(unittest.TestCase): self.assertNotIn(b"\n", header.replace(b"\r\n", b"")) # And the bare LFs inside the feedback part survive untranslated, # which is the same defect seen from the other side. - self.assertIn(b"Feedback-Type: abuse\nUser-Agent:", raw) + self.assertIn(b"Feedback-Type: fraud\nUser-Agent:", raw) def test_an_untouched_case_regenerates_without_complaint(self): """The regression that the plan's read_text() caused. |
