mirror of
https://github.com/apache/superset.git
synced 2026-06-10 01:59:17 +00:00
Compare commits
3 Commits
master
...
fix/versio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0052909f10 | ||
|
|
898b3c498f | ||
|
|
81a4665813 |
19
UPDATING.md
19
UPDATING.md
@@ -34,6 +34,25 @@ The embedded dashboard page now validates the origin of incoming `postMessage` e
|
||||
|
||||
Enforcement only applies when the Allowed Domains list is non-empty. If the list is empty (the default), any origin is accepted, so there is no behavior change for embeds that did not configure Allowed Domains.
|
||||
|
||||
### New `EXPOSE_VERSION_INFO` config to control `/version` detail
|
||||
|
||||
A new `EXPOSE_VERSION_INFO` config option controls how much detail the unauthenticated `/version` endpoint returns. It defaults to `True`, which preserves the existing behavior: the endpoint returns the full version metadata, including the Git SHA, full SHA, build number, and branch name when available.
|
||||
|
||||
Operators who prefer not to expose build-specific details to unauthenticated callers can set the following in `superset_config.py`:
|
||||
|
||||
```python
|
||||
EXPOSE_VERSION_INFO = False
|
||||
```
|
||||
|
||||
When disabled, `/version` returns only the human-readable `version_string` and omits the Git SHA, full SHA, build number, and branch name. Because the default is `True`, this change is non-breaking for existing deployments.
|
||||
|
||||
As an additional defense-in-depth hardening, Superset now sends a `Cross-Origin-Resource-Policy: same-site` response header by default via `DEFAULT_HTTP_HEADERS`. `same-site` is deliberately chosen over the stricter `same-origin` so that documented same-site embedding flows (e.g. the Embedded SDK, where a Superset subdomain is framed by a sibling application subdomain) continue to work unchanged. Deployments that serve Superset responses or static assets as subresources to a _cross-site_ origin may need to relax or remove this header. Because it is applied through `DEFAULT_HTTP_HEADERS`, the header is only set when a response does not already carry one, so it can be overridden per-response or by replacing the config value:
|
||||
|
||||
```python
|
||||
# Relax to permit cross-site consumers, or set to "same-origin" to harden further.
|
||||
DEFAULT_HTTP_HEADERS = {"Cross-Origin-Resource-Policy": "cross-origin"}
|
||||
```
|
||||
|
||||
### Dataset import validates catalog against the target connection
|
||||
|
||||
Importing a dataset now validates the `catalog` field against the target database connection. When the connection has multi-catalog disabled (`allow_multi_catalog` off) and the dataset's catalog is not the connection's default catalog, the import fails instead of silently persisting the non-default catalog. This matches the validation already enforced on the dataset update path and prevents imported datasets from querying an unintended database.
|
||||
|
||||
@@ -156,6 +156,14 @@ VERSION_SHA = _try_json_readsha(VERSION_INFO_FILE, VERSION_SHA_LENGTH)
|
||||
# can be replaced at build time to expose build information.
|
||||
BUILD_NUMBER = None
|
||||
|
||||
# Controls how much detail the unauthenticated ``/version`` endpoint returns.
|
||||
# When True (default, preserves existing behavior) the endpoint returns the full
|
||||
# version metadata, including the Git SHA and branch name when available. Set to
|
||||
# False to return only the human-readable version string and omit the Git SHA,
|
||||
# full SHA, build number, and branch name, so deployment-specific build details
|
||||
# are not exposed to unauthenticated callers.
|
||||
EXPOSE_VERSION_INFO = True
|
||||
|
||||
# default viz used in chart explorer & SQL Lab explore
|
||||
DEFAULT_VIZ_TYPE = "table"
|
||||
|
||||
@@ -1449,7 +1457,18 @@ CELERY_CONFIG: type[CeleryConfig] | None = CeleryConfig
|
||||
# within the app
|
||||
# OVERRIDE_HTTP_HEADERS: sets override values for HTTP headers. These values will
|
||||
# override anything set within the app
|
||||
DEFAULT_HTTP_HEADERS: dict[str, Any] = {}
|
||||
#
|
||||
# As a defense-in-depth default, Superset sends a conservative
|
||||
# `Cross-Origin-Resource-Policy` header on its responses. `same-site` is used
|
||||
# (rather than the stricter `same-origin`) so that same-site embedding patterns
|
||||
# such as the Embedded SDK, where a Superset subdomain is framed by a sibling
|
||||
# application subdomain, keep working out of the box. Because this is set through
|
||||
# DEFAULT_HTTP_HEADERS, the value is only applied when the response does not
|
||||
# already carry the header, so operators can override it (per-response or by
|
||||
# replacing this config value) to suit their cross-origin requirements.
|
||||
DEFAULT_HTTP_HEADERS: dict[str, Any] = {
|
||||
"Cross-Origin-Resource-Policy": "same-site",
|
||||
}
|
||||
OVERRIDE_HTTP_HEADERS: dict[str, Any] = {}
|
||||
HTTP_HEADERS: dict[str, Any] = {}
|
||||
|
||||
|
||||
@@ -37,9 +37,17 @@ def health() -> FlaskResponse:
|
||||
@talisman(force_https=False)
|
||||
def version() -> FlaskResponse:
|
||||
"""
|
||||
Return comprehensive version information including Git SHA
|
||||
and branch when available.
|
||||
Return version information for the running Superset instance.
|
||||
|
||||
When ``EXPOSE_VERSION_INFO`` is True (default) this returns the full
|
||||
version metadata, including the Git SHA and branch name when available.
|
||||
When it is False, only the human-readable version string is returned and
|
||||
build-specific details (Git SHA, full SHA, build number, branch name) are
|
||||
omitted so they are not exposed to unauthenticated callers.
|
||||
"""
|
||||
if not app.config.get("EXPOSE_VERSION_INFO", True):
|
||||
return jsonify({"version_string": app.config.get("VERSION_STRING", "unknown")})
|
||||
|
||||
from superset.utils.version import get_version_metadata
|
||||
|
||||
return jsonify(get_version_metadata())
|
||||
|
||||
@@ -312,3 +312,28 @@ def test_full_setting(
|
||||
assert dttm_col.is_dttm
|
||||
assert dttm_col.python_date_format == "epoch_s"
|
||||
assert dttm_col.expression == "CAST(dttm as INTEGER)"
|
||||
|
||||
|
||||
def test_expose_version_info_defaults_to_true() -> None:
|
||||
"""
|
||||
The /version endpoint preserves its existing behavior by default. Operators
|
||||
can set EXPOSE_VERSION_INFO = False to omit build-specific details.
|
||||
"""
|
||||
from superset import config
|
||||
|
||||
assert config.EXPOSE_VERSION_INFO is True
|
||||
|
||||
|
||||
def test_default_cross_origin_resource_policy_header() -> None:
|
||||
"""
|
||||
Superset ships a conservative `Cross-Origin-Resource-Policy: same-site`
|
||||
default through DEFAULT_HTTP_HEADERS. `same-site` (rather than `same-origin`)
|
||||
is chosen so documented same-site embedding flows, such as the Embedded SDK,
|
||||
keep working while still providing a defense-in-depth default that operators
|
||||
can override.
|
||||
"""
|
||||
from superset import config
|
||||
|
||||
assert (
|
||||
config.DEFAULT_HTTP_HEADERS.get("Cross-Origin-Resource-Policy") == "same-site"
|
||||
)
|
||||
|
||||
70
tests/unit_tests/views/health_version_test.py
Normal file
70
tests/unit_tests/views/health_version_test.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# 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.
|
||||
"""Unit tests for the ``/version`` endpoint and ``EXPOSE_VERSION_INFO`` gating."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
FULL_METADATA = {
|
||||
"version_string": "1.2.3",
|
||||
"version_sha": "abcd1234",
|
||||
"full_sha": "abcd1234ef567890",
|
||||
"build_number": "42",
|
||||
"branch_name": "master",
|
||||
}
|
||||
|
||||
|
||||
def test_version_exposes_full_metadata_by_default(
|
||||
client: Any,
|
||||
mocker: MockerFixture,
|
||||
) -> None:
|
||||
"""With EXPOSE_VERSION_INFO True (default) the full metadata is returned."""
|
||||
mocker.patch(
|
||||
"superset.utils.version.get_version_metadata",
|
||||
return_value=dict(FULL_METADATA),
|
||||
)
|
||||
client.application.config["EXPOSE_VERSION_INFO"] = True
|
||||
|
||||
response = client.get("/version")
|
||||
assert response.status_code == 200
|
||||
|
||||
body = response.get_json()
|
||||
assert body["version_string"] == "1.2.3"
|
||||
assert body["version_sha"] == "abcd1234"
|
||||
assert body["full_sha"] == "abcd1234ef567890"
|
||||
assert body["branch_name"] == "master"
|
||||
assert body["build_number"] == "42"
|
||||
|
||||
|
||||
def test_version_redacts_details_when_flag_disabled(
|
||||
client: Any,
|
||||
mocker: MockerFixture,
|
||||
) -> None:
|
||||
"""With EXPOSE_VERSION_INFO False only VERSION_STRING from config is returned."""
|
||||
client.application.config["EXPOSE_VERSION_INFO"] = False
|
||||
client.application.config["VERSION_STRING"] = "1.2.3"
|
||||
|
||||
response = client.get("/version")
|
||||
assert response.status_code == 200
|
||||
|
||||
body = response.get_json()
|
||||
assert body == {"version_string": "1.2.3"}
|
||||
assert "version_sha" not in body
|
||||
assert "full_sha" not in body
|
||||
assert "branch_name" not in body
|
||||
assert "build_number" not in body
|
||||
Reference in New Issue
Block a user