Skip to content

Commit e137497

Browse files
dc-larsenlelia
andauthored
Fix Slack and MS Teams notifiers not reading URL from dashboard config (#37)
Same config key mismatch as #34 (webhook). Both notifiers read self.config.get('webhook_url') but notifications.yaml defines param names as 'slack_webhook_url' and 'msteams_webhook_url'. Dashboard config values were silently dropped. Also adds missing MS Teams auto-enablement block in NotificationManager.load_from_config(), which prevented the notifier from loading via dashboard config or env var at all. Env var fallback paths (INPUT_SLACK_WEBHOOK_URL, INPUT_MSTEAMS_WEBHOOK_URL) were unaffected. Co-authored-by: lelia <lelia@socket.dev>
1 parent 82c37fb commit e137497

File tree

5 files changed

+182
-2
lines changed

5 files changed

+182
-2
lines changed

socket_basics/core/notification/manager.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
load_connectors_config,
99
get_slack_webhook_url,
1010
get_webhook_url,
11+
get_msteams_webhook_url,
1112
get_ms_sentinel_workspace_id,
1213
get_jira_url,
1314
get_sumologic_endpoint,
@@ -74,6 +75,19 @@ def load_from_config(self) -> None:
7475
else:
7576
enable_cause = 'app_config:slack_webhook_url'
7677

78+
# MS Teams: webhook
79+
if name.lower() == 'msteams':
80+
msteams_url = get_msteams_webhook_url()
81+
if (
82+
msteams_url
83+
or (self.app_config and self.app_config.get('msteams_webhook_url'))
84+
):
85+
enabled = True
86+
if msteams_url:
87+
enable_cause = 'env:MSTEAMS_WEBHOOK_URL or INPUT_MSTEAMS_WEBHOOK_URL'
88+
else:
89+
enable_cause = 'app_config:msteams_webhook_url'
90+
7791
# Webhook generic
7892
if name.lower() == 'webhook':
7993
webhook = get_webhook_url()

socket_basics/core/notification/ms_teams_notifier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def __init__(self, params: Dict[str, Any] | None = None):
1919
super().__init__(params or {})
2020
# Teams webhook URL from params, env variable, or app config
2121
self.webhook_url = (
22-
self.config.get('webhook_url') or
22+
self.config.get('msteams_webhook_url') or
2323
get_msteams_webhook_url()
2424
)
2525
self.title = self.config.get('title', 'Socket Security')

socket_basics/core/notification/slack_notifier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def __init__(self, params: Dict[str, Any] | None = None):
1919
super().__init__(params or {})
2020
# Slack webhook URL from params, env variable, or app config
2121
self.webhook_url = (
22-
self.config.get('webhook_url') or
22+
self.config.get('slack_webhook_url') or
2323
get_slack_webhook_url()
2424
)
2525
self.username = "Socket Security"
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import os
2+
3+
from socket_basics.core.notification.ms_teams_notifier import MSTeamsNotifier
4+
from socket_basics.core.notification.manager import NotificationManager
5+
6+
7+
def _base_cfg():
8+
return {
9+
"notifiers": {
10+
"msteams": {
11+
"module_path": "socket_basics.core.notification.ms_teams_notifier",
12+
"class": "MSTeamsNotifier",
13+
"parameters": [
14+
{"name": "msteams_webhook_url", "env_variable": "INPUT_MSTEAMS_WEBHOOK_URL", "type": "str"},
15+
],
16+
}
17+
}
18+
}
19+
20+
21+
def test_msteams_notifier_reads_url_from_params():
22+
"""msteams_webhook_url param from dashboard config should populate self.webhook_url"""
23+
n = MSTeamsNotifier({"msteams_webhook_url": "https://outlook.office.com/webhook/xxx"})
24+
assert n.webhook_url == "https://outlook.office.com/webhook/xxx"
25+
26+
27+
def test_msteams_notifier_url_is_none_without_config(monkeypatch):
28+
"""Without any config or env var, webhook_url should be falsy"""
29+
monkeypatch.delenv("MSTEAMS_WEBHOOK_URL", raising=False)
30+
monkeypatch.delenv("INPUT_MSTEAMS_WEBHOOK_URL", raising=False)
31+
n = MSTeamsNotifier({})
32+
assert not n.webhook_url
33+
34+
35+
def test_msteams_notifier_falls_back_to_env_var(monkeypatch):
36+
"""INPUT_MSTEAMS_WEBHOOK_URL env var should work as fallback when params empty"""
37+
monkeypatch.setenv("INPUT_MSTEAMS_WEBHOOK_URL", "https://outlook.office.com/webhook/env")
38+
n = MSTeamsNotifier({})
39+
assert n.webhook_url == "https://outlook.office.com/webhook/env"
40+
41+
42+
def test_msteams_notifier_params_take_precedence_over_env(monkeypatch):
43+
"""Dashboard config (params) should take precedence over env var"""
44+
monkeypatch.setenv("INPUT_MSTEAMS_WEBHOOK_URL", "https://outlook.office.com/webhook/env")
45+
n = MSTeamsNotifier({"msteams_webhook_url": "https://outlook.office.com/webhook/dashboard"})
46+
assert n.webhook_url == "https://outlook.office.com/webhook/dashboard"
47+
48+
49+
def test_msteams_enabled_via_app_config(monkeypatch):
50+
"""MS Teams notifier should load and receive URL when msteams_webhook_url is in app_config"""
51+
monkeypatch.delenv("MSTEAMS_WEBHOOK_URL", raising=False)
52+
monkeypatch.delenv("INPUT_MSTEAMS_WEBHOOK_URL", raising=False)
53+
54+
cfg = _base_cfg()
55+
nm = NotificationManager(cfg, app_config={"msteams_webhook_url": "https://outlook.office.com/webhook/dashboard"})
56+
nm.load_from_config()
57+
58+
msteams = next(n for n in nm.notifiers if getattr(n, "name", "") == "msteams")
59+
assert msteams.webhook_url == "https://outlook.office.com/webhook/dashboard"
60+
61+
62+
def test_msteams_enabled_via_env_var(monkeypatch):
63+
"""MS Teams notifier should load when INPUT_MSTEAMS_WEBHOOK_URL env var is set"""
64+
monkeypatch.setenv("INPUT_MSTEAMS_WEBHOOK_URL", "https://outlook.office.com/webhook/env")
65+
66+
cfg = _base_cfg()
67+
nm = NotificationManager(cfg, app_config={})
68+
nm.load_from_config()
69+
70+
msteams = next(n for n in nm.notifiers if getattr(n, "name", "") == "msteams")
71+
assert msteams.webhook_url == "https://outlook.office.com/webhook/env"
72+
73+
74+
def test_msteams_app_config_precedence_over_env(monkeypatch):
75+
"""app_config msteams_webhook_url should take precedence over env var in manager flow"""
76+
monkeypatch.setenv("INPUT_MSTEAMS_WEBHOOK_URL", "https://outlook.office.com/webhook/env")
77+
78+
cfg = _base_cfg()
79+
nm = NotificationManager(cfg, app_config={"msteams_webhook_url": "https://outlook.office.com/webhook/dashboard"})
80+
nm.load_from_config()
81+
82+
msteams = next(n for n in nm.notifiers if getattr(n, "name", "") == "msteams")
83+
assert msteams.webhook_url == "https://outlook.office.com/webhook/dashboard"
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import os
2+
3+
from socket_basics.core.notification.slack_notifier import SlackNotifier
4+
from socket_basics.core.notification.manager import NotificationManager
5+
6+
7+
def _base_cfg():
8+
return {
9+
"notifiers": {
10+
"slack": {
11+
"module_path": "socket_basics.core.notification.slack_notifier",
12+
"class": "SlackNotifier",
13+
"parameters": [
14+
{"name": "slack_webhook_url", "env_variable": "INPUT_SLACK_WEBHOOK_URL", "type": "str"},
15+
],
16+
}
17+
}
18+
}
19+
20+
21+
def test_slack_notifier_reads_url_from_params():
22+
"""slack_webhook_url param from dashboard config should populate self.webhook_url"""
23+
n = SlackNotifier({"slack_webhook_url": "https://hooks.slack.com/services/T00/B00/xxx"})
24+
assert n.webhook_url == "https://hooks.slack.com/services/T00/B00/xxx"
25+
26+
27+
def test_slack_notifier_url_is_none_without_config(monkeypatch):
28+
"""Without any config or env var, webhook_url should be falsy"""
29+
monkeypatch.delenv("SLACK_WEBHOOK_URL", raising=False)
30+
monkeypatch.delenv("INPUT_SLACK_WEBHOOK_URL", raising=False)
31+
n = SlackNotifier({})
32+
assert not n.webhook_url
33+
34+
35+
def test_slack_notifier_falls_back_to_env_var(monkeypatch):
36+
"""INPUT_SLACK_WEBHOOK_URL env var should work as fallback when params empty"""
37+
monkeypatch.setenv("INPUT_SLACK_WEBHOOK_URL", "https://hooks.slack.com/env")
38+
n = SlackNotifier({})
39+
assert n.webhook_url == "https://hooks.slack.com/env"
40+
41+
42+
def test_slack_notifier_params_take_precedence_over_env(monkeypatch):
43+
"""Dashboard config (params) should take precedence over env var"""
44+
monkeypatch.setenv("INPUT_SLACK_WEBHOOK_URL", "https://hooks.slack.com/env")
45+
n = SlackNotifier({"slack_webhook_url": "https://hooks.slack.com/dashboard"})
46+
assert n.webhook_url == "https://hooks.slack.com/dashboard"
47+
48+
49+
def test_slack_enabled_via_app_config(monkeypatch):
50+
"""Slack notifier should load and receive URL when slack_webhook_url is in app_config"""
51+
monkeypatch.delenv("SLACK_WEBHOOK_URL", raising=False)
52+
monkeypatch.delenv("INPUT_SLACK_WEBHOOK_URL", raising=False)
53+
54+
cfg = _base_cfg()
55+
nm = NotificationManager(cfg, app_config={"slack_webhook_url": "https://hooks.slack.com/dashboard"})
56+
nm.load_from_config()
57+
58+
slack = next(n for n in nm.notifiers if getattr(n, "name", "") == "slack")
59+
assert slack.webhook_url == "https://hooks.slack.com/dashboard"
60+
61+
62+
def test_slack_enabled_via_env_var(monkeypatch):
63+
"""Slack notifier should load when INPUT_SLACK_WEBHOOK_URL env var is set"""
64+
monkeypatch.setenv("INPUT_SLACK_WEBHOOK_URL", "https://hooks.slack.com/env")
65+
66+
cfg = _base_cfg()
67+
nm = NotificationManager(cfg, app_config={})
68+
nm.load_from_config()
69+
70+
slack = next(n for n in nm.notifiers if getattr(n, "name", "") == "slack")
71+
assert slack.webhook_url == "https://hooks.slack.com/env"
72+
73+
74+
def test_slack_app_config_precedence_over_env(monkeypatch):
75+
"""app_config slack_webhook_url should take precedence over env var in manager flow"""
76+
monkeypatch.setenv("INPUT_SLACK_WEBHOOK_URL", "https://hooks.slack.com/env")
77+
78+
cfg = _base_cfg()
79+
nm = NotificationManager(cfg, app_config={"slack_webhook_url": "https://hooks.slack.com/dashboard"})
80+
nm.load_from_config()
81+
82+
slack = next(n for n in nm.notifiers if getattr(n, "name", "") == "slack")
83+
assert slack.webhook_url == "https://hooks.slack.com/dashboard"

0 commit comments

Comments
 (0)