Skip to content

Conversation

@cathteng
Copy link
Member

@cathteng cathteng commented Nov 6, 2025

Since we now have DetectorGroup rows being written, we could refactor the WorkflowGroupHistory API to use DetectorGroup, rather than use a column on WorkflowFireHistory (which shouldn't need to know which detector triggered the workflow to be fired).

Don't use DetectorWorkflow to check for active detector - workflow connections because a detector might have been disconnected from the workflow since the workflow was triggered for that issue.

@cathteng cathteng requested a review from a team as a code owner November 6, 2025 21:38
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 6, 2025
detector_subquery = DetectorGroup.objects.filter(
group=OuterRef("group"),
detector_id__in=DetectorWorkflow.objects.filter(workflow=workflow).values("detector_id"),
).values("detector_id")[:1]

This comment was marked as outdated.

@cathteng
Copy link
Member Author

cathteng commented Nov 7, 2025

Having second thoughts on whether we should do this because the detector in the notification is so tightly coupled with the metric detector code (charts, open periods, etc)

@cathteng cathteng marked this pull request as draft November 7, 2025 19:03
@cathteng cathteng marked this pull request as ready for review November 7, 2025 23:06
@cathteng
Copy link
Member Author

cathteng commented Nov 7, 2025

OK we back. We will decouple detector from action.trigger here #103000

Comment on lines 131 to 137
group=OuterRef("group"),
detector_id__in=DetectorWorkflow.objects.filter(workflow=workflow).values("detector_id"),
).values("detector_id")[:1]

qs = (
filtered_history.select_related("group", "detector")
filtered_history.select_related("group")
.values("group")
.annotate(count=Count("group"))
.annotate(event_id=Subquery(group_max_dates.values("event_id")))
.annotate(last_triggered=Max("date_added"))
.annotate(detector_id=Subquery(group_max_dates.values("detector_id")))
.annotate(detector_id=Subquery(detector_subquery))
Copy link

Choose a reason for hiding this comment

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

Bug: The DetectorGroup subquery fails for old groups lacking DetectorGroup entries, causing incorrect detector_id reporting.
Severity: CRITICAL | Confidence: 0.98

🔍 Detailed Analysis

The detector_subquery in workflow_group_history_serializer.py assumes that a DetectorGroup entry exists for every WorkflowFireHistory record with a detector_id. This assumption is false for groups created before the introduction of DetectorGroup entries. When a workflow fires for such an 'old' group, a WorkflowFireHistory record is created with a detector_id, but no corresponding DetectorGroup entry exists. Consequently, the subquery returns None, leading the API to incorrectly report detector=None for these groups, despite a detector having fired the workflow.

💡 Suggested Fix

Modify the detector_subquery in workflow_group_history_serializer.py to correctly retrieve the detector_id for groups that lack a DetectorGroup entry, potentially by falling back to WorkflowFireHistory.detector_id or ensuring DetectorGroup entries are backfilled.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
src/sentry/workflow_engine/endpoints/serializers/workflow_group_history_serializer.py#L130-L141

Potential issue: The `detector_subquery` in `workflow_group_history_serializer.py`
assumes that a `DetectorGroup` entry exists for every `WorkflowFireHistory` record with
a `detector_id`. This assumption is false for groups created before the introduction of
`DetectorGroup` entries. When a workflow fires for such an 'old' group, a
`WorkflowFireHistory` record is created with a `detector_id`, but no corresponding
`DetectorGroup` entry exists. Consequently, the subquery returns `None`, leading the API
to incorrectly report `detector=None` for these groups, despite a detector having fired
the workflow.

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

@cathteng cathteng force-pushed the cathy/aci/decouple-detector-workflowfirehistory branch from 2ad1498 to de1b9cc Compare November 12, 2025 18:07
Comment on lines +125 to +129
detector_subquery = DetectorGroup.objects.filter(
group=OuterRef("group"),
).values(
"detector_id"
)[:1]

Choose a reason for hiding this comment

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

High severity vulnerability may affect your project—review required:
Line 125 lists a dependency (django) with a known High severity vulnerability.

ℹ️ Why this matters

Affected versions of Django are vulnerable to Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'). SQL injection in Django's ORM column aliases: when using QuerySet.annotate(), QuerySet.alias(), QuerySet.aggregate(), or QuerySet.extra() with dictionary expansion (**kwargs), the dictionary keys are used unescaped as SQL column aliases. On MySQL and MariaDB backends, an attacker who can influence those keys (for example, by passing a crafted dict of annotations) can inject arbitrary SQL into the generated query.

References: GHSA, CVE

To resolve this comment:
Check if you are using Django with MySQL or MariaDB.

  • If you're affected, upgrade this dependency to at least version 5.2.7 at uv.lock.
  • If you're not affected, comment /fp we don't use this [condition]
💬 Ignore this finding

To ignore this, reply with:

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

You can view more details on this finding in the Semgrep AppSec Platform here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants