Skip to content

Commit 601779d

Browse files
markstoryandrewshie-sentry
authored andcommitted
fix(taskworker) Remove pickle usage from sentryapps task (#91372)
The `event` parameter of process_service_hook requires pickle. By generating the payload before spawning a task, we don't have to use pickle. Refs SENTRY-3V47
1 parent 1cc57b6 commit 601779d

File tree

3 files changed

+55
-18
lines changed

3 files changed

+55
-18
lines changed

src/sentry/sentry_apps/tasks/service_hooks.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
22
from time import time
3+
from typing import Any
34

45
from sentry.api.serializers import serialize
56
from sentry.http import safe_urlopen
@@ -46,16 +47,24 @@ def get_payload_v0(event):
4647
),
4748
)
4849
@retry
49-
def process_service_hook(servicehook_id, event, **kwargs):
50+
def process_service_hook(
51+
servicehook_id: int,
52+
event: Any,
53+
payload: str | None = None,
54+
project_id: int | None = None,
55+
**kwargs,
56+
):
5057
try:
5158
servicehook = ServiceHook.objects.get(id=servicehook_id)
5259
except ServiceHook.DoesNotExist:
5360
return
5461

55-
if servicehook.version == 0:
56-
payload = get_payload_v0(event)
57-
else:
58-
raise NotImplementedError
62+
project_id = project_id or event.project_id
63+
if not payload:
64+
if servicehook.version == 0:
65+
payload = json.dumps(get_payload_v0(event))
66+
else:
67+
raise NotImplementedError
5968

6069
from sentry import tsdb
6170

@@ -65,10 +74,8 @@ def process_service_hook(servicehook_id, event, **kwargs):
6574
"Content-Type": "application/json",
6675
"X-ServiceHook-Timestamp": str(int(time())),
6776
"X-ServiceHook-GUID": servicehook.guid,
68-
"X-ServiceHook-Signature": servicehook.build_signature(json.dumps(payload)),
77+
"X-ServiceHook-Signature": servicehook.build_signature(payload),
6978
}
7079

71-
safe_urlopen(
72-
url=servicehook.url, data=json.dumps(payload), headers=headers, timeout=5, verify_ssl=False
73-
)
74-
logger.info("service_hook.success", extra={"project_id": event.project_id})
80+
safe_urlopen(url=servicehook.url, data=payload, headers=headers, timeout=5, verify_ssl=False)
81+
logger.info("service_hook.success", extra={"project_id": project_id})

src/sentry/tasks/post_process.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class PostProcessJob(TypedDict, total=False):
7272
has_escalated: bool
7373

7474

75-
def _get_service_hooks(project_id):
75+
def _get_service_hooks(project_id: int) -> list[tuple[int, list[str]]]:
7676
from sentry.sentry_apps.models.servicehook import ServiceHook
7777

7878
cache_key = f"servicehooks:1:{project_id}"
@@ -1180,7 +1180,7 @@ def process_service_hooks(job: PostProcessJob) -> None:
11801180
if job["is_reprocessed"]:
11811181
return
11821182

1183-
from sentry.sentry_apps.tasks.service_hooks import process_service_hook
1183+
from sentry.sentry_apps.tasks.service_hooks import get_payload_v0, process_service_hook
11841184

11851185
event, has_alert = job["event"], job["has_alert"]
11861186

@@ -1189,10 +1189,17 @@ def process_service_hooks(job: PostProcessJob) -> None:
11891189
if has_alert:
11901190
allowed_events.add("event.alert")
11911191

1192-
if allowed_events:
1193-
for servicehook_id, events in _get_service_hooks(project_id=event.project_id):
1194-
if any(e in allowed_events for e in events):
1195-
process_service_hook.delay(servicehook_id=servicehook_id, event=event)
1192+
# TODO: when we have multiple service hook versions, this will need to change.
1193+
payload = json.dumps(get_payload_v0(event))
1194+
1195+
for servicehook_id, events in _get_service_hooks(project_id=event.project_id):
1196+
if any(e in allowed_events for e in events):
1197+
process_service_hook.delay(
1198+
servicehook_id=servicehook_id,
1199+
project_id=event.project_id,
1200+
event=event,
1201+
payload=payload,
1202+
)
11961203

11971204

11981205
def process_resource_change_bounds(job: PostProcessJob) -> None:

tests/sentry/tasks/test_post_process.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ def __eq__(self, other):
9999
return matching_id
100100

101101

102+
class ServiceHookPayloadMatcher:
103+
def __init__(self, event: Event):
104+
self.event = event
105+
106+
def __eq__(self, other: Any) -> bool:
107+
assert isinstance(other, str), "other should be a string"
108+
assert self.event.group
109+
110+
payload = json.loads(other)
111+
assert payload["event"]["id"] == self.event.event_id
112+
assert payload["group"]["id"] == str(self.event.group.id)
113+
assert "url" in payload["group"]
114+
assert "tags" in payload["event"]
115+
assert "project" in payload
116+
return True
117+
118+
102119
class BasePostProgressGroupMixin(BaseTestCase, metaclass=abc.ABCMeta):
103120
@abc.abstractmethod
104121
def create_event(self, data, project_id, assert_no_errors=True):
@@ -518,7 +535,10 @@ def test_service_hook_fires_on_new_event(self, mock_process_service_hook):
518535
)
519536

520537
mock_process_service_hook.delay.assert_called_once_with(
521-
servicehook_id=hook.id, event=EventMatcher(event)
538+
servicehook_id=hook.id,
539+
project_id=self.project.id,
540+
event=EventMatcher(event),
541+
payload=ServiceHookPayloadMatcher(event),
522542
)
523543

524544
@patch("sentry.sentry_apps.tasks.service_hooks.process_service_hook")
@@ -547,7 +567,10 @@ def test_service_hook_fires_on_alert(self, mock_processor, mock_process_service_
547567
)
548568

549569
mock_process_service_hook.delay.assert_called_once_with(
550-
servicehook_id=hook.id, event=EventMatcher(event)
570+
servicehook_id=hook.id,
571+
project_id=self.project.id,
572+
event=EventMatcher(event),
573+
payload=ServiceHookPayloadMatcher(event),
551574
)
552575

553576
@patch("sentry.sentry_apps.tasks.service_hooks.process_service_hook")

0 commit comments

Comments
 (0)