feat: upgrade Flask 2.3.3 → 3.1.3#7724
Conversation
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
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}") |
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>
|
@zachliu @madmuffin1 probably this one next - not the 'rolled up' PR |
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>
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>
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
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="pyproject.toml">
<violation number="1" location="pyproject.toml:63">
P2: The environment now resolves SQLAlchemy 2.x, not the intended SQLAlchemy 1.4 migration target. Adding an upper bound keeps installs on the compatible/tested 1.4 line and avoids accidental 2.x behavior changes.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| "semver==2.8.1", | ||
| "sentry-sdk==1.45.1", | ||
| "sqlalchemy==1.3.24", | ||
| "sqlalchemy>=1.4.18", |
There was a problem hiding this comment.
P2: The environment now resolves SQLAlchemy 2.x, not the intended SQLAlchemy 1.4 migration target. Adding an upper bound keeps installs on the compatible/tested 1.4 line and avoids accidental 2.x behavior changes.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pyproject.toml, line 63:
<comment>The environment now resolves SQLAlchemy 2.x, not the intended SQLAlchemy 1.4 migration target. Adding an upper bound keeps installs on the compatible/tested 1.4 line and avoids accidental 2.x behavior changes.</comment>
<file context>
@@ -60,7 +60,7 @@ dependencies = [
"semver==2.8.1",
"sentry-sdk==1.45.1",
- "sqlalchemy==1.3.24",
+ "sqlalchemy>=1.4.18",
"sqlalchemy-searchable==1.2.0",
"sqlalchemy-utils==0.38.3",
</file context>
| "sqlalchemy>=1.4.18", | |
| "sqlalchemy>=1.4.18,<2.0", |
The cleanup job's IN subquery included all joined columns from QueryResult.unused(), causing Postgres to reject every run with "subquery has too many columns" and preventing cache pruning. Co-authored-by: Cursor <cursoragent@cursor.com>
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