Skip to content

Commit 97bd2ef

Browse files
authored
Merge pull request #4985 from grafana/dev
v1.9.22
2 parents 0d315fc + 0fa3522 commit 97bd2ef

File tree

11 files changed

+166
-85
lines changed

11 files changed

+166
-85
lines changed
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
name: Install frontend dependencies
22
description: Setup node/pnpm + install frontend dependencies
3+
inputs:
4+
oncall-directory:
5+
description: "Relative path to oncall directory"
6+
required: false
7+
default: "."
38
runs:
49
using: composite
510
steps:
611
- name: Install pnpm
712
uses: pnpm/action-setup@v4
813
with:
914
version: 9.1.4
15+
- name: Determine grafana-plugin directory location
16+
id: grafana-plugin-directory
17+
shell: bash
18+
run: echo "grafana-plugin-directory=${{ inputs.oncall-directory }}/grafana-plugin" >> $GITHUB_OUTPUT
19+
- name: Determine pnpm-lock.yaml location
20+
id: pnpm-lock-location
21+
shell: bash
22+
# yamllint disable rule:line-length
23+
run: echo "pnpm-lock-location=${{ steps.grafana-plugin-directory.outputs.grafana-plugin-directory }}/pnpm-lock.yaml" >> $GITHUB_OUTPUT
24+
# yamllint enable rule:line-length
1025
- uses: actions/setup-node@v4
1126
with:
1227
node-version: 20.15.1
1328
cache: pnpm
14-
cache-dependency-path: grafana-plugin/pnpm-lock.yaml
29+
cache-dependency-path: ${{ steps.pnpm-lock-location.outputs.pnpm-lock-location }}
1530
- name: Install frontend dependencies
1631
shell: bash
17-
working-directory: grafana-plugin
32+
working-directory: ${{ steps.grafana-plugin-directory.outputs.grafana-plugin-directory }}
1833
run: pnpm install --frozen-lockfile --prefer-offline

docs/sources/configure/jinja2-templating/advanced-templates/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ Grafana OnCall enhances Jinja with additional functions:
9595
- `regex_replace`: Performs a regex find and replace
9696
- `regex_match`: Performs a regex match, returns `True` or `False`
9797
- Usage example: `{{ payload.ruleName | regex_match(".*") }}`
98+
- `regex_search`: Performs a regex search, returns `True` or `False`
99+
- Usage example: `{{ payload.message | regex_search("Severity: (High|Critical)") }}`
98100
- `b64decode`: Performs a base64 string decode
99101
- Usage example: `{{ payload.data | b64decode }}`
100102
- `parse_json`:Parses a JSON string to an object

engine/apps/email/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def get_from_email(user):
2121
return live_settings.EMAIL_FROM_ADDRESS
2222

2323
if settings.LICENSE == settings.CLOUD_LICENSE_NAME:
24-
return "oncall@{}.grafana.net".format(user.organization.stack_slug)
24+
return "oncall@{}.{}".format(user.organization.stack_slug, settings.EMAIL_FROM_DOMAIN)
2525

2626
return live_settings.EMAIL_HOST_USER
2727

engine/common/jinja_templater/filters.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import base64
22
import json
3-
import re
43
from datetime import datetime
54

5+
import regex
66
from django.utils.dateparse import parse_datetime
77
from pytz import timezone
88

9+
REGEX_TIMEOUT = 2
10+
911

1012
def datetimeparse(value, format="%H:%M / %d-%m-%Y"):
1113
try:
@@ -52,22 +54,22 @@ def json_dumps(value):
5254

5355
def regex_replace(value, find, replace):
5456
try:
55-
return re.sub(find, replace, value)
56-
except (ValueError, AttributeError, TypeError):
57+
return regex.sub(find, replace, value, timeout=REGEX_TIMEOUT)
58+
except (ValueError, AttributeError, TypeError, TimeoutError):
5759
return None
5860

5961

6062
def regex_match(pattern, value):
6163
try:
62-
return bool(re.match(value, pattern))
63-
except (ValueError, AttributeError, TypeError):
64+
return bool(regex.match(value, pattern, timeout=REGEX_TIMEOUT))
65+
except (ValueError, AttributeError, TypeError, TimeoutError):
6466
return None
6567

6668

6769
def regex_search(pattern, value):
6870
try:
69-
return bool(re.search(value, pattern))
70-
except (ValueError, AttributeError, TypeError):
71+
return bool(regex.search(value, pattern, timeout=REGEX_TIMEOUT))
72+
except (ValueError, AttributeError, TypeError, TimeoutError):
7173
return None
7274

7375

engine/common/tests/test_apply_jinja_template.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,38 @@
1515
templated_value_is_truthy,
1616
)
1717

18+
EMAIL_SAMPLE_PAYLOAD = {
19+
"subject": "[Reminder] Review GKE getServerConfig API permission changes",
20+
"message": "Hello Google Kubernetes Customer,\r\n"
21+
"\r\n"
22+
"We’re writing to remind you that starting October 22, 2024, "
23+
"the \r\n"
24+
"getServerConfig API for Google Kubernetes Engine (GKE) will "
25+
"enforce \r\n"
26+
"Identity and Access Management (IAM) container.clusters.list "
27+
"checks. This \r\n"
28+
"change follows a series of security improvements as IAM \r\n"
29+
"container.clusters.list permissions are being enforced across "
30+
"the \r\n"
31+
"getServerConfig API.\r\n"
32+
"\r\n"
33+
"We’ve provided additional information below to guide you through "
34+
"this \r\n"
35+
"change.\r\n"
36+
"\r\n"
37+
"What you need to know\r\n"
38+
"\r\n"
39+
"The current implementation doesn’t apply a specific permissions "
40+
"check via \r\n"
41+
"getServerConfig API. After this change goes into effect for the "
42+
"Google \r\n"
43+
"Kubernetes Engine API getServerConfig, only authorized users with "
44+
"the \r\n"
45+
"container.clusters.list permissions will be able to call the \r\n"
46+
"GetServerConfig.\r\n",
47+
"sender": "[email protected]",
48+
}
49+
1850

1951
def test_apply_jinja_template():
2052
payload = {"name": "test"}
@@ -127,25 +159,49 @@ def test_apply_jinja_template_json_dumps():
127159
assert result == expected
128160

129161

162+
@pytest.mark.filterwarnings("ignore:::jinja2.*") # ignore regex escape sequence warning
130163
def test_apply_jinja_template_regex_match():
131-
payload = {"name": "test"}
164+
payload = {
165+
"name": "test",
166+
"message": json.dumps(EMAIL_SAMPLE_PAYLOAD),
167+
}
132168

133169
assert apply_jinja_template("{{ payload.name | regex_match('.*') }}", payload) == "True"
134170
assert apply_jinja_template("{{ payload.name | regex_match('tes') }}", payload) == "True"
135171
assert apply_jinja_template("{{ payload.name | regex_match('test1') }}", payload) == "False"
172+
# check for timeouts
173+
with patch("common.jinja_templater.filters.REGEX_TIMEOUT", 1):
174+
assert (
175+
apply_jinja_template(
176+
"{{ payload.message | regex_match('(.|\\s)+Severity(.|\\s){2}High(.|\\s)+') }}", payload
177+
)
178+
== "False"
179+
)
136180

137181
# Check that exception is raised when regex is invalid
138182
with pytest.raises(JinjaTemplateError):
139183
apply_jinja_template("{{ payload.name | regex_match('*') }}", payload)
140184

141185

186+
@pytest.mark.filterwarnings("ignore:::jinja2.*") # ignore regex escape sequence warning
142187
def test_apply_jinja_template_regex_search():
143-
payload = {"name": "test"}
188+
payload = {
189+
"name": "test",
190+
"message": json.dumps(EMAIL_SAMPLE_PAYLOAD),
191+
}
144192

145193
assert apply_jinja_template("{{ payload.name | regex_search('.*') }}", payload) == "True"
146194
assert apply_jinja_template("{{ payload.name | regex_search('tes') }}", payload) == "True"
147195
assert apply_jinja_template("{{ payload.name | regex_search('est') }}", payload) == "True"
148196
assert apply_jinja_template("{{ payload.name | regex_search('test1') }}", payload) == "False"
197+
# check for timeouts
198+
with patch("common.jinja_templater.filters.REGEX_TIMEOUT", 1):
199+
assert (
200+
apply_jinja_template(
201+
"{{ payload.message | regex_search('(.|\\s)+Severity(.|\\s){2}High(.|\\s)+') }}", payload
202+
)
203+
== "False"
204+
)
149205

150206
# Check that exception is raised when regex is invalid
151207
with pytest.raises(JinjaTemplateError):

engine/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ module = [
7171
"polymorphic.*",
7272
"pyroscope.*",
7373
"ratelimit.*",
74+
"regex.*",
7475
"recurring_ical_events.*",
7576
"rest_polymorphic.*",
7677
"slackclient.*",

engine/requirements.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
babel==2.12.1
22
beautifulsoup4==4.12.2
33
celery[redis]==5.3.1
4-
cryptography==42.0.8
4+
cryptography==43.0.1
55
django==4.2.15
66
django-add-default-value==0.10.0
77
django-amazon-ses==4.0.1
@@ -52,7 +52,7 @@ PyMySQL==1.1.1
5252
python-telegram-bot==13.13
5353
recurring-ical-events==2.1.0
5454
redis==5.0.1
55-
regex==2021.11.2
55+
regex==2024.7.24
5656
requests==2.32.3
5757
slack-export-viewer==1.1.4
5858
slack_sdk==3.21.3

0 commit comments

Comments
 (0)