Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
RESPONSE_UNAUTHORIZED,
)
from sentry.apidocs.parameters import GlobalParams
from sentry.incidents.endpoints.serializers.utils import get_object_id_from_fake_id
from sentry.models.organization import Organization
from sentry.workflow_engine.endpoints.serializers.alertrule_detector_serializer import (
AlertRuleDetectorSerializer,
Expand All @@ -24,6 +25,7 @@
AlertRuleDetectorValidator,
)
from sentry.workflow_engine.models.alertrule_detector import AlertRuleDetector
from sentry.workflow_engine.models.detector import Detector


@region_silo_endpoint
Expand Down Expand Up @@ -69,7 +71,26 @@ def get(self, request: Request, organization: Organization) -> Response:
queryset = queryset.filter(rule_id=rule_id)

alert_rule_detector = queryset.first()
if not alert_rule_detector:
raise ResourceDoesNotExist

return Response(serialize(alert_rule_detector, request.user))
if alert_rule_detector:
return Response(serialize(alert_rule_detector, request.user))

# Fallback: if alert_rule_id was provided but no AlertRuleDetector was found,
# try looking up Detector directly using calculated detector_id
if alert_rule_id:
try:
calculated_detector_id = get_object_id_from_fake_id(int(alert_rule_id))
detector = Detector.objects.get(id=calculated_detector_id)

if detector:
return Response(
{
"detectorId": str(detector.id),
"alertRuleId": str(alert_rule_id),
"ruleId": None,
}
Comment on lines 82 to 93

This comment was marked as outdated.

)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Fallback ignores detector_id and rule_id filters

The fallback logic activates whenever alert_rule_id is provided, even when combined with detector_id or rule_id filters. It then returns a detector based solely on the calculated detector ID from alert_rule_id, completely ignoring the other filter parameters. This creates inconsistent results where a user requests specific detector_id or rule_id values but receives data for a different detector derived from the alert_rule_id. The fallback should either validate that filters are consistent or only activate when alert_rule_id is the sole filter.

Fix in Cursor Fix in Web

except (ValueError, Detector.DoesNotExist):
pass

raise ResourceDoesNotExist
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from sentry.api.serializers import serialize
from sentry.incidents.endpoints.serializers.utils import get_fake_id_from_object_id
from sentry.testutils.cases import APITestCase
from sentry.testutils.silo import region_silo_test

Expand Down Expand Up @@ -89,3 +90,33 @@ def test_organization_isolation(self) -> None:

def test_get_without_any_filter(self) -> None:
self.get_error_response(self.organization.slug, status_code=400)

def test_fallback_with_fake_alert_rule_id(self) -> None:
"""
Test that when an alert rule doesn't exist, the endpoint falls back to looking up
the Detector by subtracting 10^9 from the alert_rule_id.
"""
# Create a detector with no AlertRuleDetector mapping
detector = self.create_detector(project=self.project)

# Calculate the fake alert_rule_id
fake_alert_rule_id = get_fake_id_from_object_id(detector.id)

# Query using the fake alert_rule_id
response = self.get_success_response(
self.organization.slug, alert_rule_id=str(fake_alert_rule_id)
)

# Should return a fake AlertRuleDetector response
assert response.data == {
"detectorId": str(detector.id),
"alertRuleId": str(fake_alert_rule_id),
"ruleId": None,
}

def test_fallback_with_nonexistent_detector(self) -> None:
# Use a fake alert_rule_id that won't map to any real detector
nonexistent_fake_id = get_fake_id_from_object_id(999999)
self.get_error_response(
self.organization.slug, alert_rule_id=str(nonexistent_fake_id), status_code=404
)
Loading