From 84f5b43e8bd09f5337feb5b640cd4848e19287de Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Sun, 5 Apr 2026 15:52:30 +0900 Subject: [PATCH 1/2] remove ms_teams --- docs/source/alerts.rst | 92 ----- docs/source/elastalert.rst | 1 - elastalert/alerters/teams.py | 120 ------- elastalert/loaders.py | 2 - elastalert/schema.yaml | 27 -- tests/alerters/teams_test.py | 650 ----------------------------------- 6 files changed, 892 deletions(-) delete mode 100644 elastalert/alerters/teams.py delete mode 100644 tests/alerters/teams_test.py diff --git a/docs/source/alerts.rst b/docs/source/alerts.rst index bab353eac..6a74fb816 100644 --- a/docs/source/alerts.rst +++ b/docs/source/alerts.rst @@ -38,7 +38,6 @@ or - line - matrixhookshot - mattermost - - ms_teams - ms_power_automate - opsgenie - pagerduty @@ -1633,97 +1632,6 @@ Example mattermost_attach_opensearch_discover_url, mattermost_kibana_discover_co mattermost_opensearch_discover_title: "Discover in opensearch" -Microsoft Teams -~~~~~~~~~~~~~~~ - -Microsoft Teams alerter will send a notification to a predefined Microsoft Teams channel. - -The alerter requires the following options: - -``ms_teams_webhook_url``: The webhook URL that includes your auth data and the ID of the channel you want to post to. Go to the Connectors -menu in your channel and configure an Incoming Webhook, then copy the resulting URL. You can use a list of URLs to send to multiple channels. - -Optional: - -``ms_teams_alert_summary``: MS Teams use this value for notification title, defaults to `Alert Subject `_. You can set this value with arbitrary text if you don't want to use the default. - -``ms_teams_theme_color``: By default the alert will be posted without any color line. To add color, set this attribute to a HTML color value e.g. ``#ff0000`` for red. - -``ms_teams_proxy``: By default ElastAlert 2 will not use a network proxy to send notifications to MS Teams. Set this option using ``hostname:port`` if you need to use a proxy. only supports https. - -``ms_teams_alert_fixed_width``: By default this is ``False`` and the notification will be sent to MS Teams as-is. Teams supports a partial Markdown implementation, which means asterisk, underscore and other characters may be interpreted as Markdown. Currently, Teams does not fully implement code blocks. Setting this attribute to ``True`` will enable line by line code blocks. It is recommended to enable this to get clearer notifications in Teams. - -``ms_teams_alert_facts``: You can add additional facts to your MS Teams alerts using this field. Specify the title using `name` and a value for the field or arbitrary text using `value`. - -Example ms_teams_alert_facts:: - - ms_teams_alert_facts: - - name: Host - value: monitor.host - - name: Status - value: monitor.status - - name: What to do - value: Page your boss - -``ms_teams_attach_kibana_discover_url``: Enables the attachment of the ``kibana_discover_url`` to the MS Teams notification. The config ``generate_kibana_discover_url`` must also be ``True`` in order to generate the url. Defaults to ``False``. - -``ms_teams_kibana_discover_title``: The title of the Kibana Discover url attachment. Defaults to ``Discover in Kibana``. - -``ms_teams_attach_opensearch_discover_url``: Enables the attachment of the ``opensearch_discover_url`` to the MS Teams notification. The config ``generate_opensearch_discover_url`` must also be ``True`` in order to generate the url. Defaults to ``False``. - -``ms_teams_opensearch_discover_title``: The title of the Opensearch Discover url attachment. Defaults to ``Discover in opensearch``. - -Example ms_teams_attach_kibana_discover_url, ms_teams_kibana_discover_title:: - - # (Required) - generate_kibana_discover_url: True - kibana_discover_app_url: "http://localhost:5601/app/discover#/" - kibana_discover_index_pattern_id: "4babf380-c3b1-11eb-b616-1b59c2feec54" - kibana_discover_version: "7.15" - - # (Optional) - kibana_discover_from_timedelta: - minutes: 10 - kibana_discover_to_timedelta: - minutes: 10 - - # (Required) - ms_teams_attach_kibana_discover_url: True - - # (Optional) - ms_teams_kibana_discover_title: "Discover in Kibana" - -Example ms_teams_attach_opensearch_discover_url, ms_teams_opensearch_discover_title:: - - # (Required) - generate_opensearch_discover_url: True - opensearch_discover_app_url: "http://localhost:5601/app/discover#/" - opensearch_discover_index_pattern_id: "4babf380-c3b1-11eb-b616-1b59c2feec54" - opensearch_discover_version: "7.15" - - # (Optional) - opensearch_discover_from_timedelta: - minutes: 10 - opensearch_discover_to_timedelta: - minutes: 10 - - # (Required) - ms_teams_attach_opensearch_discover_url: True - - # (Optional) - ms_teams_opensearch_discover_title: "Discover in opensearch" - -``ms_teams_ca_certs``: Set this option to ``True`` or a path to a CA cert bundle or directory (eg: ``/etc/ssl/certs/ca-certificates.crt``) to validate the SSL certificate. - -``ms_teams_ignore_ssl_errors``: By default ElastAlert 2 will verify SSL certificate. Set this option to ``True`` if you want to ignore SSL errors. - -Example usage:: - - alert: - - "ms_teams" - ms_teams_theme_color: "#6600ff" - ms_teams_webhook_url: "MS Teams Webhook URL" - Microsoft Power Automate ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/elastalert.rst b/docs/source/elastalert.rst index 975301a57..35ae1c06d 100755 --- a/docs/source/elastalert.rst +++ b/docs/source/elastalert.rst @@ -54,7 +54,6 @@ Currently, we have support built in for these alert types: - LINE Messaging API - Matrix Hookshot - Mattermost -- Microsoft Teams - Microsoft Power Automate - OpsGenie - PagerDuty diff --git a/elastalert/alerters/teams.py b/elastalert/alerters/teams.py deleted file mode 100644 index 7e6882ab2..000000000 --- a/elastalert/alerters/teams.py +++ /dev/null @@ -1,120 +0,0 @@ -import copy -import json -import requests - -from elastalert.alerts import Alerter, DateTimeEncoder -from elastalert.util import EAException, elastalert_logger, lookup_es_key -from requests.exceptions import RequestException - - -class MsTeamsAlerter(Alerter): - """ Creates a Microsoft Teams Conversation Message for each alert """ - required_options = frozenset(['ms_teams_webhook_url']) - - def __init__(self, rule): - super(MsTeamsAlerter, self).__init__(rule) - self.ms_teams_webhook_url = self.rule.get('ms_teams_webhook_url', None) - if isinstance(self.ms_teams_webhook_url, str): - self.ms_teams_webhook_url = [self.ms_teams_webhook_url] - self.ms_teams_proxy = self.rule.get('ms_teams_proxy', None) - self.ms_teams_alert_summary = self.rule.get('ms_teams_alert_summary', None) - self.ms_teams_alert_fixed_width = self.rule.get('ms_teams_alert_fixed_width', False) - self.ms_teams_theme_color = self.rule.get('ms_teams_theme_color', '') - self.ms_teams_ca_certs = self.rule.get('ms_teams_ca_certs') - self.ms_teams_ignore_ssl_errors = self.rule.get('ms_teams_ignore_ssl_errors', False) - self.ms_teams_alert_facts = self.rule.get('ms_teams_alert_facts', '') - self.ms_teams_attach_kibana_discover_url = self.rule.get('ms_teams_attach_kibana_discover_url', False) - self.ms_teams_kibana_discover_title = self.rule.get('ms_teams_kibana_discover_title', 'Discover in Kibana') - self.ms_teams_attach_opensearch_discover_url = self.rule.get('ms_teams_attach_opensearch_discover_url', False) - self.ms_teams_opensearch_discover_title = self.rule.get('ms_teams_opensearch_discover_title', 'Discover in opensearch') - - def format_body(self, body): - if self.ms_teams_alert_fixed_width: - body = body.replace('`', "'") - body = "```{0}```".format('```\n\n```'.join(x for x in body.split('\n'))).replace('\n``````', '') - return body - - def populate_facts(self, matches): - alert_facts = [] - for arg in self.ms_teams_alert_facts: - arg = copy.copy(arg) - matched_value = lookup_es_key(matches[0], arg['value']) - arg['value'] = matched_value if matched_value is not None else arg['value'] - alert_facts.append(arg) - return alert_facts - - def alert(self, matches): - body = self.create_alert_body(matches) - body = self.format_body(body) - - title = self.create_title(matches) - summary = title if self.ms_teams_alert_summary is None else self.ms_teams_alert_summary - # post to Teams - headers = {'content-type': 'application/json'} - - if self.ms_teams_ca_certs: - verify = self.ms_teams_ca_certs - else: - verify = not self.ms_teams_ignore_ssl_errors - if self.ms_teams_ignore_ssl_errors: - requests.packages.urllib3.disable_warnings() - - # set https proxy, if it was provided - proxies = {'https': self.ms_teams_proxy} if self.ms_teams_proxy else None - payload = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': summary , - 'title': title, - 'sections': [{'text': body}], - } - - if self.ms_teams_alert_facts != '': - payload['sections'][0]['facts'] = self.populate_facts(matches) - - if self.ms_teams_theme_color != '': - payload['themeColor'] = self.ms_teams_theme_color - - if self.ms_teams_attach_kibana_discover_url: - kibana_discover_url = lookup_es_key(matches[0], 'kibana_discover_url') - if kibana_discover_url: - payload['potentialAction'] = [ - { - '@type': 'OpenUri', - 'name': self.ms_teams_kibana_discover_title, - 'targets': [ - { - 'os': 'default', - 'uri': kibana_discover_url, - } - ], - } - ] - if self.ms_teams_attach_opensearch_discover_url: - opensearch_discover_url = lookup_es_key(matches[0], 'opensearch_discover_url') - if opensearch_discover_url: - payload['potentialAction'] = [ - { - '@type': 'OpenUri', - 'name': self.ms_teams_opensearch_discover_title, - 'targets': [ - { - 'os': 'default', - 'uri': opensearch_discover_url, - } - ], - } - ] - - for url in self.ms_teams_webhook_url: - try: - response = requests.post(url, data=json.dumps(payload, cls=DateTimeEncoder), - headers=headers, proxies=proxies, verify=verify) - response.raise_for_status() - except RequestException as e: - raise EAException("Error posting to MS Teams: %s" % e) - elastalert_logger.info("Alert sent to MS Teams") - - def get_info(self): - return {'type': 'ms_teams', - 'ms_teams_webhook_url': self.ms_teams_webhook_url} diff --git a/elastalert/loaders.py b/elastalert/loaders.py index 82b6ff58c..eeab26150 100644 --- a/elastalert/loaders.py +++ b/elastalert/loaders.py @@ -53,7 +53,6 @@ from elastalert.alerters.smseagle import SMSEagleAlerter from elastalert.alerters.sns import SnsAlerter from elastalert.alerters.sqs import SqsAlerter -from elastalert.alerters.teams import MsTeamsAlerter from elastalert.alerters.powerautomate import MsPowerAutomateAlerter from elastalert.alerters.yzj import YzjAlerter from elastalert.alerters.zabbix import ZabbixAlerter @@ -117,7 +116,6 @@ class RulesLoader(object): 'command': elastalert.alerters.command.CommandAlerter, 'sns': SnsAlerter, 'sqs': SqsAlerter, - 'ms_teams': MsTeamsAlerter, 'ms_power_automate': MsPowerAutomateAlerter, 'slack': SlackAlerter, 'mattermost': MattermostAlerter, diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index b31104f71..d26fcd50e 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -51,13 +51,6 @@ definitions: type: array items: *slackField - msTeamsFact: &msTeamsFact - type: object - additionalProperties: false - properties: - name: {type: string} - value: {type: string} - msPowerAutomateFact: &msPowerAutomateFact type: object additionalProperties: false @@ -65,10 +58,6 @@ definitions: name: {type: string} value: {type: string} - arrayOfMsTeamsFacts: &arrayOfMsTeamsFacts - type: array - items: *msTeamsFact - arrayOfMsPowerAutomateFacts: &arrayOfMsPowerAutomateFacts type: array items: *msPowerAutomateFact @@ -711,22 +700,6 @@ properties: mattermost_opensearch_discover_color: {type: string} mattermost_opensearch_discover_title: {type: string} - - ### Microsoft Teams - ms_teams_webhook_url: *arrayOfString - ms_teams_alert_summary: {type: string} - ms_teams_theme_color: {type: string} - ms_teams_proxy: {type: string} - ms_teams_alert_fixed_width: {type: boolean} - ms_teams_alert_facts: *arrayOfMsTeamsFacts - ms_teams_attach_kibana_discover_url: {type: boolean} - ms_teams_kibana_discover_title: {type: string} - ms_teams_ca_certs: {type: [boolean, string]} - ms_teams_ignore_ssl_errors: {type: boolean} - ms_teams_attach_opensearch_discover_url: {type: boolean} - ms_teams_opensearch_discover_title: {type: string} - - ### Microsoft Power Automate ms_power_automate_webhook_url: *arrayOfString ms_power_automate_webhook_url_from_field: { type: string } diff --git a/tests/alerters/teams_test.py b/tests/alerters/teams_test.py deleted file mode 100644 index b50a354b5..000000000 --- a/tests/alerters/teams_test.py +++ /dev/null @@ -1,650 +0,0 @@ -import json -import logging - -from unittest import mock -import pytest -from requests import RequestException - -from elastalert.alerters.teams import MsTeamsAlerter -from elastalert.alerts import BasicMatchString -from elastalert.loaders import FileRulesLoader -from elastalert.util import EAException - - -def test_ms_teams(caplog): - caplog.set_level(logging.INFO) - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}] - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) - assert ('elastalert', logging.INFO, 'Alert sent to MS Teams') == caplog.record_tuples[0] - - -def test_ms_teams_uses_color_and_fixed_width_text(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'ms_teams_alert_fixed_width': True, - 'ms_teams_theme_color': '#124578', - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - body = BasicMatchString(rule, match).__str__() - body = body.replace('`', "'") - body = "```{0}```".format('```\n\n```'.join(x for x in body.split('\n'))).replace('\n``````', '') - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'themeColor': '#124578', - 'sections': [{'text': body}] - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) - - -def test_ms_teams_proxy(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'ms_teams_proxy': 'https://test.proxy.url', - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}] - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies={'https': rule['ms_teams_proxy']}, - verify=True - ) - assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) - - -def test_ms_teams_ea_exception(): - with pytest.raises(EAException) as ea: - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz' - } - mock_run = mock.MagicMock(side_effect=RequestException) - with mock.patch('requests.post', mock_run), pytest.raises(RequestException): - alert.alert([match]) - assert 'Error posting to MS Teams: ' in str(ea) - - -def test_ms_teams_getinfo(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - - expected_data = { - 'type': 'ms_teams', - 'ms_teams_webhook_url': ['http://test.webhook.url'] - } - actual_data = alert.get_info() - assert expected_data == actual_data - - -@pytest.mark.parametrize('ms_teams_webhook_url, expected_data', [ - ('', 'Missing required option(s): ms_teams_webhook_url'), - ('http://test.webhook.url', - { - 'type': 'ms_teams', - 'ms_teams_webhook_url': ['http://test.webhook.url'] - }) -]) -def test_ms_teams_required_error(ms_teams_webhook_url, expected_data): - try: - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'alert_subject': 'Cool subject', - 'alert': [] - } - - if ms_teams_webhook_url != '': - rule['ms_teams_webhook_url'] = ms_teams_webhook_url - - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - - actual_data = alert.get_info() - assert expected_data == actual_data - except Exception as ea: - assert expected_data in str(ea) - - -@pytest.mark.parametrize('ca_certs, ignore_ssl_errors, expect_verify', [ - ('', '', True), - ('', True, False), - ('', False, True), - (True, '', True), - (True, True, True), - (True, False, True), - (False, '', True), - (False, True, False), - (False, False, True) -]) -def test_ms_teams_ca_certs(ca_certs, ignore_ssl_errors, expect_verify): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert_subject': 'Cool subject', - 'alert': [] - } - if ca_certs: - rule['ms_teams_ca_certs'] = ca_certs - - if ignore_ssl_errors: - rule['ms_teams_ignore_ssl_errors'] = ignore_ssl_errors - - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}] - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=expect_verify - ) - assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) - - -def test_ms_teams_attach_kibana_discover_url_when_generated(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_attach_kibana_discover_url': True, - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert': [], - 'alert_subject': 'Cool subject', - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'kibana_discover_url': 'http://kibana#discover' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}], - 'potentialAction': [ - { - '@type': 'OpenUri', - 'name': 'Discover in Kibana', - 'targets': [ - { - 'os': 'default', - 'uri': 'http://kibana#discover', - } - ], - } - ], - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - assert expected_data == actual_data - - -def test_ms_teams_attach_kibana_discover_url_when_not_generated(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_attach_kibana_discover_url': True, - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert': [], - 'alert_subject': 'Cool subject', - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}], - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - assert expected_data == actual_data - - -def test_ms_teams_kibana_discover_title(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_attach_kibana_discover_url': True, - 'ms_teams_kibana_discover_title': 'Click to discover in Kibana', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert': [], - 'alert_subject': 'Cool subject', - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'kibana_discover_url': 'http://kibana#discover' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}], - 'potentialAction': [ - { - '@type': 'OpenUri', - 'name': 'Click to discover in Kibana', - 'targets': [ - { - 'os': 'default', - 'uri': 'http://kibana#discover', - } - ], - } - ], - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - assert expected_data == actual_data - - -def test_ms_teams_attach_opensearch_discover_url_when_generated(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_attach_opensearch_discover_url': True, - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert': [], - 'alert_subject': 'Cool subject', - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'opensearch_discover_url': 'http://opensearch#discover' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}], - 'potentialAction': [ - { - '@type': 'OpenUri', - 'name': 'Discover in opensearch', - 'targets': [ - { - 'os': 'default', - 'uri': 'http://opensearch#discover', - } - ], - } - ], - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - assert expected_data == actual_data - - -def test_ms_teams_attach_opensearch_discover_url_when_not_generated(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_attach_opensearch_discover_url': True, - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert': [], - 'alert_subject': 'Cool subject', - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}], - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - assert expected_data == actual_data - - -def test_ms_teams_opensearch_discover_title(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_attach_opensearch_discover_url': True, - 'ms_teams_opensearch_discover_title': 'Click to discover in opensearch', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'alert': [], - 'alert_subject': 'Cool subject', - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'opensearch_discover_url': 'http://opensearch#discover' - } - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [{'text': BasicMatchString(rule, match).__str__()}], - 'potentialAction': [ - { - '@type': 'OpenUri', - 'name': 'Click to discover in opensearch', - 'targets': [ - { - 'os': 'default', - 'uri': 'http://opensearch#discover', - } - ], - } - ], - } - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) - assert expected_data == actual_data - - -def test_ms_teams_alert_facts(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'ms_teams_alert_summary': 'Alert from ElastAlert', - 'ms_teams_alert_facts': [ - { - 'name': 'Host', - 'value': 'somefield' - }, - { - 'name': 'Sensors', - 'value': '@timestamp' - }, - { - 'name': 'Speed', - 'value': 'vehicle.speed' - }, - { - 'name': 'Boolean', - 'value': 'boolean' - }, - { - 'name': 'Blank', - 'value': 'blank' - }, - { - 'name': 'Arbitrary Text Name', - 'value': 'Arbitrary Text Value' - } - ], - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz', - 'vehicle': { - 'speed': 0, - }, - 'boolean': False, - 'blank': '' - } - - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['ms_teams_alert_summary'], - 'title': rule['alert_subject'], - 'sections': [ - { - 'text': BasicMatchString(rule, match).__str__(), - 'facts': [ - {'name': 'Host', 'value': 'foobarbaz'}, - {'name': 'Sensors', 'value': '2016-01-01T00:00:00'}, - {'name': 'Speed', 'value': 0}, - {'name': 'Boolean', 'value': False}, - {'name': 'Blank', 'value': ''}, - {'name': 'Arbitrary Text Name', 'value': 'Arbitrary Text Value'} - ], - } - ], - } - - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) - - -def test_ms_teams_alert_summary_none(): - rule = { - 'name': 'Test Rule', - 'type': 'any', - 'ms_teams_webhook_url': 'http://test.webhook.url', - 'alert_subject': 'Cool subject', - 'alert': [] - } - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = MsTeamsAlerter(rule) - match = { - '@timestamp': '2016-01-01T00:00:00', - 'somefield': 'foobarbaz' - } - - with mock.patch('requests.post') as mock_post_request: - alert.alert([match]) - - expected_data = { - '@type': 'MessageCard', - '@context': 'http://schema.org/extensions', - 'summary': rule['alert_subject'], - 'title': rule['alert_subject'], - 'sections': [ - { - 'text': BasicMatchString(rule, match).__str__() - } - ], - } - - mock_post_request.assert_called_once_with( - rule['ms_teams_webhook_url'], - data=mock.ANY, - headers={'content-type': 'application/json'}, - proxies=None, - verify=True - ) - assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) From 46162f387448b5032273cb8e5f36ee4cd26f8a11 Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Sun, 5 Apr 2026 15:55:38 +0900 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79555c915..6d8e654ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - [Datadog] Add optional `datadog_api_url` parameter to support regional Datadog sites (US3, US5, EU1, AP1, etc.) - [#1754](https://github.com/jertel/elastalert2/pull/1754) - @BillyWeans ## Other changes -- None +- Remove MS Teams Alerter - [#1757](https://github.com/jertel/elastalert2/pull/1757) - @nsano-rururu # 2.29.0