From a6c24af622dd8eb9449e510a1317e8a39b46bb1d Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 10 Aug 2022 11:28:56 -0400 Subject: [PATCH] Common: Prevent topic collision between types and tags If an event tag happened to be the same as an event type, subscribers could receive event types that they were not prepared to handle, resulting in difficult-to-diagnose bugs. Prevent tags and types from being sent to the wrong subscribers by appending unique strings to the topics. --- .../event_queue/pypubsub_event_queue.py | 22 +++++++++++++++---- .../event_queue/test_pypubsub_event_queue.py | 8 +++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/monkey/common/event_queue/pypubsub_event_queue.py b/monkey/common/event_queue/pypubsub_event_queue.py index dc4a3991d..87813311f 100644 --- a/monkey/common/event_queue/pypubsub_event_queue.py +++ b/monkey/common/event_queue/pypubsub_event_queue.py @@ -22,10 +22,12 @@ class PyPubSubEventQueue(IEventQueue): self, event_type: Type[AbstractEvent], subscriber: Callable[[AbstractEvent], None] ): # pypubsub.pub.subscribe needs a string as the topic/event name - self._pypubsub_publisher.subscribe(listener=subscriber, topicName=event_type.__name__) + event_type_topic = PyPubSubEventQueue._get_type_topic(event_type) + self._pypubsub_publisher.subscribe(listener=subscriber, topicName=event_type_topic) def subscribe_tag(self, tag: str, subscriber: Callable[[AbstractEvent], None]): - self._pypubsub_publisher.subscribe(listener=subscriber, topicName=tag) + tag_topic = PyPubSubEventQueue._get_tag_topic(tag) + self._pypubsub_publisher.subscribe(listener=subscriber, topicName=tag_topic) def publish(self, event: AbstractEvent): self._publish_to_all_events_topic(event) @@ -36,8 +38,20 @@ class PyPubSubEventQueue(IEventQueue): self._pypubsub_publisher.sendMessage(_INTERNAL_ALL_EVENT_TYPES_TOPIC, event=event) def _publish_to_type_topic(self, event: AbstractEvent): - self._pypubsub_publisher.sendMessage(event.__class__.__name__, event=event) + event_type_topic = PyPubSubEventQueue._get_type_topic(event.__class__) + self._pypubsub_publisher.sendMessage(event_type_topic, event=event) def _publish_to_tags_topics(self, event: AbstractEvent): for tag in event.tags: - self._pypubsub_publisher.sendMessage(tag, event=event) + tag_topic = PyPubSubEventQueue._get_tag_topic(tag) + self._pypubsub_publisher.sendMessage(tag_topic, event=event) + + # Appending a unique string to the topics for type and tags prevents bugs caused by collisions + # between type names and tag names. + @staticmethod + def _get_type_topic(event_type: Type[AbstractEvent]) -> str: + return f"{event_type.__name__}-type" + + @staticmethod + def _get_tag_topic(tag: str) -> str: + return f"{tag}-tag" diff --git a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py index 1bd919133..449a7776a 100644 --- a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py +++ b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py @@ -99,3 +99,11 @@ def test_subscribe_tags_multiple_types(event_queue, subscriber): assert TestEvent1 in subscriber.call_types assert TestEvent2 in subscriber.call_types assert {EVENT_TAG_1, EVENT_TAG_2}.issubset(subscriber.call_tags) + + +def test_type_tag_collision(event_queue, subscriber): + event_queue.subscribe_type(TestEvent1, subscriber) + + event_queue.publish(TestEvent2(tags={TestEvent1.__name__})) + + assert subscriber.call_count == 0