You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2023/08/31 11:44:55 UTC

[superset] branch master updated: fix: Bumps Flask Caching to fix RCE vulnerability (#25090)

This is an automated email from the ASF dual-hosted git repository.

michaelsmolina pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 9df1b26654 fix: Bumps Flask Caching to fix RCE vulnerability (#25090)
9df1b26654 is described below

commit 9df1b2665497c5f5e073d0921e19354ae59d01e5
Author: Michael S. Molina <70...@users.noreply.github.com>
AuthorDate: Thu Aug 31 08:44:48 2023 -0300

    fix: Bumps Flask Caching to fix RCE vulnerability (#25090)
---
 CONTRIBUTING.md                                 | 88 ++++++++++++-------------
 docker/pythonpath_dev/superset_config.py        |  2 +-
 docs/docs/installation/async-queries-celery.mdx |  4 +-
 helm/superset/Chart.yaml                        |  2 +-
 helm/superset/README.md                         |  2 +-
 helm/superset/templates/_helpers.tpl            |  2 +-
 requirements/base.txt                           |  6 +-
 setup.cfg                                       |  2 +-
 setup.py                                        |  3 +-
 superset/config.py                              |  2 +-
 superset/extensions/__init__.py                 |  2 +-
 tests/integration_tests/cachekeys/api_tests.py  |  5 ++
 tests/integration_tests/core_tests.py           |  1 +
 13 files changed, 62 insertions(+), 59 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 91f224bc03..94573f2a9e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -578,6 +578,7 @@ npm ci
 ```
 
 Note that Superset uses [Scarf](https://docs.scarf.sh) to capture telemetry/analytics about versions being installed, including the `scarf-js` npm package. As noted elsewhere in this documentation, Scarf gathers aggregated stats for the sake of security/release strategy, and does not capture/retain PII. [You can read here](https://docs.scarf.sh/package-analytics/) about the package, and various means to opt out of it, but one easy way to opt out is to add this setting in `superset-fronte [...]
+
 ```json
 // your-package/package.json
 {
@@ -598,10 +599,13 @@ There are three types of assets you can build:
 3. `npm run build-instrumented`: instrumented application code for collecting code coverage from Cypress tests
 
 If this type of error comes while building assets(i.e using above commands):
+
 ```bash
 Error: You must provide the URL of lib/mappings.wasm by calling SourceMapConsumer.initialize
 ```
+
 Then put this:
+
 ```bash
 export NODE_OPTIONS=--no-experimental-fetch
 ```
@@ -925,28 +929,22 @@ For debugging locally using VSCode, you can configure a launch configuration fil
 
 ```json
 {
-    "version": "0.2.0",
-    "configurations": [
-        {
-            "name": "Python: Flask",
-            "type": "python",
-            "request": "launch",
-            "module": "flask",
-            "env": {
-                "FLASK_APP": "superset",
-                "SUPERSET_ENV": "development"
-            },
-            "args": [
-                "run",
-                "-p 8088",
-                "--with-threads",
-                "--reload",
-                "--debugger"
-            ],
-            "jinja": true,
-            "justMyCode": true
-        }
-    ]
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Python: Flask",
+      "type": "python",
+      "request": "launch",
+      "module": "flask",
+      "env": {
+        "FLASK_APP": "superset",
+        "SUPERSET_ENV": "development"
+      },
+      "args": ["run", "-p 8088", "--with-threads", "--reload", "--debugger"],
+      "jinja": true,
+      "justMyCode": true
+    }
+  ]
 }
 ```
 
@@ -1031,24 +1029,24 @@ You are now ready to attach a debugger to the process. Using VSCode you can conf
 
 ```json
 {
-    "version": "0.2.0",
-    "configurations": [
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Attach to Superset App in Docker Container",
+      "type": "python",
+      "request": "attach",
+      "connect": {
+        "host": "127.0.0.1",
+        "port": 5678
+      },
+      "pathMappings": [
         {
-            "name": "Attach to Superset App in Docker Container",
-            "type": "python",
-            "request": "attach",
-            "connect": {
-                "host": "127.0.0.1",
-                "port": 5678
-            },
-            "pathMappings": [
-                {
-                    "localRoot": "${workspaceFolder}",
-                    "remoteRoot": "/app"
-                }
-            ]
-        },
-    ]
+          "localRoot": "${workspaceFolder}",
+          "remoteRoot": "/app"
+        }
+      ]
+    }
+  ]
 }
 ```
 
@@ -1349,7 +1347,7 @@ To do this, you'll need to:
   but perfect for testing (stores cache in `/tmp`)
 
   ```python
-  from cachelib.file import FileSystemCache
+  from flask_caching.backends.filesystemcache import FileSystemCache
   RESULTS_BACKEND = FileSystemCache('/tmp/sqllab')
   ```
 
@@ -1415,11 +1413,11 @@ Note not all fields are correctly categorized. The fields vary based on visualiz
 
 ### Time
 
-| Field              | Type     | Notes                                 |
-| ------------------ | -------- | ------------------------------------- |
-| `granularity_sqla` | _string_ | The SQLA **Time Column** widget       |
-| `time_grain_sqla`  | _string_ | The SQLA **Time Grain** widget        |
-| `time_range`       | _string_ | The **Time range** widget             |
+| Field              | Type     | Notes                           |
+| ------------------ | -------- | ------------------------------- |
+| `granularity_sqla` | _string_ | The SQLA **Time Column** widget |
+| `time_grain_sqla`  | _string_ | The SQLA **Time Grain** widget  |
+| `time_range`       | _string_ | The **Time range** widget       |
 
 ### GROUP BY
 
diff --git a/docker/pythonpath_dev/superset_config.py b/docker/pythonpath_dev/superset_config.py
index 794f7c910f..005cc600ae 100644
--- a/docker/pythonpath_dev/superset_config.py
+++ b/docker/pythonpath_dev/superset_config.py
@@ -23,8 +23,8 @@
 import logging
 import os
 
-from cachelib.file import FileSystemCache
 from celery.schedules import crontab
+from flask_caching.backends.filesystemcache import FileSystemCache
 
 logger = logging.getLogger()
 
diff --git a/docs/docs/installation/async-queries-celery.mdx b/docs/docs/installation/async-queries-celery.mdx
index f6c0dbcc3d..49f1ce72a8 100644
--- a/docs/docs/installation/async-queries-celery.mdx
+++ b/docs/docs/installation/async-queries-celery.mdx
@@ -66,7 +66,7 @@ celery --app=superset.tasks.celery_app:app beat
 ```
 
 To setup a result backend, you need to pass an instance of a derivative of from
-cachelib.base.BaseCache to the RESULTS_BACKEND configuration key in your superset_config.py. You can
+from flask_caching.backends.base import BaseCache to the RESULTS_BACKEND configuration key in your superset_config.py. You can
 use Memcached, Redis, S3 (https://pypi.python.org/pypi/s3werkzeugcache), memory or the file system
 (in a single server-type setup or for testing), or to write your own caching interface. Your
 `superset_config.py` may look something like:
@@ -79,7 +79,7 @@ S3_CACHE_KEY_PREFIX = 'sql_lab_result'
 RESULTS_BACKEND = S3Cache(S3_CACHE_BUCKET, S3_CACHE_KEY_PREFIX)
 
 # On Redis
-from cachelib.redis import RedisCache
+from flask_caching.backends.rediscache import RedisCache
 RESULTS_BACKEND = RedisCache(
     host='localhost', port=6379, key_prefix='superset_results')
 ```
diff --git a/helm/superset/Chart.yaml b/helm/superset/Chart.yaml
index 7582c560c4..8af3ae4acf 100644
--- a/helm/superset/Chart.yaml
+++ b/helm/superset/Chart.yaml
@@ -29,7 +29,7 @@ maintainers:
   - name: craig-rueda
     email: craig@craigrueda.com
     url: https://github.com/craig-rueda
-version: 0.10.5
+version: 0.10.6
 dependencies:
   - name: postgresql
     version: 12.1.6
diff --git a/helm/superset/README.md b/helm/superset/README.md
index 9ee8b9d12c..724eb43101 100644
--- a/helm/superset/README.md
+++ b/helm/superset/README.md
@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
 
 # superset
 
-![Version: 0.10.5](https://img.shields.io/badge/Version-0.10.5-informational?style=flat-square)
+![Version: 0.10.6](https://img.shields.io/badge/Version-0.10.6-informational?style=flat-square)
 
 Apache Superset is a modern, enterprise-ready business intelligence web application
 
diff --git a/helm/superset/templates/_helpers.tpl b/helm/superset/templates/_helpers.tpl
index f7b23634e1..b450ec3ef0 100644
--- a/helm/superset/templates/_helpers.tpl
+++ b/helm/superset/templates/_helpers.tpl
@@ -63,7 +63,7 @@ Create chart name and version as used by the chart label.
 
 {{- define "superset-config" }}
 import os
-from cachelib.redis import RedisCache
+from flask_caching.backends.rediscache import RedisCache
 
 def env(key, default=None):
     return os.getenv(key, default)
diff --git a/requirements/base.txt b/requirements/base.txt
index f8a7728cbe..4928876a13 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -31,8 +31,8 @@ bottleneck==1.3.7
     # via pandas
 brotli==1.0.9
     # via flask-compress
-cachelib==0.4.1
-    # via apache-superset
+cachelib==0.6.0
+    # via flask-caching
 celery==5.2.2
     # via apache-superset
 certifi==2023.7.22
@@ -100,7 +100,7 @@ flask-appbuilder==4.3.6
     # via apache-superset
 flask-babel==1.0.0
     # via flask-appbuilder
-flask-caching==1.10.1
+flask-caching==1.11.1
     # via apache-superset
 flask-compress==1.13
     # via apache-superset
diff --git a/setup.cfg b/setup.cfg
index 4340cf50c4..0d7c0b655f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -30,7 +30,7 @@ combine_as_imports = true
 include_trailing_comma = true
 line_length = 88
 known_first_party = superset
-known_third_party =alembic,apispec,backoff,cachelib,celery,click,colorama,cron_descriptor,croniter,cryptography,dateutil,deprecation,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_jwt_extended,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,freezegun,geohash,geopy,holidays,humanize,isodate,jinja2,jwt,markdown,markupsafe,marshmallow,msgpack,nh3,numpy,pandas,parameterized,parsedatetime,pgsanity,pkg_resources,polyline,prison,progress, [...]
+known_third_party =alembic,apispec,backoff,celery,click,colorama,cron_descriptor,croniter,cryptography,dateutil,deprecation,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_jwt_extended,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,freezegun,geohash,geopy,holidays,humanize,isodate,jinja2,jwt,markdown,markupsafe,marshmallow,msgpack,nh3,numpy,pandas,parameterized,parsedatetime,pgsanity,pkg_resources,polyline,prison,progress,pyarrow,s [...]
 multi_line_output = 3
 order_by_type = false
 
diff --git a/setup.py b/setup.py
index 75e03fd4b1..26d8ebc2af 100644
--- a/setup.py
+++ b/setup.py
@@ -75,7 +75,6 @@ setup(
     },
     install_requires=[
         "backoff>=1.8.0",
-        "cachelib>=0.4.1,<0.5",
         "celery>=5.2.2, <6.0.0",
         "click>=8.0.3",
         "click-option-group",
@@ -86,7 +85,7 @@ setup(
         "deprecation>=2.1.0, <2.2.0",
         "flask>=2.2.5, <3.0.0",
         "flask-appbuilder>=4.3.6, <5.0.0",
-        "flask-caching>=1.10.1, <2.0",
+        "flask-caching>=1.11.1, <2.0",
         "flask-compress>=1.13, <2.0",
         "flask-talisman>=1.0.0, <2.0",
         "flask-login>=0.6.0, < 1.0",
diff --git a/superset/config.py b/superset/config.py
index 3f27deffea..e646ca8c45 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -37,10 +37,10 @@ from importlib.resources import files
 from typing import Any, Callable, Literal, TYPE_CHECKING, TypedDict
 
 import pkg_resources
-from cachelib.base import BaseCache
 from celery.schedules import crontab
 from flask import Blueprint
 from flask_appbuilder.security.manager import AUTH_DB
+from flask_caching.backends.base import BaseCache
 from pandas import Series
 from pandas._libs.parsers import STR_NA_VALUES  # pylint: disable=no-name-in-module
 from sqlalchemy.orm.query import Query
diff --git a/superset/extensions/__init__.py b/superset/extensions/__init__.py
index f6367067a4..42daf8205b 100644
--- a/superset/extensions/__init__.py
+++ b/superset/extensions/__init__.py
@@ -19,9 +19,9 @@ import os
 from typing import Any, Callable, Optional
 
 import celery
-from cachelib.base import BaseCache
 from flask import Flask
 from flask_appbuilder import AppBuilder, SQLA
+from flask_caching.backends.base import BaseCache
 from flask_migrate import Migrate
 from flask_talisman import Talisman
 from flask_wtf.csrf import CSRFProtect
diff --git a/tests/integration_tests/cachekeys/api_tests.py b/tests/integration_tests/cachekeys/api_tests.py
index c867ce7f51..db2c51d124 100644
--- a/tests/integration_tests/cachekeys/api_tests.py
+++ b/tests/integration_tests/cachekeys/api_tests.py
@@ -27,6 +27,10 @@ from tests.integration_tests.base_tests import (
     SupersetTestCase,
     post_assert_metric,
 )
+from tests.integration_tests.fixtures.birth_names_dashboard import (
+    load_birth_names_dashboard_with_slices,
+    load_birth_names_data,
+)
 
 
 @pytest.fixture
@@ -95,6 +99,7 @@ def test_invalidate_cache_bad_request(invalidate):
     assert rv.status_code == 400
 
 
+@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
 def test_invalidate_existing_caches(invalidate):
     schema = get_example_default_schema() or ""
     bn = SupersetTestCase.get_birth_names_dataset()
diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py
index 2f346564e9..a10b3974b3 100644
--- a/tests/integration_tests/core_tests.py
+++ b/tests/integration_tests/core_tests.py
@@ -411,6 +411,7 @@ class TestCore(SupersetTestCase):
         self.get_json_resp(f"/superset/warm_up_cache?slice_id={slc.id}")
         ck = db.session.query(CacheKey).order_by(CacheKey.id.desc()).first()
         assert ck.datasource_uid == f"{slc.table.id}__table"
+        db.session.delete(ck)
         app.config["STORE_CACHE_KEYS_IN_METADATA_DB"] = store_cache_keys
 
     def test_redirect_invalid(self):