Skip to content

Commit 92c1b76

Browse files
committed
fixing template
1 parent 9281648 commit 92c1b76

2 files changed

Lines changed: 64 additions & 34 deletions

File tree

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import json
22
import logging
33
import os
4-
from typing import Dict, Any, Optional, List, Tuple
4+
import re
5+
from typing import Any, Dict, List
56

67
from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
78

89
# Get the directory where our templates are stored
910
TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)))
1011

1112

13+
def escape_raw_newlines_in_json_strings(raw_json: str) -> str:
14+
def fix_string(match):
15+
s = match.group(1)
16+
return s.replace("\n", "\\n") # Escape raw newlines in strings
17+
18+
STRING_LITERAL_RE = re.compile(r'("(?:\\.|[^"\\])*")', flags=re.DOTALL)
19+
return STRING_LITERAL_RE.sub(fix_string, raw_json)
20+
21+
1222
class SlackTemplateLoader:
1323
"""
1424
Loads and renders Jinja2 templates for Slack messages.
@@ -28,10 +38,10 @@ def __init__(self):
2838
def get_template(self, template_name: str) -> Template:
2939
"""
3040
Get a template by name, loading from file if not already cached.
31-
41+
3242
Args:
3343
template_name: The name of the template file (e.g., "header.j2")
34-
44+
3545
Returns:
3646
A Jinja2 Template object
3747
"""
@@ -42,41 +52,73 @@ def get_template(self, template_name: str) -> Template:
4252
logging.error(f"Error loading template {template_name}: {e}")
4353
# Return a simple default template as fallback
4454
return Template("Template loading error")
45-
55+
4656
return self._templates[template_name]
4757

4858
def render_to_blocks(self, template_name: str, context: Dict[str, Any]) -> List[Dict[str, Any]]:
4959
"""
5060
Render a template using the provided context and parse the result as JSON to get Slack blocks.
51-
61+
5262
Args:
5363
template_name: The name of the template file
5464
context: Dictionary of variables to pass to the template
55-
65+
5666
Returns:
5767
List of Slack block objects (dictionaries)
5868
"""
5969
template = self.get_template(template_name)
60-
70+
6171
try:
6272
rendered = template.render(**context)
63-
73+
6474
# Split by newlines to get multiple blocks and parse each as JSON
6575
blocks = []
76+
blocks = []
6677
for block_str in rendered.strip().split("\n\n"):
67-
if block_str.strip():
68-
try:
69-
block = json.loads(block_str)
70-
blocks.append(block)
71-
except json.JSONDecodeError as e:
72-
logging.error(f"Error parsing JSON from template output: {e}")
73-
logging.debug(f"Problematic JSON: {block_str}")
74-
78+
if not block_str.strip():
79+
continue
80+
81+
try:
82+
block_str_fixed = escape_raw_newlines_in_json_strings(block_str)
83+
block = json.loads(block_str_fixed)
84+
blocks.append(block)
85+
86+
except json.JSONDecodeError as e:
87+
logging.exception(f"Error parsing JSON from template output: {e}")
88+
logging.warning(f"Problematic JSON (repr): {repr(block_str)}")
89+
7590
return blocks
7691
except Exception as e:
7792
logging.error(f"Error rendering template {template_name}: {e}")
7893
return []
7994

95+
def render_custom_or_file_template_to_blocks(self, template_name: str, context: Dict[str, Any], custom_template: str = None) -> List[Dict[str, Any]]:
96+
"""
97+
Render a custom Jinja template string (if provided) or a file-based template to Slack blocks.
98+
Args:
99+
template_name: The name of the file-based template (e.g., "header.j2")
100+
context: Dictionary of variables to pass to the template
101+
custom_template: Optional Jinja template string to use instead of file-based template
102+
Returns:
103+
List of Slack block objects (dictionaries)
104+
"""
105+
if custom_template:
106+
try:
107+
template = Template(custom_template)
108+
rendered_blocks = []
109+
for block_str in template.render(**context).strip().split("\n\n"):
110+
if block_str.strip():
111+
block_str_fixed = escape_raw_newlines_in_json_strings(block_str)
112+
block = json.loads(block_str_fixed)
113+
rendered_blocks.append(block)
114+
return rendered_blocks
115+
except Exception as e:
116+
logging.error(f"Error rendering custom template: {e}")
117+
# Fall back to file-based template
118+
119+
# Use file-based template
120+
return self.render_to_blocks(template_name, context)
121+
80122

81123
# Singleton instance
82-
template_loader = SlackTemplateLoader()
124+
template_loader = SlackTemplateLoader()

src/robusta/integrations/slack/sender.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -507,23 +507,11 @@ def __create_finding_header(
507507
"resource_emoji": resource_emoji,
508508
"finding": finding
509509
}
510-
511-
# If custom template provided, use it directly with Jinja
512-
if custom_template:
513-
try:
514-
template = Template(custom_template)
515-
rendered_blocks = []
516-
for block_str in template.render(**template_context).strip().split("\n\n"):
517-
if block_str.strip():
518-
block = json.loads(block_str)
519-
rendered_blocks.append(block)
520-
return rendered_blocks
521-
except Exception as e:
522-
logging.error(f"Error rendering custom template: {e}")
523-
# Fall back to file-based template
524-
525-
# Use file-based template
526-
return template_loader.render_to_blocks(template_name, template_context)
510+
511+
# Use the new template loader method for both custom and file-based templates
512+
return template_loader.render_custom_or_file_template_to_blocks(
513+
template_name, template_context, custom_template
514+
)
527515

528516
def __create_links(
529517
self,

0 commit comments

Comments
 (0)