Skip to content

Commit 8672cd8

Browse files
committed
be more permissive for the broker topic regex; be sure to allow all alphanumeric/hyphens/underscores
Signed-off-by: Lance-Drane <Lance-Drane@users.noreply.github.com>
1 parent 31bd839 commit 8672cd8

2 files changed

Lines changed: 19 additions & 6 deletions

File tree

src/intersect_sdk_common/control_plane/control_plane_manager.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@
1010
from .definitions import MessageCallback
1111
from .topic_handler import TopicHandler
1212

13-
_CHANNEL_REGEX = re.compile(r'^[a-zA-Z0-9*/-]+[a-zA-Z0-9*#/-]$')
13+
_CHANNEL_REGEX = re.compile(r'^[a-zA-Z0-9_*/-]+[a-zA-Z0-9_*#/-]$')
1414
"""Allow for these patterns:
1515
1616
- alphanumeric characters
1717
- hyphens
18+
- underscores
1819
- `/` (topic separator; note that this is '.' on the broker)
1920
- `*` (wildcard for exactly one word)
2021
- `#` (wildcard for any number of words, but can ONLY appear at the end of the topic string, see section 4.7.1.2 at https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718107)
22+
23+
This should be permissive relative to other patterns. You must cover system/service/hierarchy regexes, capability regexes, and event name regexes.
2124
"""
2225

2326

@@ -75,7 +78,11 @@ def __init__(
7578
self._wildcards: dict[str, TopicHandler] = {}
7679

7780
def add_subscription_channel(
78-
self, channel: str, callbacks: set[MessageCallback], persist: bool, queue_name: str
81+
self,
82+
channel: str,
83+
callbacks: set[MessageCallback],
84+
persist: bool,
85+
queue_name: str,
7986
) -> None:
8087
"""Start listening for messages on a channel on all configured brokers.
8188
@@ -167,7 +174,9 @@ def get_wildcard_topic_and_topic_handler(self, topic: str) -> tuple[str, TopicHa
167174
return wildcard, topic_handler
168175
return None
169176

170-
def get_all_subscription_channels(self) -> itertools.chain[tuple[str, TopicHandler]]:
177+
def get_all_subscription_channels(
178+
self,
179+
) -> itertools.chain[tuple[str, TopicHandler]]:
171180
"""Get all subscription channels, including wildcard channels.
172181
173182
This function is safe to call from the broker clients, as it does not mutate state.

src/intersect_sdk_common/control_plane/topic_handler.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ class TopicHandler:
2323
"""If this is a wildcard topic, the regex pattern to match incoming topics against (if no wildcards, this will be None)."""
2424

2525
def __init__(
26-
self, topic_persist: bool, queue_name: str, regex_pattern: str | None = None
26+
self,
27+
topic_persist: bool,
28+
queue_name: str,
29+
regex_pattern: str | None = None,
2730
) -> None:
2831
"""Initialize a TopicHandler instance.
2932
@@ -37,14 +40,15 @@ def __init__(
3740
self.queue_name = queue_name
3841

3942
if regex_pattern:
43+
# the generated regex must be permissive and allow any non-special characters _CHANNEL_REGEX (ControlPlaneManager) allows
4044
regex_builder = ['^']
4145
for char in regex_pattern:
4246
if char == '*':
4347
# match a single word (do not include the separator)
44-
regex_builder.append('[a-zA-Z0-9-]+')
48+
regex_builder.append('[a-zA-Z0-9_-]+')
4549
elif char == '#':
4650
# match any sequence of 0 or more words (make sure to allow for the separator)
47-
regex_builder.append('[a-zA-Z0-9/-]*')
51+
regex_builder.append('[a-zA-Z0-9/_-]*')
4852
elif char == '/':
4953
# in-memory topics use '/' as the separator, it is the protocol handler's responsibility to convert topics to use '/' as the separator
5054
regex_builder.append('/')

0 commit comments

Comments
 (0)