Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[FIX] Bump DRF version to 3.17 to address vulnerability and drop DRF auto UniqueTogetherValidator on upsert/catch serializers#2104

Merged
chandrasekharan-zipstack merged 3 commits into
mainZipstack/unstract:mainfrom
fix/drf-validators-bucket1Zipstack/unstract:fix/drf-validators-bucket1Copy head branch name to clipboard
Jun 24, 2026
Merged

[FIX] Bump DRF version to 3.17 to address vulnerability and drop DRF auto UniqueTogetherValidator on upsert/catch serializers#2104
chandrasekharan-zipstack merged 3 commits into
mainZipstack/unstract:mainfrom
fix/drf-validators-bucket1Zipstack/unstract:fix/drf-validators-bucket1Copy head branch name to clipboard

Conversation

@chandrasekharan-zipstack

Copy link
Copy Markdown
Contributor

What

DRF 3.15+ auto-generates a UniqueTogetherValidator from each model's Meta.constraints UniqueConstraint. For serializers whose view already owns uniqueness — either an upsert (update_or_create) or an IntegrityError → DuplicateData catch — that validator fires at is_valid() and returns a non_field_errors: must make a unique set 400 on a legitimate re-save, before the view runs. This short-circuits the view's duplicate handling (was a rc.343 staging regression once DRF 3.15.2 shipped).

This sets Meta.validators = [] on those 8 serializers so the view/DB own uniqueness:

  • adapter_processor_v2.AdapterInstanceSerializer (catch → DuplicateAdapterNameError)
  • api_v2.APIDeploymentSerializer (IntegrityErrorMixin)
  • connector_v2.ConnectorInstanceSerializer (catch → DuplicateData)
  • pipeline_v2.PipelineSerializer (IntegrityErrorMixin + view catch)
  • workflow_v2.WorkflowSerializer (IntegrityErrorMixin)
  • prompt_studio_v2.ToolStudioPromptSerializer (create catches; also fixes Mode-B on PUT/PATCH update)
  • prompt_profile_manager_v2.ProfileManagerSerializer (create catches; fixes update)
  • notification_v2.NotificationSerializer (custom validate_name already enforces uniqueness)

Why now / safety

  • No-op on the currently-pinned DRF 3.14 (it only auto-validates legacy unique_together, which these models don't use). So this changes nothing at runtime today.
  • Required prep for the DRF re-bump to 3.17.x (stacked PR follows). Landing it first keeps these endpoints safe the moment 3.15+ is reintroduced.
  • Uniqueness is still enforced — by each view's existing upsert / IntegrityError catch and the DB constraint itself.

Part of the staged DRF uniqueness fix. Cloud-side counterparts (pluggable_apps) go in a separate unstract-cloud PR.

🤖 Generated with Claude Code

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
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Multiple DRF serializer Meta classes now explicitly disable auto-generated validators, and the project dependency files were updated to bump djangorestframework and remove one dependency group.

Changes

Disable DRF auto-validators across serializers

Layer / File(s) Summary
Disable serializer validators
backend/adapter_processor_v2/serializers.py, backend/api_v2/serializers.py, backend/connector_v2/serializers.py, backend/notification_v2/serializers.py, backend/pipeline_v2/serializers/crud.py, backend/prompt_studio/prompt_profile_manager_v2/serializers.py, backend/prompt_studio/prompt_studio_v2/serializers.py, backend/workflow_manager/workflow_v2/serializers.py
BaseAdapterSerializer, APIDeploymentSerializer, ConnectorInstanceSerializer, NotificationSerializer, PipelineSerializer, ProfileManagerSerializer, ToolStudioPromptSerializer, and WorkflowSerializer now set validators = [] in Meta.

Dependency file updates

Layer / File(s) Summary
Update dependency configuration
backend/pyproject.toml, pyproject.toml
djangorestframework is bumped from 3.14.0 to 3.17.1, and the hook-check-django-migrations dependency group is removed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains what and why, but it omits several required template sections like How, breakage impact, testing, and checklist. Add the missing template sections, especially How, breakage analysis, database migrations, env config, testing notes, and the checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the DRF version bump and the serializer validator changes that are the main focus of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/drf-validators-bucket1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR bumps DRF from 3.14.0 to 3.17.1 to address a security vulnerability, and pre-emptively adds Meta.validators = [] to eight serializers to prevent DRF 3.15+'s auto-generated UniqueTogetherValidator (derived from Meta.constraints UniqueConstraint) from firing before the view can run its own upsert/IntegrityError uniqueness logic.

  • Serializer changes: validators = [] is added to AdapterInstanceSerializer, APIDeploymentSerializer, ConnectorInstanceSerializer, PipelineSerializer, WorkflowSerializer, ToolStudioPromptSerializer, ProfileManagerSerializer, and NotificationSerializer. All are well-commented and correctly targeted — the views already own uniqueness via IntegrityErrorMixin.save(), update_or_create, or application-level validate_name.
  • Dependency changes: DRF bumped from 3.14.0 → 3.17.1 in backend/pyproject.toml and both lock files updated accordingly; the now-obsolete hook-check-django-migrations optional group is removed from the root pyproject.toml (no remaining references in the repo).
  • Runtime impact today: The serializer changes are no-ops on DRF 3.14 (which only auto-generates validators from legacy unique_together, not UniqueConstraint); they become load-bearing only after the DRF 3.17 bump takes effect.

Confidence Score: 5/5

Safe to merge. The serializer changes are no-ops against the currently pinned DRF 3.14 and become load-bearing only once DRF 3.17 is active, which is exactly the intended sequencing.

All eight validators = [] additions are correctly scoped: seven are backed by IntegrityErrorMixin or view-level upsert logic, and one (NotificationSerializer) relies on an application-level validate_name method that was already the sole uniqueness guard before this PR. The DRF version bump is clean — pytz is dropped from DRF's transitive dependencies but is still resolved via other backend packages. The hook-check-django-migrations optional group removal leaves no dangling references in the repository.

None require blocking attention. backend/notification_v2/serializers.py is worth a second look for a follow-up to add IntegrityErrorMixin or view-level IntegrityError handling, but that gap predates this PR.

Important Files Changed

Filename Overview
backend/adapter_processor_v2/serializers.py Adds validators = [] to BaseAdapterSerializer.Meta, which all child serializers inherit. Correct — the view handles duplicates via IntegrityError → DuplicateAdapterNameError.
backend/api_v2/serializers.py Adds validators = [] to APIDeploymentSerializer.Meta. IntegrityErrorMixin maps DB constraint violations to friendly field errors; disabling the DRF auto-validator is correct.
backend/notification_v2/serializers.py Adds validators = [] to NotificationSerializer.Meta. Uniqueness is enforced solely by the application-level validate_name field validator; unlike the other seven serializers, there is no IntegrityErrorMixin catch, so a concurrent duplicate write bypasses validate_name and reaches the DB unguarded.
backend/workflow_manager/workflow_v2/serializers.py Adds validators = [] to WorkflowSerializer.Meta. IntegrityErrorMixin maps unique_workflow_name constraint to a friendly message; correct.
backend/pyproject.toml Bumps djangorestframework from 3.14.0 to 3.17.1. The version pin is exact, consistent with the rest of the dependency list.
pyproject.toml Removes the hook-check-django-migrations optional group and its pinned DRF 3.14 + drf-yasg 1.21.7 transitive set. No remaining references to this group in the repository.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Client request\n(POST / PUT / PATCH)"] --> B["DRF serializer.is_valid()"]
    B --> C{"validators = [] ?"}
    C -- "DRF 3.15+ without fix\n(auto UniqueTogetherValidator)" --> D["UniqueTogetherValidator fires\nHTTP 400 on re-save\nbefore view runs"]
    C -- "This PR: validators = []" --> E["Field-level validate_*\n+ validate() run"]
    E --> F{"Serializer has\nIntegrityErrorMixin?"}
    F -- "Yes\n(API, Workflow, Pipeline,\nConnector, Adapter,\nPrompt, ProfileMgr)" --> G["save() wrapped\nIntegrityError → friendly 400"]
    F -- "No\n(Notification)" --> H["validate_name checks\nuniqueness at app level"]
    H --> I{"Concurrent write\nraces past validate_name?"}
    I -- "No (normal path)" --> J["DB write succeeds ✓"]
    I -- "Yes (race)" --> K["DB UniqueConstraint fires\nUnhandled IntegrityError → 500"]
    G --> J
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Client request\n(POST / PUT / PATCH)"] --> B["DRF serializer.is_valid()"]
    B --> C{"validators = [] ?"}
    C -- "DRF 3.15+ without fix\n(auto UniqueTogetherValidator)" --> D["UniqueTogetherValidator fires\nHTTP 400 on re-save\nbefore view runs"]
    C -- "This PR: validators = []" --> E["Field-level validate_*\n+ validate() run"]
    E --> F{"Serializer has\nIntegrityErrorMixin?"}
    F -- "Yes\n(API, Workflow, Pipeline,\nConnector, Adapter,\nPrompt, ProfileMgr)" --> G["save() wrapped\nIntegrityError → friendly 400"]
    F -- "No\n(Notification)" --> H["validate_name checks\nuniqueness at app level"]
    H --> I{"Concurrent write\nraces past validate_name?"}
    I -- "No (normal path)" --> J["DB write succeeds ✓"]
    I -- "Yes (race)" --> K["DB UniqueConstraint fires\nUnhandled IntegrityError → 500"]
    G --> J
Loading

Reviews (3): Last reviewed commit: "Merge branch 'main' into fix/drf-validat..." | Re-trigger Greptile

* [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>
@chandrasekharan-zipstack chandrasekharan-zipstack changed the title [FIX] Drop DRF auto UniqueTogetherValidator on upsert/catch serializers [FIX] Bump DRF version to 3.17 to address vulnerability and drop DRF auto UniqueTogetherValidator on upsert/catch serializers Jun 24, 2026
Comment thread pyproject.toml
@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
unit-connectors unit 64 12 0 3 16.8
unit-core unit 0 0 4 0 1.2
unit-platform-service unit 9 0 1 0 1.4
unit-prompt-service unit 15 0 0 0 19.9
unit-rig unit 53 0 0 0 3.3
unit-runner unit 11 0 0 0 3.0
unit-sdk1 unit 390 0 0 0 20.7
unit-tool-registry unit 0 0 1 0 1.3
unit-workers unit 0 0 0 0 17.6
TOTAL 542 12 6 3 85.2

Critical paths

⚠️ Critical paths not yet covered

  • auth-login — User can log in and obtain a session cookie. (entry: POST /api/v1/auth/login; declared coverage: no groups declared)
  • adapter-register-llm — Register and validate an LLM adapter. (entry: POST /api/v1/adapter/; declared coverage: no groups declared)
  • workflow-create-execute — Create a workflow, configure source+destination, execute, poll, fetch result. (entry: POST /api/v1/workflow/{id}/execute/; declared coverage: e2e-workflow)
  • api-deployment-run — Deploy a workflow as an API, POST a document, receive structured JSON. (entry: POST /deployment/api/{org}/{name}/; declared coverage: e2e-api-deployment)
  • prompt-studio-fetch-response — Prompt Studio: create project, add prompt, run single-pass, get response. (entry: POST /api/v1/prompt-studio/prompt-studio-tool/{id}/fetch_response/; declared coverage: e2e-prompt-studio)
  • pipeline-etl-execute — Run an ETL pipeline from source connector to destination. (entry: POST /api/v1/pipeline/{id}/execute/; declared coverage: no groups declared)
  • usage-token-tracking — Per-execution token usage is recorded and retrievable. (entry: GET /api/v1/usage/get_token_usage/; declared coverage: no groups declared)
  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (entry: internal: backend → rabbitmq → workers/file_processing; declared coverage: no groups declared)
  • callback-result-delivery — Async results are posted back via the callback worker. (entry: internal: workers/callback → backend /internal endpoints; declared coverage: no groups declared)
✅ Covered critical paths
  • tool-sandbox-exec — covered by unit-runner

@chandrasekharan-zipstack chandrasekharan-zipstack merged commit 6b3cfab into main Jun 24, 2026
10 checks passed
@chandrasekharan-zipstack chandrasekharan-zipstack deleted the fix/drf-validators-bucket1 branch June 24, 2026 10:03
@sonarqubecloud

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.