diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index 81f87ec1e..7ccae89e0 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -216,6 +216,7 @@ "sneaky", "soft", "sophisticated", + "spicy", "spiteful", "squishy", "steamy", @@ -456,6 +457,7 @@ "hermione", "homer", "howard", + "hunter", "irene", "isaac", "isabella", diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 19ea7106a..85b9a0073 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -116,6 +116,7 @@ def __init__( **kwargs (list[str], optional): Additional keyword arguments (passed through to `Preset`). """ self._root_event = None + self._finish_event = None self.start_time = None self.end_time = None self.duration = None @@ -377,8 +378,8 @@ async def async_start(self): new_activity = await self.finish() if not new_activity: self._success = True - await self._mark_finished() - yield self.root_event + scan_finish_event = await self._mark_finished() + yield scan_finish_event break await asyncio.sleep(0.1) @@ -434,8 +435,7 @@ async def _mark_finished(self): status_message = f"Scan {self.name} completed in {self.duration_human} with status {status}" - scan_finish_event = self.make_root_event(status_message) - scan_finish_event.data["status"] = status + scan_finish_event = self.finish_event(status_message, status) # queue final scan event with output modules output_modules = [m for m in self.modules.values() if m._type == "output" and m.name != "python"] @@ -451,6 +451,7 @@ async def _mark_finished(self): self.status = status log_fn(status_message) + return scan_finish_event def _start_modules(self): self.verbose(f"Starting module worker loops") @@ -990,6 +991,14 @@ def root_event(self): self._root_event.data["status"] = self.status return self._root_event + def finish_event(self, context=None, status=None): + if self._finish_event is None: + if context is None or status is None: + raise ValueError("Must specify context and status") + self._finish_event = self.make_root_event(context) + self._finish_event.data["status"] = status + return self._finish_event + def make_root_event(self, context): root_event = self.make_event(data=self.json, event_type="SCAN", dummy=True, context=context) root_event._id = self.id diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index bbff8a60b..3f80807af 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -118,3 +118,28 @@ async def test_speed_counter(): await asyncio.sleep(0.2) # only 5 should show assert 4 <= counter.speed <= 5 + + +@pytest.mark.asyncio +async def test_python_output_matches_json(bbot_scanner): + import json + + scan = bbot_scanner( + "blacklanternsecurity.com", + config={"speculate": True, "dns": {"minimal": False}, "scope": {"report_distance": 10}}, + ) + await scan.helpers.dns._mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.1"]}}) + events = [e.json() async for e in scan.async_start()] + output_json = scan.home / "output.json" + json_events = [] + for line in open(output_json): + json_events.append(json.loads(line)) + + assert len(events) == 5 + scan_events = [e for e in events if e["type"] == "SCAN"] + assert len(scan_events) == 2 + assert all([isinstance(e["data"]["status"], str) for e in scan_events]) + assert len([e for e in events if e["type"] == "DNS_NAME"]) == 1 + assert len([e for e in events if e["type"] == "ORG_STUB"]) == 1 + assert len([e for e in events if e["type"] == "IP_ADDRESS"]) == 1 + assert events == json_events