Skip to content

feat: upgrade SQLAlchemy 1.3→1.4 and Flask-SQLAlchemy 2.5→3.0#7723

Open
wtfiwtz wants to merge 6 commits into
getredash:masterfrom
orchestrated-io:fix/sqlalchemy14-flask-sqlalchemy3
Open

feat: upgrade SQLAlchemy 1.3→1.4 and Flask-SQLAlchemy 2.5→3.0#7723
wtfiwtz wants to merge 6 commits into
getredash:masterfrom
orchestrated-io:fix/sqlalchemy14-flask-sqlalchemy3

Conversation

@wtfiwtz
Copy link
Copy Markdown

@wtfiwtz wtfiwtz commented Jun 1, 2026

Summary

Upgrade SQLAlchemy to 1.4.53 and Flask-SQLAlchemy to 3.0.5 while keeping Flask at 2.3.3. This allows the ORM migration to land independently of the Flask 3 upgrade (which will follow in a separate PR once this merges).

This PR is one of two PRs that split the original #7722 into smaller, reviewable pieces.

Dependency upgrades

Core ORM stack:

  • sqlalchemy: 1.3.24 → 1.4.53
  • flask-sqlalchemy: 2.5.1 → 3.0.5 (requires Flask ≥ 2.2.5, SQLAlchemy ≥ 1.4.18)
  • flask-migrate: 2.5.2 → 4.0.7 (requires Flask-SQLAlchemy 3.x)
  • nzalchemy: ^11.0.2 → ^11.1.2 (SQLAlchemy 1.4 compat)

Test tooling:

  • pytest: 7.4.0 → 9.0.3
  • coverage: 7.2.7 → 7.14.0
  • pytest-cov: 4.1.0 → 6.0.0
  • jwcrypto: 1.5.6 → 1.5.7

Code changes (SQLAlchemy 1.4 / Flask-SQLAlchemy 3.0 API compatibility)

  • redash/models/base.py: Replace BaseQuery (removed in FSA 3.0) with flask_sqlalchemy.query.Query; add SearchBaseQuery._entities shim for sqlalchemy-searchable 1.2 which reads the removed _entities attribute
  • redash/handlers/base.py: FSA 3.0 changed paginate(page, page_size)paginate(page=…, per_page=…, error_out=False)
  • redash/metrics/database.py: SQLAlchemy 1.4 removed .froms; use .get_final_froms()
  • redash/models/__init__.py: Replace .options(load_only("id")) with .with_entities(Model.id) in .in_() subqueries
  • redash/utils/query_order.py: _ColumnEntity, _MapperEntity, _mapper_registry are internal APIs removed in 1.4; replace with column_descriptions and _mapper_registries
  • redash/models/changes.py: Guard ChangeTrackingMixin.__setattr__ against detached/deleted SQLAlchemy 1.4 identity-map state
  • redash/tasks/queries/execution.py: SQLAlchemy 1.4 identity-map is stricter; skip session.close() in TESTING mode to prevent detached-object errors
  • redash/authentication/__init__.py: Use session.flush() instead of commit() in TESTING mode for SQLAlchemy 1.4 session scoping
  • redash/utils/configuration.py: Compact JSON separators for test_cli.py assertions

Test infrastructure

  • tests/__init__.py: db.get_engine(app).dispose()db.engine.dispose() (FSA 3.0 removed the get_engine(app) signature)
  • tests/destinations/__init__.py: Add empty __init__.py for pytest collection
  • tests/tasks/test_worker.py: Add super().tearDown() calls
  • tests/test_cli.py: Update compact-JSON expectations
  • pytest.ini: Add pythonpath = ., logging config, addopts

Test plan

  1. Depends on security: upgrade Python dependencies to Flask 2.3.3 and Werkzeug 3.1.6 #7719 (Werkzeug 3 + authlib 1.7) merging first
  2. poetry install --only main,dev
  3. make test — expect ~900+ pytest passes
  4. Smoke-test login, query execution, dashboard views

Notes

  • This PR intentionally does not upgrade Flask (stays at 2.3.3). Flask 2→3 will follow in a separate PR once this lands.
  • Flask-SQLAlchemy 3.0.5 supports Flask 2.2.5+, so this migration is independent of Flask 3.
  • Split from original feat: upgrade to Flask 3.1.3 and SQLAlchemy 1.4.53 #7722 to reduce review complexity.

Related PRs

Made with Cursor

wtfiwtz and others added 3 commits June 1, 2026 15:30
Upgrade security-critical Python dependencies while staying on Flask 2.x.
Werkzeug 3.x is compatible with Flask 2.3.x and provides important security
fixes without requiring a Flask 3 migration.

Core dependency upgrades:
- authlib: 0.15.5 → 1.7.2 (fixes CVEs in OAuth/OIDC flows)
- cryptography: 43.0.1 → 48.0.0
- flask: 2.3.2 → 2.3.3
- flask-login: 0.6.0 → 0.6.3
- flask-wtf: 1.1.1 → 1.3.0
- itsdangerous: 2.1.2 → 2.2.0
- jinja2: 3.1.5 → 3.1.6
- pyjwt: 2.4.0 → 2.12.0
- pyopenssl: 24.2.1 → 26.2.0
- python-dotenv: 0.19.2 → 1.2.2
- requests: 2.32.3 → 2.33.0
- sqlparse: 0.5.0 → 0.5.4
- urllib3: 1.26.19 → 1.26.20
- werkzeug: 2.3.8 → 3.1.6

Added transitive dependency pins: pyasn1, mako, pynacl

Data source dependency upgrades:
- boto3/botocore: 1.28.8 → 1.43.7
- snowflake-connector-python: 3.12.3 → 4.5.0
- New additions: azure-core, grpcio, h11, httpcore, marshmallow

Dev dependency upgrades:
- pre-commit: 3.3.3 → 4.3.0
- Add filelock, pygments, virtualenv

Code changes for authlib 1.x and Werkzeug 3.x compatibility:
- Remove api_key_load_user_from_request from user_loader (belongs in request_loader)
- Add TESTING-mode reset_request_g_cache hook to prevent g leakage across test requests
- Pass explicit client_id/client_secret to oauth.register() (authlib 1.x API)
- Replace flask.globals._app_ctx_stack with current_app (Werkzeug 3 removal)

Co-authored-by: Cursor <cursoragent@cursor.com>
Upgrade SQLAlchemy to 1.4.53 and Flask-SQLAlchemy to 3.0.5 while keeping
Flask at 2.3.3. This allows the ORM migration to land independently of the
Flask 3 upgrade.

Dependency upgrades:
- sqlalchemy: 1.3.24 → 1.4.53
- flask-sqlalchemy: 2.5.1 → 3.0.5 (requires Flask ≥ 2.2.5, SQLAlchemy ≥ 1.4.18)
- flask-migrate: 2.5.2 → 4.0.7 (requires Flask-SQLAlchemy 3.x)
- nzalchemy: ^11.0.2 → ^11.1.2 (SQLAlchemy 1.4 compatibility)
- pytest: 7.4.0 → 9.0.3
- coverage: 7.2.7 → 7.14.0
- pytest-cov: 4.1.0 → 6.0.0
- jwcrypto: 1.5.6 → 1.5.7

Code changes for SQLAlchemy 1.4 / Flask-SQLAlchemy 3.0 API compatibility:
- models/base.py: Replace BaseQuery with flask_sqlalchemy.query.Query; add
  SearchBaseQuery._entities shim for sqlalchemy-searchable 1.2
- handlers/base.py: Update paginate() for FSA 3.0 signature change
- metrics/database.py: Replace .froms with .get_final_froms()
- models/__init__.py: Replace .options(load_only("id")) with .with_entities()
- utils/query_order.py: Replace removed internal APIs (_ColumnEntity,
  _mapper_registry) with column_descriptions and _mapper_registries
- models/changes.py: Guard ChangeTrackingMixin against detached/deleted state
- tasks/queries/execution.py: Skip session.close() in TESTING mode
- authentication/__init__.py: Use flush() instead of commit() in TESTING mode
- utils/configuration.py: Compact JSON separators for test assertions

Test infrastructure:
- tests/__init__.py: Replace db.get_engine(app) with db.engine
- tests/destinations/__init__.py: Add package marker for pytest collection
- tests/tasks/test_worker.py: Add super().tearDown() calls
- tests/test_cli.py: Update compact-JSON expectations
- pytest.ini: Add pythonpath, logging config, addopts

Depends on getredash#7719 (Werkzeug 3 + authlib 1.7) merging first.

Co-authored-by: Cursor <cursoragent@cursor.com>
wtfiwtz and others added 3 commits June 1, 2026 18:08
1. P1: Restore get_mapper() ambiguity check - collect all matching mappers
   and raise ValueError if multiple found (regression from original code)

2. P2: Log exceptions in ChangeTrackingMixin instead of silent pass -
   provides observability when attribute access fails during change tracking

Addresses cubic-dev-ai issues on original getredash#7722.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Remove nested app_context in destination test_post that caused
  "Object is already attached to session" under SQLAlchemy 1.4
- Clear JWT public-key cache in TestJWTAuthentication tearDown and
  require both RSA key files before regenerating
- Update database metrics listeners to SQLAlchemy 1.4 event signatures

Co-authored-by: Cursor <cursoragent@cursor.com>
Class-level MonkeyPatch instances in test_script.py were never undone,
leaving a subprocess.check_output mock that broke TestJWTAuthentication
when the full suite ran test_script before test_authentication.

Co-authored-by: Cursor <cursoragent@cursor.com>
@wtfiwtz wtfiwtz marked this pull request as ready for review June 1, 2026 10:42
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 24 files

Re-trigger cubic

@wtfiwtz
Copy link
Copy Markdown
Author

wtfiwtz commented Jun 1, 2026

Disclaimer: This comment was AI-generated to summarize the CVE and advisory coverage for this PR. Please verify against your scanner output and release notes before treating it as authoritative.

CVE / advisory coverage for PR #7723 (fix/sqlalchemy14-flask-sqlalchemy3)

This PR is stacked on #7719 — the branch contains the Python security dependency commits from #7719 plus the SQLAlchemy / Flask-SQLAlchemy migration. If merged to master as-is, it delivers both sets of fixes.


Inherited from #7719 (already in this branch)

See the AI-generated CVE comment on #7719 for the full list. Highlights:

Package Version change CVEs / advisories
werkzeug 2.3.8 → 3.1.6 CVE-2026-27199, CVE-2024-34069, CVE-2024-49766, CVE-2024-49767
jinja2 3.1.5 → 3.1.6 CVE-2025-27516
authlib 0.15.5 → 1.7.2 OAuth/OIDC advisory class (e.g. CVE-2024-37568)
cryptography 43.0.1 → 48.0.0 Multiple OpenSSL-binding advisories
pyjwt 2.4.0 → 2.12.0 CVE-2022-29217 and related algorithm-confusion fixes
urllib3 1.26.19 → 1.26.20 CVE-2025-50181, CVE-2025-50182
flask 2.3.2 → 2.3.3 Flask 2.3 security patch level
Plus: requests, sqlparse, itsdangerous, pyopenssl, boto3/botocore, snowflake-connector-python, etc.

Incremental fixes added by this PR (SQLAlchemy / ORM migration)

Package Version change CVEs / advisories addressed
jwcrypto 1.5.6 → 1.5.7 CVE-2026-39373 (GHSA-fjrm-76x2-c4q4) — JWE ZIP decompression bomb / memory exhaustion; completes mitigation beyond CVE-2024-28102 input-size limit
sqlalchemy 1.3.24 → 1.4.53 No new CVE IDs specific to 1.4.53; moves to the maintained 1.4 line with Python 3.13 fixes and backported hardening (1.4.53 release). Redash already on 1.3.x (past CVE-2019-7164 / GHSA-887w-45rq-vxgf order_by injection).
flask-sqlalchemy 2.5.1 → 3.0.5 Compatibility / maintainability (required for SQLAlchemy 1.4); not a direct CVE remediation
flask-migrate 2.5.2 → 4.0.7 Compatibility with Flask-SQLAlchemy 3.x
nzalchemy ^11.0.2 → ^11.1.2 SQLAlchemy 1.4 compatibility for Netezza data source

Flask remains at 2.3.3 in this PR — Flask 3 security fixes are in #7724.


Code changes (security-relevant context, not CVE IDs)

Change Notes
SQLAlchemy 1.4 / FSA 3.0 API compatibility ORM session identity-map is stricter; fixes prevent detached-object errors and audit-log corruption under 1.4
get_mapper() ambiguity check restored Prevents silent wrong-mapper selection (review bot P1)
ChangeTrackingMixin logging Replaces silent except pass on change tracking failures
Test isolation fixes JWT key cache teardown, destination test session fix, MonkeyPatch.undo() in script runner tests

Out of scope (other split PRs)

Area PR
Flask 3.x security fixes #7724
urllib3 2.x + champion SSRF #7721
Frontend / npm CVEs #7720
Debian OS / Docker build-time CVEs #7718

Known remaining gaps (not in this PR)

Package CVE / advisory Notes
paramiko 3.4.1 CVE-2026-44405 Blocked by sshtunnel compatibility
pysaml2 7.3.1 GMS-2016-67 pyOpenSSL constraint
bootstrap@3.4.1 CVE-2019-8331, CVE-2025-1647 Frontend; CSS-only use

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.

1 participant