Skip to content

Wxo persistence#12011

Open
jordanrfrazier wants to merge 9 commits intomainfrom
wxo-persistence
Open

Wxo persistence#12011
jordanrfrazier wants to merge 9 commits intomainfrom
wxo-persistence

Conversation

@jordanrfrazier
Copy link
Collaborator

@jordanrfrazier jordanrfrazier commented Mar 3, 2026

Summary by CodeRabbit

  • New Features

    • Added deployment management system with support for creating, retrieving, updating, and deleting deployments
    • Introduced deployment provider account management with encrypted API key storage
    • Implemented pagination and filtering for deployment queries
    • Added comprehensive input validation and error handling for deployment operations
  • Tests

    • Added test coverage for deployment CRUD operations and model validation
    • Added test coverage for provider account CRUD operations and encryption handling
    • Added utility function tests for UUID parsing and string validation

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR introduces a complete deployment management system with deployment provider accounts, featuring SQLModel-based data models, database migrations, comprehensive CRUD operations with API key encryption, validation utilities, and extensive test coverage for the new entities and their interactions.

Changes

Cohort / File(s) Summary
Database Migrations
src/backend/base/langflow/alembic/versions/2a5defa5ddc0_add_deployment_table.py, src/backend/base/langflow/alembic/versions/8106300be7aa_add_deployment_provider_account_table.py
Adds two migration scripts creating deployment and deployment_provider_account tables with foreign keys, indices, and unique constraints. Both include idempotency checks to prevent re-creation.
Deployment Model & CRUD
src/backend/base/langflow/services/database/models/deployment/__init__.py, src/backend/base/langflow/services/database/models/deployment/model.py, src/backend/base/langflow/services/database/models/deployment/crud.py
Defines Deployment SQLModel with create/read schemas, table constraints, and validators. Implements async CRUD operations (create, retrieve, list, count, delete) with input validation, error handling, and user-scoped operations.
Deployment Provider Account Model & CRUD
src/backend/base/langflow/services/database/models/deployment_provider_account/__init__.py, src/backend/base/langflow/services/database/models/deployment_provider_account/model.py, src/backend/base/langflow/services/database/models/deployment_provider_account/crud.py
Defines DeploymentProviderAccount SQLModel with create, read, and update schemas. CRUD implementation includes API key encryption/decryption integration, field validators, and comprehensive error handling for IntegrityError and encryption failures.
Model Relationship Updates
src/backend/base/langflow/services/database/models/__init__.py, src/backend/base/langflow/services/database/models/folder/model.py, src/backend/base/langflow/services/database/models/folder/pagination_model.py, src/backend/base/langflow/services/database/models/user/model.py
Adds deployment relationships to Folder and User models with cascade delete semantics. Updates package exports and pagination type hints to include new models.
Database Utilities
src/backend/base/langflow/services/database/utils.py
Introduces validation helpers (validate_non_empty_string, validate_non_empty_string_optional) and parse_uuid utility for flexible UUID handling with contextual error messages.
Test Suites
src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py, src/backend/base/langflow/tests/services/database/models/deployment/test_model.py, src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_crud.py, src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_model.py, src/backend/base/langflow/tests/services/database/models/test_parse_uuid.py
Comprehensive test coverage for CRUD operations, model validation, schema fields, encryption handling, error scenarios, and UUID parsing with mocked database and auth utilities.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title "Wxo persistence" is vague and does not clearly convey what the changeset implements. The raw summary reveals extensive database schema additions for deployment and provider account models with CRUD operations, but the title fails to describe these changes. Replace with a descriptive title like "Add deployment and provider account database models" or "Implement deployment persistence models and CRUD operations" to accurately reflect the substantial backend changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Excessive Mock Usage Warning ⚠️ Warning CRUD tests mock core model classes and AsyncSession entirely, testing mock call sequences rather than real code behavior, obscuring actual functionality and creating false confidence. Refactor CRUD tests to instantiate real model instances, use real or testable AsyncSession via SQLAlchemy fixtures, and only mock external dependencies like auth_utils.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Test Coverage For New Implementations ✅ Passed The PR includes comprehensive test coverage for all new implementations with 86 test functions across 5 test files covering CRUD operations, model validation, and utility functions.
Test Quality And Coverage ✅ Passed Test suite demonstrates comprehensive coverage with proper async patterns, error validation, input testing, and DB operation verification across all CRUD functions.
Test File Naming And Structure ✅ Passed All test files follow correct backend testing patterns with proper pytest structure, descriptive names, logical organization, comprehensive coverage of positive/negative scenarios and edge cases, and proper async/await handling.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wxo-persistence

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 and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Migration Validation Passed

All migrations follow the Expand-Contract pattern correctly.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 23%
22.87% (7981/34889) 15.45% (4224/27334) 15.6% (1147/7348)

Unit Test Results

Tests Skipped Failures Errors Time
2611 0 💤 0 ❌ 0 🔥 42.123s ⏱️

@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 36.07595% with 202 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.31%. Comparing base (2fc6ca8) to head (651e3e9).

Files with missing lines Patch % Lines
...atabase/models/deployment_provider_account/crud.py 0.00% 90 Missing ⚠️
...ngflow/services/database/models/deployment/crud.py 0.00% 76 Missing ⚠️
...c/backend/base/langflow/services/database/utils.py 15.62% 27 Missing ⚠️
...tabase/models/deployment_provider_account/model.py 90.32% 6 Missing ⚠️
...gflow/services/database/models/deployment/model.py 94.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #12011      +/-   ##
==========================================
- Coverage   37.31%   37.31%   -0.01%     
==========================================
  Files        1592     1596       +4     
  Lines       78280    78594     +314     
  Branches    11824    11824              
==========================================
+ Hits        29212    29328     +116     
- Misses      47448    47646     +198     
  Partials     1620     1620              
Flag Coverage Δ
backend 57.03% <36.07%> (-0.30%) ⬇️
frontend 20.49% <ø> (ø)
lfx 42.29% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../langflow/services/database/models/folder/model.py 100.00% <100.00%> (ø)
...ervices/database/models/folder/pagination_model.py 100.00% <100.00%> (ø)
...se/langflow/services/database/models/user/model.py 100.00% <100.00%> (ø)
...gflow/services/database/models/deployment/model.py 94.00% <94.00%> (ø)
...tabase/models/deployment_provider_account/model.py 90.32% <90.32%> (ø)
...c/backend/base/langflow/services/database/utils.py 43.01% <15.62%> (-14.37%) ⬇️
...ngflow/services/database/models/deployment/crud.py 0.00% <0.00%> (ø)
...atabase/models/deployment_provider_account/crud.py 0.00% <0.00%> (ø)

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jordanrfrazier jordanrfrazier marked this pull request as ready for review March 3, 2026 21:44
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (3)
src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_crud.py (1)

22-43: Consider adding a small DB-backed test layer alongside these unit mocks.

Most assertions are mock-interaction based, so SQL/ORM integration regressions can still slip through.

As per coding guidelines: "Warn when mocks are used instead of testing real behavior and interactions, and suggest using real objects or test doubles when mocks become excessive."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_crud.py`
around lines 22 - 43, The tests rely solely on mocks (_make_db and
_make_provider_account) which can miss ORM/integration regressions; add a small
DB-backed test layer by creating an AsyncSession test fixture (e.g., in-memory
SQLite or the project's test database) and a helper that persists a real
DeploymentProviderAccount model instance instead of returning a MagicMock from
_make_provider_account, and use that session in at least one CRUD test to assert
real DB behavior; update or add a helper to produce a real AsyncSession
(replacing _make_db or adding a new fixture) and ensure the test cleans up
transactions after each run.
src/backend/base/langflow/alembic/versions/2a5defa5ddc0_add_deployment_table.py (1)

62-75: Consider adding a composite index for the paginated listing query.

Current single-column indexes may degrade for large per-user/provider datasets when filtering by (user_id, deployment_provider_account_id) and ordering by (created_at, id).

📈 Suggested migration diff
@@
     with op.batch_alter_table("deployment", schema=None) as batch_op:
+        batch_op.create_index(
+            batch_op.f("ix_deployment_user_provider_created_id"),
+            ["user_id", "deployment_provider_account_id", "created_at", "id"],
+            unique=False,
+        )
         batch_op.create_index(batch_op.f("ix_deployment_name"), ["name"], unique=False)
@@
     with op.batch_alter_table("deployment", schema=None) as batch_op:
+        batch_op.drop_index(batch_op.f("ix_deployment_user_provider_created_id"))
         batch_op.drop_constraint(RESOURCE_KEY_UNIQUE_CONSTRAINT, type_="unique")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/backend/base/langflow/alembic/versions/2a5defa5ddc0_add_deployment_table.py`
around lines 62 - 75, Add a composite index to speed paginated listing queries:
inside the op.batch_alter_table("deployment", schema=None) block (the same place
where batch_op.create_index and create_unique_constraint are called), add a
non-unique composite index on ["user_id", "deployment_provider_account_id",
"created_at", "id"] (use batch_op.f(...) to name it, e.g.,
ix_deployment_user_provider_created_id) so queries filtering by user_id and
deployment_provider_account_id and ordering by created_at,id are covered; keep
the existing unique constraints NAME_UNIQUE_CONSTRAINT and
RESOURCE_KEY_UNIQUE_CONSTRAINT unchanged.
src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py (1)

31-31: Remove 20 redundant @pytest.mark.asyncio decorators throughout this module.

With asyncio_mode = "auto" enabled in pyproject.toml, async tests are automatically detected and these decorators add unnecessary noise.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py`
at line 31, The test module contains 20 redundant uses of the
pytest.mark.asyncio decorator (e.g., decorators applied to async test functions
in
src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py);
since asyncio_mode = "auto" is enabled, remove the unnecessary
`@pytest.mark.asyncio` decorators from the async test functions (leave the async
def test_* functions intact) so tests rely on automatic detection rather than
the explicit decorator.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/backend/base/langflow/services/database/models/deployment_provider_account/crud.py`:
- Around line 98-103: The create path currently sets provider_tenant_id to
provider_tenant_id.strip() which preserves empty string; change the creation
logic that builds the DeploymentProviderAccount (where provider_tenant_id is
assigned) to normalize blank values to None (e.g., if provider_tenant_id is not
None after strip and != "" else None) so it matches the update logic's
normalization; update the assignment that currently reads
provider_tenant_id=provider_tenant_id.strip() if provider_tenant_id is not None
else None to return None for blank strings.
- Around line 110-113: The IntegrityError handlers currently pass the raw
exception object to logger.aerror (logger.aerror("IntegrityError creating
provider account: %s", exc)), which can leak SQL and sensitive parameters;
update each handler (the except IntegrityError as exc blocks that call
logger.aerror and compute err_detail) to not log exc directly—instead log a
generic, non-sensitive message and include only the sanitized err_detail string
(or a redacted/safe error token) along with context such as the operation
("creating provider account") and ensure db.rollback() remains; replace all uses
of logger.aerror(..., exc) in these IntegrityError handlers (the blocks that set
err_detail) with logger.aerror(..., err_detail) or a redacted constant.

In `@src/backend/base/langflow/services/database/models/deployment/crud.py`:
- Around line 89-106: In list_deployments_page validate the pagination params
before building the query: check the offset and limit parameters (used in
list_deployments_page signature) and guard against negative offset and
non-positive limit (e.g., raise a ValueError or return an empty list) so the DB
call using AsyncSession and the select(Deployment)...offset(offset).limit(limit)
chain never receives invalid values; put the checks at the top of
list_deployments_page to fail fast and document the behavior.

In `@src/backend/base/langflow/services/database/models/folder/model.py`:
- Around line 9-13: Move the Flow symbol out of the runtime import and into the
TYPE_CHECKING block: keep FlowRead imported at top-level from
langflow.services.database.models.flow.model, remove Flow from that runtime
import, and add "from langflow.services.database.models.flow.model import Flow"
inside the existing TYPE_CHECKING block (alongside Deployment). Update any type
annotations if needed to use Flow directly (no stringization required if
TYPE_CHECKING is present).

In `@src/backend/base/langflow/services/database/utils.py`:
- Around line 100-117: The parse_uuid function currently lets non-str/non-UUID
values pass through; update parse_uuid to explicitly handle UUID instances and
raise a TypeError for any unsupported runtime types: if isinstance(value, UUID)
return it, if isinstance(value, str) keep the existing logic, otherwise raise a
TypeError that includes the field_name and the actual type (e.g., f"{field_name}
must be a UUID or string, got {type(value).__name__}"), so callers get a clear,
immediate error instead of downstream failures.

In
`@src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_crud.py`:
- Around line 379-381: Update the failing multiline docstrings so they include a
blank line between the one-line summary and the rest of the description to
satisfy Ruff D205: locate the docstring that begins "When provider_tenant_id is
not passed at all (_UNSET), the existing ..." in test_crud.py (and the other
similar docstring around the second occurrence) and insert an empty line after
the summary line so the docstring has a single-line summary, a blank line, then
the detailed description.

---

Nitpick comments:
In
`@src/backend/base/langflow/alembic/versions/2a5defa5ddc0_add_deployment_table.py`:
- Around line 62-75: Add a composite index to speed paginated listing queries:
inside the op.batch_alter_table("deployment", schema=None) block (the same place
where batch_op.create_index and create_unique_constraint are called), add a
non-unique composite index on ["user_id", "deployment_provider_account_id",
"created_at", "id"] (use batch_op.f(...) to name it, e.g.,
ix_deployment_user_provider_created_id) so queries filtering by user_id and
deployment_provider_account_id and ordering by created_at,id are covered; keep
the existing unique constraints NAME_UNIQUE_CONSTRAINT and
RESOURCE_KEY_UNIQUE_CONSTRAINT unchanged.

In
`@src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_crud.py`:
- Around line 22-43: The tests rely solely on mocks (_make_db and
_make_provider_account) which can miss ORM/integration regressions; add a small
DB-backed test layer by creating an AsyncSession test fixture (e.g., in-memory
SQLite or the project's test database) and a helper that persists a real
DeploymentProviderAccount model instance instead of returning a MagicMock from
_make_provider_account, and use that session in at least one CRUD test to assert
real DB behavior; update or add a helper to produce a real AsyncSession
(replacing _make_db or adding a new fixture) and ensure the test cleans up
transactions after each run.

In
`@src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py`:
- Line 31: The test module contains 20 redundant uses of the pytest.mark.asyncio
decorator (e.g., decorators applied to async test functions in
src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py);
since asyncio_mode = "auto" is enabled, remove the unnecessary
`@pytest.mark.asyncio` decorators from the async test functions (leave the async
def test_* functions intact) so tests rely on automatic detection rather than
the explicit decorator.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2fc6ca8 and 3293607.

📒 Files selected for processing (20)
  • src/backend/base/langflow/alembic/versions/2a5defa5ddc0_add_deployment_table.py
  • src/backend/base/langflow/alembic/versions/8106300be7aa_add_deployment_provider_account_table.py
  • src/backend/base/langflow/services/database/models/__init__.py
  • src/backend/base/langflow/services/database/models/deployment/__init__.py
  • src/backend/base/langflow/services/database/models/deployment/crud.py
  • src/backend/base/langflow/services/database/models/deployment/model.py
  • src/backend/base/langflow/services/database/models/deployment_provider_account/__init__.py
  • src/backend/base/langflow/services/database/models/deployment_provider_account/crud.py
  • src/backend/base/langflow/services/database/models/deployment_provider_account/model.py
  • src/backend/base/langflow/services/database/models/folder/model.py
  • src/backend/base/langflow/services/database/models/folder/pagination_model.py
  • src/backend/base/langflow/services/database/models/user/model.py
  • src/backend/base/langflow/services/database/utils.py
  • src/backend/base/langflow/tests/services/database/models/deployment/__init__.py
  • src/backend/base/langflow/tests/services/database/models/deployment/test_crud.py
  • src/backend/base/langflow/tests/services/database/models/deployment/test_model.py
  • src/backend/base/langflow/tests/services/database/models/deployment_provider_account/__init__.py
  • src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_crud.py
  • src/backend/base/langflow/tests/services/database/models/deployment_provider_account/test_model.py
  • src/backend/base/langflow/tests/services/database/models/test_parse_uuid.py

jordanrfrazier and others added 8 commits March 4, 2026 01:30
  Critical Issues Fixed

  1. is_encrypted removed — update_provider_account now always encrypts, matching create_provider_account. No more heuristic that could store plaintext keys.
  2. Proper Alembic revision IDs — a1b2c3d4e5f6 → 8106300be7aa, c3d4e5f6a7b8 → 2a5defa5ddc0 (randomly generated).
  3. Folder ↔ Deployment relationship — Added folder on Deployment and deployments on Folder with "all, delete, delete-orphan" cascade.

  Important Issues Fixed

  4. Schema layering — Added DeploymentRead, DeploymentProviderAccountCreate, DeploymentProviderAccountRead (no api_key!), DeploymentProviderAccountUpdate.
  5. Cascade config — DeploymentProviderAccount.deployments now uses "all, delete, delete-orphan" (matching Folder.flows pattern).
  6. UUID validation standardized — Both CRUDs now use _parse_uuid() that raises ValueError with context (field name + value). No moent return None/return 0 on bad input.
  7. encrypt_api_key error context — Wrapped in try/except raising RuntimeError with clear message about encryption config.

  Suggestions Fixed

  8. Field validators — name, resource_key (Deployment) and provider_key, provider_url (DeploymentProviderAccount) now validated non-empty with .strip().
  9. (provider_account_id, resource_key) uniqueness — Added to both model and migration.
  10. account_id NULL documented — Comment explaining unique constraint behavior with NULLs.
  11. or 0 removed from count_deployment_rows.
…persistence

  - Extract shared validators (validate_non_empty_string) to database/utils.py
  - Add DeploymentCreate schema with field validators
  - Add _UNSET sentinel to update_provider_account for nullable field handling
  - Extract _encrypt_api_key helper with broadened exception handling
  - Add empty-string validation in CRUD create functions before DB round-trip
  - Escalate IntegrityError and None rowcount logging to aerror with rollback
  - Fix parse_uuid to chain exceptions with `from exc`
  - Fix folder relationship nullability (Folder, not Folder | None)
  - Add tests for 5 previously untested CRUD functions and new validation paths
- Rename count_deployments to count_deployments_by_provider
- Add update_deployment CRUD function and DeploymentUpdate schema
- Extract _strip_or_raise helper to deduplicate input validation
- Clarify IntegrityError messages to describe conflicts generically
- Document cascade semantics on User model relationships, double-
  validation rationale in CRUD, and model_fields_set usage on
  DeploymentProviderAccountUpdate
- Add missing get_deployment and update_deployment tests
…atibility

- Validate pagination bounds (offset >= 0, limit > 0) in list_deployments_page
- Normalize blank provider_tenant_id to None on create, matching update behavior
- Centralize normalization via normalize_string_or_none utility and model validators
- Remove raw exception objects from IntegrityError log messages to avoid leaking SQL
- Reject unsupported types in parse_uuid with a clear TypeError
- Remove `from __future__ import annotations` from table models to fix SQLAlchemy
  relationship mapper errors at runtime
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.

2 participants