diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-10 11:14:21 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-10 11:14:21 +0200 |
| commit | f2fea43813ccebb1cf60e8afa5d4c7cdc52d0a20 (patch) | |
| tree | 7988c9c9222bfbc28c469b68b079451df98297dc /tests/test_offline.py | |
| parent | 45a68fbbe8da80a7bdf399b2e042f1982ca6a69d (diff) | |
| download | abusectl-f2fea43813ccebb1cf60e8afa5d4c7cdc52d0a20.tar.gz abusectl-f2fea43813ccebb1cf60e8afa5d4c7cdc52d0a20.zip | |
test: cover report.py in the no-socket proof
The offline test enumerates modules by import and report was absent, so
the module that writes documents naming hosts and addresses from a message
was outside the second property's only actual verification.
Exercised through generate() against a real case directory rather than
build() alone, so the disk path is covered too. Confirmed the test can
fail: a getaddrinfo planted in build() makes it fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
Diffstat (limited to 'tests/test_offline.py')
| -rw-r--r-- | tests/test_offline.py | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/tests/test_offline.py b/tests/test_offline.py index 547bd96..7866950 100644 --- a/tests/test_offline.py +++ b/tests/test_offline.py @@ -20,11 +20,13 @@ this asserts that the default is never reached by accident during a test run: parse stays pure, and nothing above it opens a socket unasked. """ +import pathlib import socket +import tempfile import unittest from unittest import mock -from abusectl import contacts, parse, rdap +from abusectl import case, contacts, parse, rdap, report class NothingOpensASocket(unittest.TestCase): @@ -82,6 +84,32 @@ class NothingOpensASocket(unittest.TestCase): self.assertEqual(len(result), 1) self.assertEqual(result[0]["handle"], "NET-1") + def test_generating_report_bodies_opens_no_socket(self): + # report writes documents naming hosts and addresses from the + # message. Nothing in that resolves any of them: the destinations + # come from the manifest contacts already produced, and a body is + # assembled from text. Written to a real case directory so the + # disk path is covered too, not just build(). + raw = (b"Received: from relay.example.invalid ([192.0.2.10])\r\n" + b"From: sender@example.invalid\r\n" + b"To: victim@example.org\r\n" + b"Subject: test\r\n\r\nhttp://phish.example.invalid/a\r\n") + with tempfile.TemporaryDirectory() as tmp: + path = case.create(pathlib.Path(tmp), raw).path + manifest = case.load(path) + manifest["iocs"] = parse.iocs(raw, trusted=["192.0.2.0/24"]) + manifest["contacts"] = [{ + "iocs": [manifest["iocs"][0]["id"]], + "query": "phish.example.invalid", + "abuse": ["abuse@example.invalid"], + "source": "rdap", + }] + result = report.generate( + manifest, path, + {"name": "A Reporter", "email": "r@example.org"}, + ) + self.assertEqual(len(result["destinations"]), 1) + def test_the_real_transport_is_never_the_default_in_a_test(self): """Sanity: http_fetch exists and is the documented default.""" self.assertIs(contacts.resolve.__defaults__[-1], rdap.http_fetch) |
