Compare commits

...

5 Commits

Author SHA1 Message Date
Evan
622a53dc5e test(security): harden swagger UI config test against env pollution
Add docstrings to the helper and test, strip config-path env vars from
the subprocess, and read only the final stdout line so banner output
from local config loading can't taint the result.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:48:05 -07:00
Amin Ghadersohi
9b3095902a test(security): enable Swagger UI in csrf-exempt blueprints test
test_csrf_exempt_blueprints expects the OpenApi blueprint in the exempt set,
but it is only registered when FAB_API_SWAGGER_UI is enabled — now opt-in (off
by default). Enable it in the test's app config so the OpenApi blueprint is
registered; the test exercises CSRF exemption, not the Swagger default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-22 22:08:10 -07:00
Amin Ghadersohi
44db966270 test(config): fix Swagger UI test isolation and enable spec in test config
The previous unit test reloaded superset.config in-process, mutating the shared
config module and cascading failures into unrelated unit tests. Evaluate the
env-driven default in a fresh subprocess instead, so no global state is
mutated.

Also enable FAB_API_SWAGGER_UI in the integration test config so the
/api/v1/_openapi spec endpoint remains available to the OpenAPI-spec tests now
that Swagger is opt-in (off) by default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-22 21:48:22 -07:00
Evan
0bf69216b8 test(config): type-annotate swagger test, restore env on teardown
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 21:08:39 -07:00
Amin Ghadersohi
f3922070a8 fix(config): make Swagger UI opt-in (off by default)
FAB_API_SWAGGER_UI was hardcoded to True in the base config, so the
interactive Swagger UI / OpenAPI spec endpoints were exposed by default in
every deployment that inherits it. Make it environment-driven and default it
off so the API documentation surface is opt-in.

Enable via SUPERSET_ENABLE_SWAGGER_UI=true (set in the Docker development env
so local DX is unchanged) or by overriding FAB_API_SWAGGER_UI in
superset_config.py.

Adds a unit test for the env-driven default and documents the change in
UPDATING.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-22 21:06:00 -07:00
6 changed files with 97 additions and 2 deletions

View File

@@ -24,6 +24,10 @@ assists people when migrating to a new version.
## Next
### Swagger UI is opt-in (off by default)
`FAB_API_SWAGGER_UI` now defaults to `False` and is driven by the `SUPERSET_ENABLE_SWAGGER_UI` environment variable. The interactive Swagger UI / OpenAPI documentation endpoints (e.g. `/swagger/v1`) are therefore no longer exposed by default. To enable them, set `SUPERSET_ENABLE_SWAGGER_UI=true` (the bundled Docker development environment sets this) or override `FAB_API_SWAGGER_UI = True` in `superset_config.py`.
### Pivot table First/Last aggregations follow data order
The pivot table chart's `First` and `Last` aggregations now return the first and last value in data (query result) order, instead of effectively returning the minimum and maximum. Existing pivot tables that use these aggregations for totals/subtotals may show different values after upgrading. For deterministic results, ensure the underlying query has a stable sort order.

View File

@@ -70,6 +70,8 @@ SUPERSET_LOG_LEVEL=info
SUPERSET_APP_ROOT="/"
SUPERSET_ENV=development
# Swagger UI is opt-in (off by default); enable it for local development.
SUPERSET_ENABLE_SWAGGER_UI=true
SUPERSET_LOAD_EXAMPLES=yes
CYPRESS_CONFIG=false
SUPERSET_PORT=8088

View File

@@ -424,7 +424,13 @@ LOGO_RIGHT_TEXT: Callable[[], str] | str = ""
# Enables SWAGGER UI for superset openapi spec
# ex: http://localhost:8080/swagger/v1
FAB_API_SWAGGER_UI = True
# Disabled by default so the interactive API documentation surface is opt-in.
# Enable it by setting the SUPERSET_ENABLE_SWAGGER_UI environment variable
# (e.g. for local development) or by overriding FAB_API_SWAGGER_UI in
# superset_config.py.
FAB_API_SWAGGER_UI = utils.cast_to_boolean(
os.environ.get("SUPERSET_ENABLE_SWAGGER_UI", False)
)
# ----------------------------------------------------
# AUTHENTICATION CONFIG

View File

@@ -135,6 +135,10 @@ ALERT_REPORTS_QUERY_EXECUTION_MAX_TRIES = 3
FAB_ADD_SECURITY_API = True
# Swagger UI / OpenAPI spec is opt-in in the base config; enable it for tests
# that exercise the /api/v1/_openapi spec endpoint.
FAB_API_SWAGGER_UI = True
class CeleryConfig:
broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}"

View File

@@ -0,0 +1,77 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Tests for environment-driven Swagger UI config defaults.
``superset.config`` is imported in a fresh subprocess for each case so the
module is evaluated under a controlled environment without reloading (and
mutating) the config module shared by the rest of the test session.
"""
import os
import subprocess
import sys
import pytest
def _resolve_swagger_default(env_value: str | None) -> str:
"""Resolve ``FAB_API_SWAGGER_UI`` for a given ``SUPERSET_ENABLE_SWAGGER_UI``.
Evaluates ``superset.config`` in a fresh subprocess under a controlled
environment so the result reflects only the supplied env var. Config-path
overrides are stripped so a local ``superset_config`` cannot taint the
default, and only the final stdout line is read in case config loading
emits banner output.
"""
env = dict(os.environ)
for var in (
"SUPERSET_ENABLE_SWAGGER_UI",
"SUPERSET_CONFIG_PATH",
"SUPERSET_CONFIG",
):
env.pop(var, None)
if env_value is not None:
env["SUPERSET_ENABLE_SWAGGER_UI"] = env_value
result = subprocess.run( # noqa: S603
[
sys.executable,
"-c",
"import superset.config as c; print(c.FAB_API_SWAGGER_UI)",
],
env=env,
capture_output=True,
text=True,
check=True,
)
return result.stdout.strip().splitlines()[-1]
@pytest.mark.parametrize(
"env_value, expected",
[
(None, "False"), # unset -> off by default
("true", "True"),
("True", "True"),
("false", "False"),
("", "False"),
],
)
def test_fab_api_swagger_ui_is_env_driven_and_off_by_default(
env_value: str | None, expected: str
) -> None:
"""Swagger UI defaults to off and follows ``SUPERSET_ENABLE_SWAGGER_UI``."""
assert _resolve_swagger_default(env_value) == expected

View File

@@ -23,7 +23,9 @@ from superset.extensions import csrf
@pytest.mark.parametrize(
"app",
[{"WTF_CSRF_ENABLED": True}],
# Enable the Swagger UI / OpenAPI spec (opt-in, off by default) so the
# OpenApi blueprint is registered and included in the exempt set below.
[{"WTF_CSRF_ENABLED": True, "FAB_API_SWAGGER_UI": True}],
indirect=True,
)
def test_csrf_exempt_blueprints(app_context: None) -> None: