Skip to content

Commit 6b3cfab

Browse files
[FIX] Bump DRF version to 3.17 to address vulnerability and drop DRF auto UniqueTogetherValidator on upsert/catch serializers (#2104)
* [FIX] Drop DRF auto UniqueTogetherValidator on upsert/catch serializers DRF 3.15+ auto-generates a UniqueTogetherValidator from each model's Meta.constraints UniqueConstraint. For serializers whose view already owns uniqueness (upsert via update_or_create, or IntegrityError->Duplicate catch), that validator fires at is_valid() and 400s on a legitimate re-save before the view can run, short-circuiting the view's duplicate handling. Set Meta.validators = [] on those serializers so the view/DB own uniqueness. No-op on the currently-pinned DRF 3.14 (which only auto-validates legacy unique_together); required once DRF is re-bumped to 3.17.x. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu * [FIX] Re-bump djangorestframework 3.14.0 → 3.17.1 (#2105) * [FIX] Re-bump djangorestframework 3.14.0 -> 3.17.1 Re-attempts the DRF upgrade reverted in #2098. 3.17.1 is chosen because it: - carries PR encode/django-rest-framework#9766 (3.17.0), so the auto UniqueTogetherValidator honors a UniqueConstraint's violation_error_message for friendly duplicate messages (used by cloud-side create-only serializers), - includes the CVE-2024-21520 (XSS) fix first shipped in 3.15.2. Safe to layer on top of the Meta.validators=[] changes in the parent commit, which neutralize the 3.15+ auto-validator for every upsert / IntegrityError-catch serializer. Django 4.2.30 + Python 3.12 satisfy DRF 3.17's floors. MUST be build + test + staging validated before merge (this bump caused the rc.343 regression). drf-yasg 1.21.7 / drf-standardized-errors compatibility with DRF 3.17 to be verified in CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu * [FIX] Remove unused hook-check-django-migrations dep group Group had no consumer (migration check runs in backend env); its pinned drf-yasg==1.21.7 paired with DRF 3.17.1 in the root lock was an incompatible skew. Drop the group and relock. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6c690af commit 6b3cfab

12 files changed

Lines changed: 29 additions & 277 deletions

File tree

backend/adapter_processor_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class BaseAdapterSerializer(AuditSerializer):
3434
class Meta:
3535
model = AdapterInstance
3636
fields = "__all__"
37+
# View owns uniqueness (IntegrityError->DuplicateData); drop the DRF
38+
# auto-validator that 400s on re-save before the view can handle it.
39+
validators = []
3740
extra_kwargs = {
3841
"shared_users": {"read_only": True},
3942
"shared_to_org": {"read_only": True},

backend/api_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class APIDeploymentSerializer(IntegrityErrorMixin, AuditSerializer):
4444
class Meta:
4545
model = APIDeployment
4646
fields = "__all__"
47+
# IntegrityErrorMixin owns uniqueness; drop the DRF auto-validator
48+
# that 400s on re-save before the mixin can map a friendly message.
49+
validators = []
4750
extra_kwargs = {
4851
"shared_users": {"read_only": True},
4952
"shared_to_org": {"read_only": True},

backend/connector_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class ConnectorInstanceSerializer(AuditSerializer):
3434
class Meta:
3535
model = ConnectorInstance
3636
fields = "__all__"
37+
# View owns uniqueness (IntegrityError->DuplicateData); drop the DRF
38+
# auto-validator that 400s on re-save before the view can handle it.
39+
validators = []
3740
extra_kwargs = {
3841
"connector_name": {"required": False},
3942
# connector_mode is derived from the catalog in to_representation.

backend/notification_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class NotificationSerializer(serializers.ModelSerializer):
2525
class Meta:
2626
model = Notification
2727
fields = "__all__"
28+
# Custom validate_name already enforces uniqueness with friendly per-field
29+
# errors; drop the redundant DRF auto-validator (fragile on partial PATCH).
30+
validators = []
2831

2932
def validate(self, data):
3033
"""Validate the data for the NotificationSerializer."""

backend/pipeline_v2/serializers/crud.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class PipelineSerializer(IntegrityErrorMixin, AuditSerializer):
3838
class Meta:
3939
model = Pipeline
4040
fields = "__all__"
41+
# IntegrityErrorMixin / view own uniqueness; drop the DRF auto-validator
42+
# that 400s on re-save before the view can map a friendly message.
43+
validators = []
4144
extra_kwargs = {
4245
"shared_users": {"read_only": True},
4346
"shared_to_org": {"read_only": True},

backend/prompt_studio/prompt_profile_manager_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class ProfileManagerSerializer(AuditSerializer):
1414
class Meta:
1515
model = ProfileManager
1616
fields = "__all__"
17+
# View owns uniqueness (IntegrityError->DuplicateData on create); drop
18+
# the DRF auto-validator that 400s on re-save / PUT before the view runs.
19+
validators = []
1720

1821
def to_representation(self, instance): # type: ignore
1922
rep: dict[str, str] = super().to_representation(instance)

backend/prompt_studio/prompt_studio_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class ToolStudioPromptSerializer(AuditSerializer):
2626
class Meta:
2727
model = ToolStudioPrompt
2828
fields = "__all__"
29+
# View owns uniqueness (IntegrityError->DuplicateData on create); drop
30+
# the DRF auto-validator that 400s on re-save / PUT before the view runs.
31+
validators = []
2932

3033

3134
class ToolStudioIndexSerializer(serializers.Serializer):

backend/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ dependencies = [
1919
"cron-descriptor==1.4.0", # For cron string description
2020
"cryptography>=48.0.1",
2121
"django==4.2.30",
22-
"djangorestframework==3.14.0",
22+
"djangorestframework==3.17.1",
2323
"django-cors-headers==4.3.1",
2424
# Pinning django-celery-beat to avoid build issues
2525
"django-celery-beat==2.5.0",

backend/uv.lock

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/workflow_manager/workflow_v2/serializers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class WorkflowSerializer(IntegrityErrorMixin, AuditSerializer):
4141
class Meta:
4242
model = Workflow
4343
fields = "__all__"
44+
# IntegrityErrorMixin owns uniqueness; drop the DRF auto-validator
45+
# that 400s on re-save before the mixin can map a friendly message.
46+
validators = []
4447
extra_kwargs = {
4548
WorkflowKey.LLM_RESPONSE: {
4649
"required": False,

0 commit comments

Comments
 (0)