aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test_report.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/tests/test_report.py b/tests/test_report.py
index d0e8239..c0fe0b0 100644
--- a/tests/test_report.py
+++ b/tests/test_report.py
@@ -2106,3 +2106,82 @@ class VendorDestinations(unittest.TestCase):
[row["id"] for row in second])
self.assertEqual([row["id"] for row in first],
["misp", "abusedb", "urlhaus"])
+
+
+class GenerateWritesVendorRows(unittest.TestCase):
+ """The seam: vendor rows land in the manifest beside the email rows.
+
+ generate() takes `configured` as an ARGUMENT rather than reading the
+ config, the way it already takes the identity and parse.py takes the
+ trust boundary. That is what keeps this module testable with no files
+ on disk beyond the case directory it writes into.
+ """
+
+ def _manifest(self):
+ return {
+ "format": 1,
+ "case_id": "2026-09-10-test",
+ "headers": [["From", "phish@example.invalid"],
+ ["Subject", "test"],
+ ["Date", "Wed, 09 Sep 2026 09:12:44 +0000"]],
+ "iocs": [
+ {"id": "ioc-1", "type": "ipv4", "value": "198.51.100.7"},
+ {"id": "ioc-2", "type": "url",
+ "value": "http://example.invalid/a"},
+ ],
+ "contacts": [{"ioc": "ioc-1", "iocs": ["ioc-1"],
+ "abuse": ["abuse@example.invalid"]}],
+ }
+
+ def test_configured_destinations_appear_alongside_the_email_rows(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ out = report.generate(self._manifest(), Path(tmp),
+ {"email": "r@example.org"},
+ configured={"misp", "abusedb"})
+ kinds = [row["kind"] for row in out["destinations"]]
+ self.assertIn("email", kinds)
+ self.assertIn("misp", kinds)
+ self.assertIn("api", kinds)
+
+ def test_nothing_configured_leaves_the_email_rows_untouched(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ out = report.generate(self._manifest(), Path(tmp),
+ {"email": "r@example.org"},
+ configured=set())
+ self.assertEqual([row["kind"] for row in out["destinations"]],
+ ["email"])
+
+ def test_a_second_run_produces_the_same_rows(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ first = report.generate(self._manifest(), Path(tmp),
+ {"email": "r@example.org"},
+ configured={"misp"})
+ ids = [row["id"] for row in first["destinations"]]
+ second = report.generate(first, Path(tmp),
+ {"email": "r@example.org"},
+ configured={"misp"})
+ self.assertEqual([row["id"] for row in second["destinations"]], ids)
+
+ def test_vendor_rows_get_no_body_written_to_disk(self):
+ with tempfile.TemporaryDirectory() as tmp:
+ out = report.generate(self._manifest(), Path(tmp),
+ {"email": "r@example.org"},
+ configured={"misp", "abusedb"})
+ written = sorted(p.name
+ for p in (Path(tmp) / "bodies").iterdir())
+ self.assertTrue(all(name.endswith(".xarf") for name in written))
+ self.assertEqual(len(written), 1)
+ for row in out["destinations"]:
+ if row["kind"] != "email":
+ self.assertIsNone(row["body"])
+ self.assertNotIn("body_sha256", row)
+
+ def test_configured_defaults_to_nothing(self):
+ # An older caller that does not pass it must not crash, and must not
+ # silently gain destinations it never configured.
+ with tempfile.TemporaryDirectory() as tmp:
+ out = report.generate(self._manifest(), Path(tmp),
+ {"email": "r@example.org"})
+ self.assertEqual([row["kind"] for row in out["destinations"]],
+ ["email"])
+