Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -32,6 +32,8 @@ def human_desc(
return "Send a notification to " + target.get_email()
elif target_type == AlertRuleTriggerAction.TargetType.TEAM.value:
return "Send an email to members of #" + target.slug
else:
return "Send a notification to [removed]"
Copy link
Contributor

Choose a reason for hiding this comment

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

Bug: EMAIL Action Missing in Dictionary

The added else clause for EMAIL action type creates a logic gap. When action_target is truthy but target_type is neither USER nor TEAM, the function doesn't return anything from the EMAIL block and falls through to the final else statement (line 48), which tries to access action_type_to_string[action_type]. However, EMAIL is not in the action_type_to_string dictionary (lines 22-27), causing a KeyError. The else clause should be moved inside the if action_target: block to properly handle cases where action_target exists but target_type doesn't match expected values.

Fix in Cursor Fix in Web

elif action_type == AlertRuleTriggerAction.Type.OPSGENIE.value:
if priority:
return f"Send a {priority} Opsgenie notification to {target_display}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@ def target(action: Action) -> OrganizationMember | Team | str | None:
target_type = action.config.get("target_type")
if target_type == ActionTarget.USER.value:
dcga = DataConditionGroupAction.objects.get(action=action)
return OrganizationMember.objects.get(
user_id=int(target_identifier),
organization=dcga.condition_group.organization,
)
try:
return OrganizationMember.objects.get(
user_id=int(target_identifier),
organization=dcga.condition_group.organization,
)
except OrganizationMember.DoesNotExist:
# user is no longer a member of the organization
pass
Comment on lines +49 to +56
Copy link

Choose a reason for hiding this comment

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

Bug: human_desc() receives None for target from MetricAlertRegistryHandler.target() and attempts to access attributes, causing an AttributeError.
Severity: CRITICAL | Confidence: 0.98

🔍 Detailed Analysis

When MetricAlertRegistryHandler.target() returns None due to a caught OrganizationMember.DoesNotExist exception, the WorkflowEngineActionSerializer passes this None value to human_desc(). If the action is an email type (AlertRuleTriggerAction.Type.EMAIL.value) targeting a user or team (AlertRuleTriggerAction.TargetType.USER.value or AlertRuleTriggerAction.TargetType.TEAM.value), human_desc() attempts to call target.get_email() or target.slug on the None object. This occurs when an email action is configured for a user or team member who is subsequently deleted, leading to an AttributeError.

💡 Suggested Fix

Modify human_desc() to check if target is None before attempting to access target.get_email() or target.slug when action_type is email and target_type is user or team.

🤖 Prompt for AI Agent
Fix this bug. In
src/sentry/notifications/notification_action/group_type_notification_registry/handlers/metric_alert_registry_handler.py
at lines 49-56: When `MetricAlertRegistryHandler.target()` returns `None` due to a
caught `OrganizationMember.DoesNotExist` exception, the `WorkflowEngineActionSerializer`
passes this `None` value to `human_desc()`. If the action is an email type
(`AlertRuleTriggerAction.Type.EMAIL.value`) targeting a user or team
(`AlertRuleTriggerAction.TargetType.USER.value` or
`AlertRuleTriggerAction.TargetType.TEAM.value`), `human_desc()` attempts to call
`target.get_email()` or `target.slug` on the `None` object. This occurs when an email
action is configured for a user or team member who is subsequently deleted, leading to
an `AttributeError`.

Did we get this right? 👍 / 👎 to inform future reviews.

elif target_type == ActionTarget.TEAM.value:
try:
return Team.objects.get(id=int(target_identifier))
Expand Down
Loading