diff --git a/docs/configuration/sinks/ms-teams.rst b/docs/configuration/sinks/ms-teams.rst index 8e5747ed3..ef6466471 100644 --- a/docs/configuration/sinks/ms-teams.rst +++ b/docs/configuration/sinks/ms-teams.rst @@ -93,4 +93,35 @@ For example: - ms_teams_sink: name: main_ms_teams_sink webhook_url: teams-incoming-webhook - prefer_redirect_to_platform: false \ No newline at end of file + prefer_redirect_to_platform: false + +File Attachments +------------------------------------------------------------------- + +MS Teams Power Automate workflow webhooks have a strict 28KB payload size limit. +Robusta automatically detects Power Automate URLs and disables file attachments +to avoid exceeding this limit. + +**Auto-detection behavior:** + +- Power Automate URLs (``*.api.powerplatform.com``): files disabled by default +- Legacy webhook URLs (``*.webhook.office.com``): files enabled by default + +**Override auto-detection:** + +You can explicitly control file attachments using the ``send_files`` parameter: + +.. code-block:: yaml + + sinksConfig: + - ms_teams_sink: + name: main_ms_teams_sink + webhook_url: teams-incoming-webhook + send_files: true # Force enable files (override auto-detection) + # send_files: false # Force disable files + +.. note:: + + When ``send_files`` is false (or auto-detected as false for Power Automate), + all file attachments (images, logs, graphs, etc.) will not be included in + the MS Teams message. Text-based content will still be sent normally. \ No newline at end of file diff --git a/src/robusta/core/sinks/msteams/msteams_sink.py b/src/robusta/core/sinks/msteams/msteams_sink.py index f96b7f6b8..57b9f81c2 100644 --- a/src/robusta/core/sinks/msteams/msteams_sink.py +++ b/src/robusta/core/sinks/msteams/msteams_sink.py @@ -12,6 +12,12 @@ def __init__(self, sink_config: MsTeamsSinkConfigWrapper, registry): self.sink_config = sink_config.ms_teams_sink def write_finding(self, finding: Finding, platform_enabled: bool): + """Write a finding to the MS Teams channel via webhook. + + Args: + finding: The finding to send to MS Teams. + platform_enabled: Whether the Robusta platform is enabled for enhanced links. + """ MsTeamsSender.send_finding_to_ms_teams( self.webhook_url, finding, @@ -20,4 +26,5 @@ def write_finding(self, finding: Finding, platform_enabled: bool): self.account_id, self.webhook_override, self.sink_config.prefer_redirect_to_platform, + self.sink_config.send_files, ) diff --git a/src/robusta/core/sinks/msteams/msteams_sink_params.py b/src/robusta/core/sinks/msteams/msteams_sink_params.py index b10ba7ea0..d5871ec10 100644 --- a/src/robusta/core/sinks/msteams/msteams_sink_params.py +++ b/src/robusta/core/sinks/msteams/msteams_sink_params.py @@ -10,6 +10,7 @@ class MsTeamsSinkParams(SinkBaseParams): webhook_url: str webhook_override: Optional[str] = None + send_files: Optional[bool] = None # Auto-detect: False for Power Automate, True for legacy @classmethod def _get_sink_type(cls): diff --git a/src/robusta/integrations/msteams/sender.py b/src/robusta/integrations/msteams/sender.py index 686b0743e..3a94985e1 100644 --- a/src/robusta/integrations/msteams/sender.py +++ b/src/robusta/integrations/msteams/sender.py @@ -1,4 +1,5 @@ import logging +from typing import Optional from robusta.core.reporting import ( BaseBlock, @@ -18,6 +19,15 @@ from robusta.integrations.msteams.msteams_msg import MsTeamsMsg +def _is_power_automate_url(url: str) -> bool: + """Check if URL is a Power Automate workflow webhook (has 28KB payload limit). + + Power Automate URLs contain '.api.powerplatform.com' or '/powerautomate/'. + Legacy connector URLs use '*.webhook.office.com' and don't have the 28KB limit. + """ + return ".api.powerplatform.com" in url or "/powerautomate/" in url + + class MsTeamsSender: @classmethod def __to_ms_teams(cls, block: BaseBlock, msg: MsTeamsMsg): @@ -61,15 +71,40 @@ def send_finding_to_ms_teams( account_id: str, webhook_override: str, prefer_redirect_to_platform: bool, + send_files: Optional[bool] = None, ): + """Send a finding to MS Teams via webhook. + + Args: + webhook_url: The MS Teams webhook URL. + finding: The finding to send. + platform_enabled: Whether the Robusta platform is enabled. + cluster_name: The name of the cluster. + account_id: The Robusta account ID. + webhook_override: Optional webhook URL override pattern. + prefer_redirect_to_platform: Whether to prefer platform links over Prometheus. + send_files: Whether to include file attachments. None (default) auto-detects + based on webhook URL: disabled for Power Automate (28KB limit), enabled + for legacy webhooks. Explicit True/False overrides auto-detection. + """ webhook_url = MsTeamsWebhookUrlTransformer.template( webhook_override=webhook_override, default_webhook_url=webhook_url, annotations=finding.subject.annotations ) + + # Auto-detect send_files based on webhook URL if not explicitly set + if send_files is None: + send_files = not _is_power_automate_url(webhook_url) + msg = MsTeamsMsg(webhook_url, prefer_redirect_to_platform) msg.write_title_and_desc(platform_enabled, finding, cluster_name, account_id) for enrichment in finding.enrichments: files_blocks, other_blocks = cls.__split_block_to_files_and_all_the_rest(enrichment) + + # Filter out all files when send_files is False to avoid 28KB payload limit + if not send_files: + files_blocks = [] + for block in other_blocks: cls.__to_ms_teams(block, msg)