Skip to content

Commit 4b6977c

Browse files
feat(detectors): Handle config field updates in base detector validator (#103184)
Previously, the base detector validator update() method did not handle config field updates at all. This adds proper support for updating the config field with JSON schema validation using enforce_config_schema(). Adds tests to verify: - Valid config updates are applied correctly - Invalid config updates that violate the schema are rejected with appropriate error messages
1 parent aca9df4 commit 4b6977c

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

src/sentry/workflow_engine/endpoints/validators/base/detector.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ def update(self, instance: Detector, validated_data: dict[str, Any]):
133133
group_validator = BaseDataConditionGroupValidator()
134134
group_validator.update(instance.workflow_condition_group, condition_group)
135135

136+
# Handle config field update
137+
if "config" in validated_data:
138+
instance.config = validated_data.get("config", instance.config)
139+
try:
140+
enforce_config_schema(instance)
141+
except JSONSchemaValidationError as error:
142+
raise serializers.ValidationError({"config": [str(error)]})
143+
136144
instance.save()
137145

138146
create_audit_entry(

tests/sentry/workflow_engine/endpoints/test_organization_detector_details.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,59 @@ def test_update_workflows_no_changes(self) -> None:
709709
== 0
710710
)
711711

712+
def test_update_config_valid(self) -> None:
713+
"""Test updating detector config with valid schema data"""
714+
# Initial config
715+
initial_config = {"detection_type": "static", "comparison_delta": None}
716+
self.detector.config = initial_config
717+
self.detector.save()
718+
719+
# Update with valid new config
720+
updated_config = {"detection_type": "dynamic", "comparison_delta": 3600}
721+
data = {
722+
"config": updated_config,
723+
}
724+
725+
with self.tasks():
726+
response = self.get_success_response(
727+
self.organization.slug,
728+
self.detector.id,
729+
**data,
730+
status_code=200,
731+
)
732+
733+
self.detector.refresh_from_db()
734+
# Verify config was updated in database (snake_case)
735+
assert self.detector.config == updated_config
736+
# API returns camelCase
737+
assert response.data["config"] == {
738+
"detectionType": "dynamic",
739+
"comparisonDelta": 3600,
740+
}
741+
742+
def test_update_config_invalid_schema(self) -> None:
743+
"""Test updating detector config with invalid schema data fails validation"""
744+
# Config missing required field 'detection_type'
745+
invalid_config = {"comparison_delta": 3600}
746+
data = {
747+
"config": invalid_config,
748+
}
749+
750+
with self.tasks():
751+
response = self.get_error_response(
752+
self.organization.slug,
753+
self.detector.id,
754+
**data,
755+
status_code=400,
756+
)
757+
758+
assert "config" in response.data
759+
assert "detection_type" in str(response.data["config"])
760+
761+
# Verify config was not updated
762+
self.detector.refresh_from_db()
763+
assert self.detector.config != invalid_config
764+
712765

713766
@region_silo_test
714767
class OrganizationDetectorDetailsDeleteTest(OrganizationDetectorDetailsBaseTest):

0 commit comments

Comments
 (0)