"""Telegram alerts are sent with parse_mode='HTML', so every interpolated
value has to be escaped.
Unescaped, an alert message as ordinary as "Disk usage > 90% on /var & /tmp"
makes the Bot API reject the request with "can't parse entities" and the whole
notification is dropped — precisely when something is already wrong on the box.
These pin the escaping and that the literal markup survives it.
"""
from unittest.mock import patch
from app.services.notification_service import NotificationService
TELEGRAM_CONFIG = {
'enabled': True,
'bot_token': 'test-token',
'chat_id': '123456',
'notify_on': ['critical', 'warning', 'info'],
}
class _FakeResponse:
def __init__(self, payload):
self._payload = payload
def json(self):
return self._payload
def _send(alerts, hostname='test-host'):
"""Run send_telegram against a stubbed API and return the posted payload."""
captured = {}
def fake_post(url, json=None, timeout=None):
captured['url'] = url
captured['payload'] = json
return _FakeResponse({'ok': True})
with patch('app.services.notification_service.requests.post', side_effect=fake_post), \
patch.object(NotificationService, 'get_hostname', return_value=hostname):
result = NotificationService.send_telegram(alerts, config=dict(TELEGRAM_CONFIG))
assert result['success'] is True, result
return captured['payload']
def test_alert_message_with_html_metacharacters_is_escaped():
"""The regression: > and & in a message used to reach Telegram raw."""
payload = _send([{
'severity': 'warning',
'type': 'disk',
'message': 'Disk usage > 90% on /var & /tmp',
}])
text = payload['text']
assert 'Disk usage > 90% on /var & /tmp' in text
# The raw form must be gone, or the API rejects the whole message.
assert 'Disk usage > 90%' not in text
def test_angle_bracket_payload_cannot_inject_markup():
"""A value that looks like a tag is data, not markup."""
payload = _send([{
'severity': 'critical',
'type': 'service',
'message': 'container web exited',
}])
text = payload['text']
assert '<b>web</b>' in text
assert 'web' not in text
def test_hostname_and_threshold_values_are_escaped():
"""Every interpolated field, not just the message."""
payload = _send(
[{
'severity': 'warning',
'type': 'cpu',
'message': 'high load',
'value': '95% > limit',
'threshold': '90% & rising',
}],
hostname='box<1>&2',
)
text = payload['text']
assert 'box<1>&2' in text
assert 'Current: 95% > limit' in text
assert 'Threshold: 90% & rising' in text
def test_literal_markup_and_parse_mode_survive_escaping():
"""Escaping data must not escape the template's own tags."""
payload = _send([{
'severity': 'info',
'type': 'test',
'message': 'plain message',
}])
text = payload['text']
assert payload['parse_mode'] == 'HTML'
assert '🔔 ServerKit Alert' in text
assert 'Host: test-host' in text
assert 'INFO: TEST' in text