Skip to content

feat(ACI): Make ProjectRuleDetailsEndpoint GET method backwards compatible#109387

Merged
ceorourke merged 7 commits intomasterfrom
ceorourke/ISWF-2031
Mar 2, 2026
Merged

feat(ACI): Make ProjectRuleDetailsEndpoint GET method backwards compatible#109387
ceorourke merged 7 commits intomasterfrom
ceorourke/ISWF-2031

Conversation

@ceorourke
Copy link
Copy Markdown
Member

Make ProjectRuleDetailsEndpoint GET method backwards compatible mostly via a new convert_args method that first attempts to looks up the AlertRuleWorkflow for dual written rules, and if that fails we assume it is a singly written workflow and look it up directly on the Workflow model.

@ceorourke ceorourke requested review from a team as code owners February 25, 2026 22:12
@linear
Copy link
Copy Markdown

linear bot commented Feb 25, 2026

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Feb 25, 2026
return args, kwargs


class WorkflowEngineRuleEndpoint(RuleEndpoint):
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I had to make a new class here because RuleEndpoint encompasses ProjectRuleGroupHistoryIndexEndpoint and ProjectRuleStatsIndexEndpoint as well which we don't want to affect.

except AlertRuleWorkflow.DoesNotExist:
# XXX: this means the workflow was single written and has no ARW or related Rule object
try:
workflow_id = get_object_id_from_fake_id(int(rule_id))
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We assume we are being passed a "fake id" here because for singly written rules we will not have a rule id, so the rule index endpoint will generate a fake id for a workflow so it can be looked up here.

except Workflow.DoesNotExist:
raise ResourceDoesNotExist

return args, kwargs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Legacy rules return 404 when feature flag enabled

High Severity

When organizations:workflow-engine-rule-serializers is enabled, WorkflowEngineRuleEndpoint.convert_args returns 404 for legacy rules. If AlertRuleWorkflow lookup fails, it only tries Workflow via get_object_id_from_fake_id. When that also fails (e.g. for a legacy Rule id), it raises ResourceDoesNotExist instead of falling back to the legacy Rule lookup, breaking backwards compatibility.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's intentional

prepare_component_fields=True,
project_slug=project.slug,
)
serialized_rule = serialize(rule, request.user, rule_serializer)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

GET uses wrong serializer when legacy Rule returned

High Severity

The GET handler selects the serializer using only the feature flag. If convert_args is fixed to fall back to legacy Rule when both AlertRuleWorkflow and Workflow lookups fail, the handler would pass a Rule to WorkflowEngineRuleSerializer, which expects Workflow objects. That would cause get_attrs and serialize to fail (e.g. KeyError on attrs["rule_id"]). Serializer selection should branch on isinstance(rule, Workflow) so legacy rules use RuleSerializer.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

@ceorourke ceorourke Feb 25, 2026

Choose a reason for hiding this comment

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

If convert_args is fixed to fall back to legacy Rule when both AlertRuleWorkflow and Workflow lookups fail

idk why you'd think that would happen

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

result[workflow]["rule_id"] = workflow_rule_ids[workflow.id]
result[workflow]["rule_id"] = workflow_rule_ids.get(
workflow.id, get_fake_id_from_object_id(workflow.id)
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IndexError when workflow has no WorkflowDataConditionGroup

Medium Severity

WorkflowEngineRuleSerializer.get_attrs assumes every workflow has at least one WorkflowDataConditionGroup and does workflow.prefetched_wdcgs[0] without checking. A workflow with no WorkflowDataConditionGroup raises IndexError during serialization.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it'll always have one

@ceorourke ceorourke requested a review from a team February 25, 2026 23:03
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

might be polite to type annotate the others too with an assertion of the isinstance calling out "this shouldn't be enabled; not fully supported" or whatever.

)

result[workflow]["action_match"] = (
workflow.when_condition_group.logic_type if workflow.when_condition_group else None
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The code accesses prefetched_wdcgs[0] without checking if the list is empty, which can cause an IndexError when serializing a workflow with no action filters.
Severity: HIGH

Suggested Fix

Add a conditional check to ensure workflow.prefetched_wdcgs is not empty before accessing its first element, for example: if workflow.prefetched_wdcgs:. Alternatively, consider making action_filters a required field in the validator to prevent this data state from occurring.

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/api/serializers/models/rule.py#L486

Potential issue: In `WorkflowEngineRuleSerializer.get_attrs()`, the code directly
accesses the first element of `workflow.prefetched_wdcgs`. However, the
`WorkflowValidator` allows for the creation of workflows without `action_filters`, which
results in `prefetched_wdcgs` being an empty list. When the serializer attempts to
process such a workflow, accessing `workflow.prefetched_wdcgs[0]` will raise an
`IndexError`, causing the API endpoint for retrieving the rule to return a 500 error.

@ceorourke ceorourke merged commit 1d22531 into master Mar 2, 2026
55 checks passed
@ceorourke ceorourke deleted the ceorourke/ISWF-2031 branch March 2, 2026 21:13
@github-actions github-actions bot locked and limited conversation to collaborators Mar 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

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