feat: upgrade Flask 2.3.3 → 3.1.3#7724
Open
wtfiwtz wants to merge 7 commits into
Open
Conversation
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>
Upgrade Flask to 3.1.3, building on the SQLAlchemy 1.4 + Flask-SQLAlchemy 3.0 migration. This PR must merge after the SQLAlchemy upgrade PR. Dependency upgrades: - flask: 2.3.3 → 3.1.3 - blinker: 1.6.2 → 1.9.0 (Flask 3 requires blinker ≥ 1.6.2) - pyjwt: 2.12.0 → 2.13.0 - supervisor: 4.1.0 → 4.3.0 Code changes for Flask 3 compatibility: - security.py: Rewrite csp_allows_embeding for flask-talisman Flask 3 compatibility. Flask-talisman with Flask 3 requires CSP to be passed as a dict instead of a string. New _embedding_content_security_policy() parses the semicolon-separated CONTENT_SECURITY_POLICY setting into directives and overrides frame-ancestors. - cli/rq.py: Soft-import supervisor_checks (no Python 3.13 wheel available). Wrap import in try/except and gate WorkerHealthcheck class definition on SUPERVISOR_CHECKS_AVAILABLE flag. Test changes: - tests/test_authentication.py: Clear JWT public-key cache in tearDown() to prevent cross-test pollution (exposed by Flask 3 app-context scoping changes) Depends on SQLAlchemy 1.4 + Flask-SQLAlchemy 3.0 PR merging first. Co-authored-by: Cursor <cursoragent@cursor.com>
4 tasks
Click commands don't use return values as exit codes. Use sys.exit(1) explicitly when supervisor_checks is unavailable so monitoring scripts can detect healthcheck failures. Addresses cubic-dev-ai P1 issue. 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>
Author
CVE / advisory coverage for PR #7724 (
|
| Package | Version change | CVEs / advisories addressed |
|---|---|---|
| flask | 2.3.3 → 3.1.3 | CVE-2026-27205 (GHSA-68rp-wp8r-4726) — missing Vary: Cookie when session accessed via in/len; CVE-2025-47278 (GHSA-4grg-w6v8-c28g) — incorrect SECRET_KEY_FALLBACKS signing order (patched in 3.1.3) |
| pyjwt | 2.12.0 → 2.13.0 | PyJWT 2.13.0 security release — multiple advisories including: GHSA-xgmm-8j9v-c9wx (JWK-as-HMAC algorithm confusion), GHSA-jq35-7prp-9v3f (PyJWK allow-list bypass), GHSA-993g-76c3-p5m4 / CVE-2026-48522 (non-HTTP(S) URI schemes in PyJWKClient), GHSA-w7vc-732c-9m39 / CVE-2026-48525 (DoS via b64=false detached JWS), GHSA-fhv5-28vv-h8m8 (JWK cache cleared on transient fetch errors) |
| blinker | 1.6.2 → 1.9.0 | Flask 3 dependency refresh; no named CVE mapped |
| supervisor | 4.1.0 → 4.3.0 | Process manager maintenance bump; no named CVE mapped |
Code changes (Flask 3 compatibility; security-relevant context)
| Change | Notes |
|---|---|
redash/security.py — CSP dict for flask-talisman |
Fixes brittle CSP string concatenation for dashboard embed views under Flask 3; reduces risk of misconfigured frame-ancestors silently failing |
redash/cli/rq.py — soft-import supervisor_checks |
Python 3.13 wheel absence; healthcheck uses sys.exit(1) when unavailable (monitoring can detect failure) |
tests/test_authentication.py — JWT cache teardown |
Prevents cross-test JWKS cache pollution |
Out of scope (other split PRs)
| Area | PR |
|---|---|
| urllib3 2.x + champion SSRF | #7721 |
| Frontend / npm CVEs | #7720 |
| Debian OS / Docker build-time CVEs | #7718 |
Supersedes
- #7722 (closed) — original combined Flask 3 + SQLAlchemy PR, split into feat: upgrade SQLAlchemy 1.3→1.4 and Flask-SQLAlchemy 2.5→3.0 #7723 + this PR for reviewability
Contributor
There was a problem hiding this comment.
1 issue found across 26 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="redash/cli/rq.py">
<violation number="1" location="redash/cli/rq.py:21">
P2: Import-time print() in except ImportError emits to stdout for all CLI commands when supervisor_checks is absent</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
|
||
| SUPERVISOR_CHECKS_AVAILABLE = True | ||
| except ImportError as e: | ||
| print(f"Warning: supervisor_checks not available: {e}") |
Contributor
There was a problem hiding this comment.
P2: Import-time print() in except ImportError emits to stdout for all CLI commands when supervisor_checks is absent
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At redash/cli/rq.py, line 21:
<comment>Import-time print() in except ImportError emits to stdout for all CLI commands when supervisor_checks is absent</comment>
<file context>
@@ -7,8 +7,21 @@
+
+ SUPERVISOR_CHECKS_AVAILABLE = True
+except ImportError as e:
+ print(f"Warning: supervisor_checks not available: {e}")
+ check_runner = None
+ base = None
</file context>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Upgrade Flask to 3.1.3, building on the SQLAlchemy 1.4 + Flask-SQLAlchemy 3.0 migration.
This PR is one of two PRs that split the original #7722 into smaller, reviewable pieces.
Dependency upgrades
flask: 2.3.3 → 3.1.3blinker: 1.6.2 → 1.9.0 (Flask 3 requires blinker ≥ 1.6.2)pyjwt: 2.12.0 → 2.13.0supervisor: 4.1.0 → 4.3.0Code changes (Flask 3 compatibility)
redash/security.py— CSP dict rewrite for flask-talismanFlask-talisman with Flask 3 requires CSP to be passed as a dict instead of a string. The
csp_allows_embedingdecorator now:CONTENT_SECURITY_POLICYsetting into directivesframe-ancestorsto*to allow embeddingThis avoids brittle text replacement that depended on exact
frame-ancestors 'none'substring formatting.redash/cli/rq.py— Soft-import supervisor_checkssupervisor_checkshas no Python 3.13 wheel available. The import is now wrapped intry/exceptandWorkerHealthcheckclass definition is gated onSUPERVISOR_CHECKS_AVAILABLEflag. Thehealthcheckcommand prints an error and returns exit code 1 when the library is unavailable.Test changes
tests/test_authentication.py— JWT cache teardownClear JWT public-key cache in
tearDown()to prevent cross-test pollution. This issue was exposed by Flask 3 app-context scoping changes where key cache persisted between tests.Test plan
poetry install --only main,devmake test— expect ~900+ pytest passesNotes
Related PRs
Made with Cursor