Compare commits

..

2 Commits

Author SHA1 Message Date
Đỗ Trọng Hải
6e2769fb48 Merge branch 'master' into fix/mask-sensitive-data-in-debug-log-for-failed-import-validation 2026-07-12 20:05:09 +07:00
hainenber
2f438d47a9 fix(sec): redact sensitive data in debug log for failed import validation
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-12 20:00:41 +07:00
937 changed files with 23369 additions and 71724 deletions

View File

@@ -50,8 +50,9 @@ body:
attributes:
label: Python version
options:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- Not applicable
- I don't know
validations:

View File

@@ -32,6 +32,8 @@ runs:
elif [ "$INPUT_PYTHON_VERSION" = "next" ]; then
# currently disabled in GHA matrixes because of library compatibility issues
RESOLVED_VERSION="3.12"
elif [ "$INPUT_PYTHON_VERSION" = "previous" ]; then
RESOLVED_VERSION="3.10"
elif printf '%s' "$INPUT_PYTHON_VERSION" | grep -Eq '^[0-9]+\.[0-9]+(\.[0-9]+)?$'; then
RESOLVED_VERSION="$INPUT_PYTHON_VERSION"
else

View File

@@ -10,15 +10,8 @@ updates:
- package-ecosystem: "npm"
ignore:
# TODO: remove below entries once the application supports React >= 19.0.0
- dependency-name: "react"
update-types: ["version-update:semver-major"]
- dependency-name: "react-dom"
update-types: ["version-update:semver-major"]
- dependency-name: "@types/react"
update-types: ["version-update:semver-major"]
- dependency-name: "@types/react-dom"
update-types: ["version-update:semver-major"]
- dependency-name: "@rjsf/*"
# TODO: remove below entries until React >= 19.0.0
- dependency-name: "react-icons"
# JSDOM v30 doesn't play well with Jest v30
# Source: https://jestjs.io/blog#known-issues
@@ -48,28 +41,6 @@ updates:
labels:
- npm
- dependabot
groups:
rjsf:
patterns:
- "@rjsf/*"
typescript-eslint:
patterns:
- "@typescript-eslint/*"
- "typescript-eslint"
babel:
patterns:
- "@babel/*"
deckgl:
patterns:
- "@deck.gl/*"
lumagl:
patterns:
- "@luma.gl/*"
storybook:
patterns:
- "@storybook/*"
- "storybook"
- "eslint-plugin-storybook"
open-pull-requests-limit: 30
versioning-strategy: increase
cooldown:
@@ -104,22 +75,6 @@ updates:
directory: "/docs/"
schedule:
interval: "daily"
groups:
storybook:
patterns:
- "@storybook/*"
- "storybook"
docusaurus:
patterns:
- "@docusaurus/*"
docusaurus-openapi:
patterns:
- "docusaurus-plugin-openapi-docs"
- "docusaurus-theme-openapi-docs"
typescript-eslint:
patterns:
- "@typescript-eslint/*"
- "typescript-eslint"
open-pull-requests-limit: 10
versioning-strategy: increase
cooldown:

View File

@@ -23,7 +23,7 @@ on:
jobs:
bump-python-package:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
actions: write
contents: write
@@ -42,7 +42,7 @@ jobs:
- name: Set up Python ${{ inputs.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
python-version: "3.10"
- name: Install uv
run: pip install uv

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
check-python-deps:
runs-on: ubuntu-26.04
runs-on: ubuntu-22.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
check_db_migration_conflict:
name: Check DB migration conflict
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
pull-requests: write

View File

@@ -16,7 +16,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -42,7 +42,7 @@ jobs:
# analysis runners don't spin up. push/schedule runs always proceed:
# the change-detector returns "all changed" for non-PR events.
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
actions: read
@@ -64,7 +64,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -75,6 +75,6 @@ jobs:
# queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
with:
category: "/language:${{matrix.language}}"

View File

@@ -24,7 +24,7 @@ permissions:
jobs:
dependency-review:
if: github.event_name == 'pull_request'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- name: "Checkout Repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -48,7 +48,7 @@ jobs:
python-dependency-liccheck:
# NOTE: Configuration for liccheck lives in our pyproject.yml.
# You cannot use a liccheck.ini file in this workflow.
runs-on: ubuntu-26.04
runs-on: ubuntu-22.04
steps:
- name: "Checkout Repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -40,14 +40,14 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
setup_matrix:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
matrix_config: ${{ steps.set_matrix.outputs.matrix_config }}
steps:
- id: set_matrix
run: |
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "websocket", "dockerize", "py311", "py312"]'; fi)
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]'; fi)
echo "matrix_config=${MATRIX_CONFIG}" >> $GITHUB_OUTPUT
echo $GITHUB_OUTPUT
@@ -58,7 +58,7 @@ jobs:
needs.changes.outputs.python == 'true' ||
needs.changes.outputs.frontend == 'true' ||
needs.changes.outputs.docker == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
matrix:
@@ -123,20 +123,13 @@ jobs:
# pull timeouts, 504/401 on push, ECONNRESET) that otherwise fail
# the whole job. buildx reuses the buildkit layer cache from the
# failed attempt, so a retry mostly re-does just the failed push.
#
# supersetbot's "dev"/"lean" presets pin their own --build-arg
# PY_VER, which lands ahead of --extra-flags on the assembled
# buildx command line; docker/buildx keeps the last value for a
# repeated --build-arg key, so appending PY_VER here overrides
# supersetbot's pin and keeps the build on the Dockerfile's own
# supported Python version.
for attempt in 1 2 3; do
if supersetbot docker \
$PUSH_OR_LOAD \
--preset "$BUILD_PRESET" \
--context "$EVENT" \
--context-ref "$RELEASE" $FORCE_LATEST \
--extra-flags "--build-arg PY_VER=3.11.14-slim-trixie --build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
--extra-flags "--build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
$PLATFORM_ARG; then
break
fi
@@ -180,7 +173,7 @@ jobs:
# goal is to check that building the latest image works, not required for all PR pushes
needs: changes
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.changes.outputs.docker == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"

View File

@@ -15,7 +15,7 @@ jobs:
# gate on. Restrict to the canonical repo: forks cannot mint a valid OIDC
# token for this package and must not publish.
if: github.repository == 'apache/superset'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write # required for npm trusted publishing (OIDC)
@@ -31,7 +31,7 @@ jobs:
# token, which makes npm attempt token auth and skip the OIDC
# trusted-publishing exchange. With no .npmrc auth line, npm authenticates
# via OIDC against the default registry (registry.npmjs.org).
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-embedded-sdk/.nvmrc"
- run: npm ci

View File

@@ -16,7 +16,7 @@ concurrency:
jobs:
embedded-sdk-test:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
defaults:
run:
working-directory: superset-embedded-sdk
@@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-embedded-sdk/.nvmrc"
registry-url: "https://registry.npmjs.org"

View File

@@ -11,7 +11,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -29,7 +29,7 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets
name: Generate Report
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -37,7 +37,7 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Setup Java
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
with:
distribution: "temurin"
java-version: "11"

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
validate-all-ghas:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
# Required for the zizmor action to upload its SARIF results to
@@ -32,7 +32,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "20"

View File

@@ -1,115 +0,0 @@
# 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.
name: Hold Label CI Gate
on:
pull_request:
types: [labeled, unlabeled]
permissions: {}
jobs:
cancel-on-hold:
name: Cancel CI runs when hold label applied
if: github.event.action == 'labeled' && startsWith(github.event.label.name, 'hold')
runs-on: ubuntu-26.04
permissions:
actions: write
pull-requests: read
steps:
- name: Cancel in-progress workflow runs
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
const sha = context.payload.pull_request.head.sha;
const { data: { workflow_runs: runs } } =
await github.rest.actions.listWorkflowRunsForRepo({
owner,
repo,
head_sha: sha,
per_page: 100,
});
const active = runs.filter(r =>
['in_progress', 'queued', 'waiting', 'requested', 'pending'].includes(r.status)
);
core.info(`Found ${active.length} active run(s) to cancel for SHA ${sha}`);
for (const run of active) {
try {
await github.rest.actions.cancelWorkflowRun({
owner,
repo,
run_id: run.id,
});
core.info(`Cancelled run ${run.id} (${run.name})`);
} catch (err) {
core.warning(`Could not cancel run ${run.id}: ${err.message}`);
}
}
rerun-on-unhold:
name: Re-run CI when hold label removed
if: github.event.action == 'unlabeled' && startsWith(github.event.label.name, 'hold')
runs-on: ubuntu-24.04
permissions:
actions: write
pull-requests: read
steps:
- name: Re-trigger cancelled workflow runs
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
const sha = context.payload.pull_request.head.sha;
// Check that no other hold* labels remain on the PR
const labels = context.payload.pull_request.labels.map(l => l.name);
const stillHeld = labels.some(l => l.startsWith('hold'));
if (stillHeld) {
core.info('PR still has a hold label — skipping re-run.');
return;
}
const { data: { workflow_runs: runs } } =
await github.rest.actions.listWorkflowRunsForRepo({
owner,
repo,
head_sha: sha,
per_page: 100,
});
const cancelled = runs.filter(r => r.conclusion === 'cancelled');
core.info(`Found ${cancelled.length} cancelled run(s) to re-trigger for SHA ${sha}`);
for (const run of cancelled) {
try {
await github.rest.actions.reRunWorkflow({
owner,
repo,
run_id: run.id,
});
core.info(`Re-triggered run ${run.id} (${run.name})`);
} catch (err) {
core.warning(`Could not re-run ${run.id}: ${err.message}`);
}
}

View File

@@ -9,7 +9,7 @@ on:
jobs:
superbot-orglabel:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
pull-requests: write

View File

@@ -12,9 +12,9 @@ jobs:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
with:
sync-labels: true

View File

@@ -6,7 +6,7 @@ on:
jobs:
latest-release:
name: Add/update tag to new release
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: write

View File

@@ -15,7 +15,7 @@ concurrency:
jobs:
license_check:
name: License Check
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -23,7 +23,7 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Setup Java
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
with:
distribution: "temurin"
java-version: "11"

View File

@@ -17,7 +17,7 @@ concurrency:
jobs:
check-hold-label:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- name: Check for 'hold' label
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0

View File

@@ -8,20 +8,14 @@ on:
# Possible values: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request
types: [opened, edited, reopened, synchronize]
# Serialize runs per PR without cancelling: the `edited` trigger means a PR
# opened and then edited has two queued runs for the same head SHA. On
# first-time-contributor PRs those runs start together when a maintainer
# approves workflows, and cancel-in-progress lets the older run cancel the
# newer one — leaving a permanently-cancelled required check on the head SHA
# that blocks merging until manually re-run. This job takes seconds, so let
# queued runs complete instead.
# cancel previous workflow jobs for PRs
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: false
cancel-in-progress: true
jobs:
lint-check:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
pull-requests: write

View File

@@ -7,11 +7,6 @@ on:
- "[0-9].[0-9]*"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
# Nightly full-tree sweep. Per-PR runs only lint changed files, so a change
# that invalidates an untouched file (e.g. a type change that breaks an
# importing test) can pass every PR yet leave master red. This catches that.
schedule:
- cron: "0 6 * * *"
permissions:
contents: read
@@ -23,23 +18,20 @@ concurrency:
jobs:
pre-commit:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 20
strategy:
matrix:
# Run the full version spread on push (master/release) and nightly,
# but only the current version on PRs — lint/format/type results
# rarely differ across patch versions, so 3x per PR is wasteful.
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "next"]') }}
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }}
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
submodules: recursive
# Full history so we can diff a PR/push against its base commit to
# determine changed files (see "Determine changed files" below).
fetch-depth: 0
- name: Setup Python
uses: ./.github/actions/setup-backend/
@@ -53,7 +45,7 @@ jobs:
run: go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "superset-frontend/.nvmrc"
cache: "npm"
@@ -77,82 +69,19 @@ jobs:
restore-keys: |
pre-commit-v2-${{ runner.os }}-py${{ matrix.python-version }}-
- name: Determine changed files
- name: Get changed files
id: changed_files
env:
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
BEFORE_SHA: ${{ github.event.before }}
run: |
set -euo pipefail
# Scheduled runs check the whole tree (see the pre-commit step).
if [ "${EVENT_NAME}" = "schedule" ]; then
echo "mode=all" >> "$GITHUB_OUTPUT"
exit 0
fi
# Resolve the commit to diff against.
base=""
if [ "${EVENT_NAME}" = "pull_request" ]; then
base="${BASE_SHA}"
elif [ -n "${BEFORE_SHA:-}" ] && \
[ "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]; then
base="${BEFORE_SHA}"
fi
# Fail closed: if the diff base can't be resolved, check every file
# instead of silently checking nothing. Previously an empty file list
# made `pre-commit run --files` a no-op that still reported success,
# which let unlinted code reach master.
if [ -z "${base}" ] || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then
echo "::notice::Could not resolve a diff base; falling back to --all-files."
echo "mode=all" >> "$GITHUB_OUTPUT"
exit 0
fi
# Files present in HEAD that changed since the base (drop deletions).
files="$(git diff --name-only --diff-filter=ACMRT "${base}...HEAD")"
if [ -z "${files}" ]; then
echo "mode=none" >> "$GITHUB_OUTPUT"
else
echo "mode=files" >> "$GITHUB_OUTPUT"
{
echo "files<<__CHANGED_FILES_EOF__"
echo "${files}"
echo "__CHANGED_FILES_EOF__"
} >> "$GITHUB_OUTPUT"
fi
uses: ./.github/actions/file-changes-action
with:
output: " "
- name: pre-commit
env:
MODE: ${{ steps.changed_files.outputs.mode }}
CHANGED_FILES: ${{ steps.changed_files.outputs.files }}
run: |
set +e # Don't exit immediately on failure
export SKIP=type-checking-frontend
case "${MODE}" in
all)
echo " Running pre-commit on all files."
pre-commit run --all-files
;;
files)
echo " Running pre-commit on changed files:"
echo "${CHANGED_FILES}"
# shellcheck disable=SC2086
pre-commit run --files ${CHANGED_FILES}
;;
none)
echo " No source files changed; nothing for pre-commit to check."
exit 0
;;
*)
echo "⚠️ Unrecognized changed-files mode '${MODE}'; checking all files."
pre-commit run --all-files
;;
esac
pre-commit run --files $CHANGED_FILES
PRE_COMMIT_EXIT_CODE=$?
git diff --quiet --exit-code
GIT_DIFF_EXIT_CODE=$?

View File

@@ -11,7 +11,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -29,7 +29,7 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets
name: Bump version and publish package(s)
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
@@ -50,7 +50,7 @@ jobs:
- name: Install Node.js
if: env.HAS_TAGS
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-frontend/.nvmrc"

View File

@@ -40,7 +40,7 @@ concurrency:
jobs:
config:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
latest-release: ${{ steps.latest.outputs.tag }}
@@ -93,12 +93,12 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets == '1'
name: docker-rebuild
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
strategy:
# Mirror the same matrix the release publisher uses so every variant
# operators consume from Docker Hub gets the refreshed base.
matrix:
build_preset: ["dev", "lean", "websocket", "dockerize", "py311", "py312"]
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
fail-fast: false
steps:
- name: "Checkout release tag: ${{ needs.config.outputs.latest-release }}"
@@ -117,7 +117,7 @@ jobs:
build: "true"
- name: Use Node.js 20
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: 20
@@ -155,7 +155,7 @@ jobs:
notify-on-failure:
needs: [config, docker-rebuild]
if: failure() && needs.config.outputs.has-secrets == '1'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
issues: write

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
test-load-examples:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
env:
PYTHONPATH: ${{ github.workspace }}
SUPERSET_CONFIG: tests.integration_tests.superset_test_config

View File

@@ -33,7 +33,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -57,7 +57,7 @@ jobs:
(github.event_name != 'workflow_run' ||
github.event.workflow_run.head_repository.full_name == github.repository)
name: Build & Deploy
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -66,12 +66,12 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./docs/.nvmrc"
- name: Setup Python
uses: ./.github/actions/setup-backend/
- uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
- uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
with:
distribution: "zulu"
java-version: "21"

View File

@@ -67,7 +67,7 @@ jobs:
# Build docs when PR changes docs/** (uses committed databases.json)
if: github.event_name == 'pull_request'
name: Build (PR trigger)
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
defaults:
run:
working-directory: docs
@@ -78,7 +78,7 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./docs/.nvmrc"
- name: yarn install
@@ -106,7 +106,7 @@ jobs:
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_repository.full_name == github.repository
name: Build (after integration tests)
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
defaults:
run:
working-directory: docs
@@ -118,7 +118,7 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./docs/.nvmrc"
- name: yarn install

View File

@@ -28,7 +28,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -50,7 +50,8 @@ jobs:
cypress-matrix:
needs: changes
if: (needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true') && github.event.pull_request.draft == false
runs-on: ubuntu-26.04
# Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04
runs-on: ubuntu-22.04
timeout-minutes: 30
permissions:
contents: read
@@ -127,7 +128,7 @@ jobs:
with:
run: testdata
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"
@@ -172,7 +173,7 @@ jobs:
playwright-tests:
needs: changes
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-22.04
timeout-minutes: 30
permissions:
contents: read
@@ -237,7 +238,7 @@ jobs:
with:
run: playwright_testdata
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"
@@ -300,7 +301,7 @@ jobs:
cypress-matrix-required:
needs: [changes, cypress-matrix]
if: always()
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions: {}
steps:
@@ -322,7 +323,7 @@ jobs:
playwright-tests-required:
needs: [changes, playwright-tests]
if: always()
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions: {}
steps:

View File

@@ -19,13 +19,13 @@ concurrency:
jobs:
test-superset-extensions-cli-package:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
matrix:
# Full version spread on push (master/release) + nightly; current only
# on PRs to cut runner cost (cross-version breaks are caught at merge).
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "next"]') }}
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["previous", "current", "next"]') }}
defaults:
run:
working-directory: superset-extensions-cli

View File

@@ -21,7 +21,7 @@ permissions:
jobs:
frontend-build:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 30
outputs:
should-run: ${{ steps.check.outputs.frontend }}
@@ -51,7 +51,7 @@ jobs:
git show -s --format=raw HEAD
docker buildx build \
-t $TAG \
--cache-from=type=registry,ref=apache/superset-cache:3.11-slim-trixie \
--cache-from=type=registry,ref=apache/superset-cache:3.10-slim-trixie \
--target superset-node-ci \
.
@@ -74,7 +74,7 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5, 6, 7, 8]
fail-fast: false
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Download Docker Image Artifact
@@ -104,7 +104,7 @@ jobs:
report-coverage:
needs: [sharded-jest-tests]
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
id-token: write
@@ -146,7 +146,7 @@ jobs:
lint-frontend:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Download Docker Image Artifact
@@ -171,7 +171,7 @@ jobs:
validate-frontend:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Download Docker Image Artifact
@@ -191,7 +191,7 @@ jobs:
test-storybook:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- name: Download Docker Image Artifact

View File

@@ -2,24 +2,21 @@ name: "Helm: lint and test charts"
on:
pull_request:
types: [opened, reopened, synchronize]
types: [opened, edited, reopened, synchronize]
paths:
- "helm/**"
permissions:
contents: read
# Serialize runs per PR without cancelling: when a first-time contributor's
# queued runs are approved together, cancel-in-progress lets an older run
# cancel a newer one, leaving a permanently-cancelled required check on the
# head SHA. Queued runs are cheap here, so let them all complete.
# cancel previous workflow jobs for PRs
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: false
cancel-in-progress: true
jobs:
lint-test:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -31,7 +28,7 @@ jobs:
- name: Set up Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: v3.21.3
version: v3.16.4
- name: Setup Python
uses: ./.github/actions/setup-backend/
@@ -59,9 +56,3 @@ jobs:
CT_LINT_CONF: lintconf.yaml
CT_SINCE: HEAD
CT_CHART_REPOS: bitnami=https://charts.bitnami.com/bitnami
- name: Set up helm-unittest
run: helm plugin install https://github.com/helm-unittest/helm-unittest --version v1.1.1
- name: Run helm-unittest
run: helm unittest helm/superset

View File

@@ -20,7 +20,7 @@ on:
jobs:
release:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write

View File

@@ -24,7 +24,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -48,7 +48,7 @@ jobs:
playwright-tests-experimental:
needs: changes
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-22.04
timeout-minutes: 30
continue-on-error: true
permissions:
@@ -114,7 +114,7 @@ jobs:
with:
run: playwright_testdata
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"

View File

@@ -20,7 +20,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -41,7 +41,7 @@ jobs:
test-mysql:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
id-token: write
@@ -127,7 +127,7 @@ jobs:
test-postgres:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
id-token: write
@@ -135,7 +135,7 @@ jobs:
matrix:
# Full version spread on push (master/release) + nightly; current only
# on PRs to cut runner cost (cross-version breaks are caught at merge).
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "next"]') }}
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }}
env:
PYTHONPATH: ${{ github.workspace }}
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
@@ -188,7 +188,7 @@ jobs:
test-sqlite:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
id-token: write
@@ -243,7 +243,7 @@ jobs:
test-postgres-required:
needs: [changes, test-postgres]
if: always()
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Check test-postgres result

View File

@@ -16,7 +16,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -37,7 +37,7 @@ jobs:
test-postgres-presto:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
id-token: write
@@ -100,7 +100,7 @@ jobs:
test-postgres-hive:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
id-token: write

View File

@@ -21,7 +21,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
@@ -42,7 +42,7 @@ jobs:
unit-tests:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
id-token: write
@@ -50,15 +50,9 @@ jobs:
matrix:
# Full version spread on push (master/release) + nightly; current only
# on PRs to cut runner cost (cross-version breaks are caught at merge).
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "next"]') }}
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["previous", "current", "next"]') }}
env:
PYTHONPATH: ${{ github.workspace }}
# Promotes the SQLAlchemy 2.0 deprecation warnings already locked in as
# errors via pytest.ini's `filterwarnings` to actually run in CI, so a
# regression on those fails the build instead of relying on a
# contributor remembering to set this locally. See the migration
# battleplan: https://github.com/apache/superset/discussions/40273
SQLALCHEMY_WARN_20: "1"
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -99,7 +93,7 @@ jobs:
unit-tests-required:
needs: [changes, unit-tests]
if: always()
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Check unit-tests result

View File

@@ -20,7 +20,7 @@ permissions:
jobs:
post-comment:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
# Only act when the Translations workflow failed (which means a regression
# was detected — the workflow exits 1 on regression).
if: github.event.workflow_run.conclusion == 'failure'

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
frontend-check-translations:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
pull-requests: read
@@ -38,7 +38,7 @@ jobs:
- name: Setup Node.js
if: steps.check.outputs.frontend
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"
@@ -55,7 +55,7 @@ jobs:
npm run build-translation
babel-extract:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
pull-requests: read

View File

@@ -21,7 +21,7 @@ concurrency:
jobs:
app-checks:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
@@ -29,7 +29,7 @@ jobs:
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: './superset-websocket/.nvmrc'
- name: Install dependencies

View File

@@ -15,7 +15,7 @@ on:
jobs:
supersetbot:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
if: >
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@supersetbot'))

View File

@@ -32,7 +32,7 @@ concurrency:
jobs:
config:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -50,13 +50,13 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets
name: docker-release
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: write
strategy:
matrix:
build_preset:
["dev", "lean", "websocket", "dockerize", "py311", "py312"]
["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
fail-fast: false
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
@@ -75,7 +75,7 @@ jobs:
- name: Use Node.js 20
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: 20
package-manager-cache: false
@@ -120,7 +120,7 @@ jobs:
update-prs-with-release-info:
needs: config
if: needs.config.outputs.has-secrets
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
permissions:
contents: read
pull-requests: write
@@ -133,7 +133,7 @@ jobs:
- name: Use Node.js 20
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: 20
package-manager-cache: false

View File

@@ -11,7 +11,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -28,7 +28,7 @@ jobs:
process-and-upload:
needs: config
if: needs.config.outputs.has-secrets
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
name: Generate Reports
steps:
- name: Checkout Repository
@@ -37,7 +37,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version-file: "./superset-frontend/.nvmrc"

View File

@@ -7,7 +7,7 @@ on:
jobs:
welcome:
runs-on: ubuntu-26.04
runs-on: ubuntu-24.04
if: github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
permissions:
pull-requests: write

3
.gitmodules vendored
View File

@@ -21,6 +21,9 @@
[submodule ".github/actions/pr-lint-action"]
path = .github/actions/pr-lint-action
url = https://github.com/morrisoncole/pr-lint-action
[submodule ".github/actions/file-changes-action"]
path = .github/actions/file-changes-action
url = https://github.com/trilom/file-changes-action
[submodule ".github/actions/cached-dependencies"]
path = .github/actions/cached-dependencies
url = https://github.com/apache-superset/cached-dependencies

View File

@@ -31,10 +31,9 @@ repos:
types-simplejson,
types-python-dateutil,
types-requests,
# types-redis is intentionally absent: redis-py ships its own
# bundled types (py.typed, since 4.6+/5.x), while the stub
# package is unmaintained (frozen at the 4.6.0.x API surface).
# Installing the stub would shadow the accurate inline types.
# types-redis 4.6.0.5 is failing mypy
# because of https://github.com/python/typeshed/pull/10531
types-redis==4.6.0.4,
types-pytz,
types-croniter,
types-PyYAML,
@@ -82,12 +81,6 @@ repos:
language: system
pass_filenames: true
files: ^superset-frontend/.*\.(js|jsx|ts|tsx)$
- id: stylelint-frontend
name: stylelint (frontend css-in-js)
entry: ./scripts/stylelint.sh
language: system
pass_filenames: true
files: ^superset-frontend/.*\.(js|jsx|ts|tsx)$
- id: eslint-docs
name: eslint (docs)
entry: bash -c 'cd docs && FILES=$(printf "%s\n" "$@" | sed "s|^docs/||" | tr "\n" " ") && yarn eslint --fix --quiet $FILES'

View File

@@ -7,7 +7,6 @@
.codecov.yml
.eslintrc
.eslintignore
.stylelintignore
.flake8
.nvmrc
.prettierrc

View File

@@ -15,8 +15,8 @@
# limitations under the License.
#
# Python version installed; we need 3.11-3.12
PYTHON=`command -v python3.11 || command -v python3.12`
# Python version installed; we need 3.10-3.11
PYTHON=`command -v python3.11 || command -v python3.10`
.PHONY: install superset venv pre-commit up down logs ps nuke ports open
@@ -76,7 +76,7 @@ update-js:
venv:
# Create a virtual environment and activate it (recommended)
if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.11 or 3.12 installed"; exit 1; fi
if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.10 or 3.11 installed"; exit 1; fi
test -d venv || ${PYTHON} -m venv venv # setup a python3 virtualenv
. venv/bin/activate

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.11-slim-trixie
FROM python:3.10-slim-trixie
RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.11-slim-trixie
FROM python:3.10-slim-trixie
RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.11-slim-trixie
FROM python:3.10-slim-trixie
ARG VERSION
RUN git clone --depth 1 --branch ${VERSION} https://github.com/apache/superset.git /superset

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.11-slim-trixie
FROM python:3.10-slim-trixie
RUN apt-get update -y
RUN apt-get install -y \

View File

@@ -24,21 +24,6 @@ assists people when migrating to a new version.
## Next
### SQL_QUERY_MUTATOR now honors MUTATE_AFTER_SPLIT in SQL Lab
SQL Lab now applies `SQL_QUERY_MUTATOR` according to `MUTATE_AFTER_SPLIT`, matching the documented semantics and the chart/query path. This only affects deployments that define `SQL_QUERY_MUTATOR` in `superset_config.py`:
- With `MUTATE_AFTER_SPLIT = True`, the mutator previously never ran in SQL Lab; it now runs on each individual statement (including on engines like BigQuery and Kusto that execute multiple statements as one block, where each statement is mutated before the statements are joined).
- With `MUTATE_AFTER_SPLIT = False` (the default), multi-statement SQL Lab queries previously applied the mutator to each statement separately; the mutator now runs once on the whole un-split query, as documented. Single-statement queries are unaffected.
- With `MUTATE_AFTER_SPLIT = False` on engines that execute statements individually, the mutator's output is re-parsed to split it into statements. A mutator that emits SQL Superset's parser cannot parse will now fail with a clear parse error before execution, and one that strips a query down to nothing raises an invalid-SQL error instead of executing an empty query.
### Python 3.10 support removed
Python 3.10 is no longer supported. Superset now requires **Python 3.11 or higher**.
Update your environment (virtualenv, Docker base image, CI configuration, etc.) to
Python 3.11+ before upgrading. The `apache/superset-cache:3.10-slim-trixie` and
`py310` Docker image variants are no longer published.
### Owners, dashboard roles, and RLS roles replaced by Subjects
Superset now uses subject-based access assignments for dashboards, charts, datasets,
@@ -127,8 +112,6 @@ in a later major version.
- [41044](https://github.com/apache/superset/issues/41044): Removes the deprecated `AVOID_COLORS_COLLISION` feature flag (it defaulted to `True`). Color-collision avoidance is now permanently enabled; any config override setting it to `False` is ignored.
- [41813](https://github.com/apache/superset/pull/41813): `redis` (the Python client, `redis-py`) is bumped from 5.3.1 to 8.0.1. redis-py 8 changes several connection defaults; Superset's own Redis-backed features (`GLOBAL_ASYNC_QUERIES_CACHE_BACKEND`, `DISTRIBUTED_COORDINATION_CONFIG`, and the MCP Redis store) explicitly pin the pre-upgrade behavior so this bump is a no-op for them: the wire protocol stays RESP2 (not the new RESP3 default, which requires Redis/Sentinel 6+ to speak `HELLO`) and there is still no socket timeout by default (redis-py 8 defaults to 5s, which could otherwise newly time out large cached payloads or slow networks). The no-timeout default can now be overridden via two new config keys, `CACHE_REDIS_SOCKET_TIMEOUT` / `CACHE_REDIS_SOCKET_CONNECT_TIMEOUT`, on any `CacheConfig` dict using `CACHE_TYPE: RedisCache` or `RedisSentinelCache`. Separately, redis-py 6+ changed the default for `ssl_check_hostname` from `False` to `True` for SSL connections using `ssl_cert_reqs="required"` (the default) — this is a security improvement, so it has **not** been reverted; deployments with `CACHE_REDIS_SSL=True` whose certificates lack a hostname matching the connection address should set `CACHE_REDIS_SSL_CERT_REQS="none"` (disables cert verification entirely, matching hostname-check bypass) or replace the certificate. General-purpose cache/results backends configured via `CACHE_CONFIG` / `DATA_CACHE_CONFIG` / `RESULTS_BACKEND` with `CACHE_TYPE: RedisCache` go through `flask-caching`'s own Redis backend (outside Superset's code) and are subject to the same new defaults; pass `socket_timeout` / `protocol` via `CACHE_OPTIONS` there if needed. Celery broker and result-backend connections (built by `kombu`, also outside Superset's code) keep their no-socket-timeout behavior (`kombu` passes `socket_timeout=None` explicitly) but do **not** pin the wire protocol, so they follow redis-py's RESP3 default — which requires a Redis server new enough to speak `HELLO` (Redis 6+). Deployments using a pre-6.0 Redis server (EOL) as a Celery broker should upgrade the server before taking this bump.
- [39925](https://github.com/apache/superset/pull/39925): URL prefixing for `SUPERSET_APP_ROOT` subdirectory deployments is now handled automatically by helpers in `src/utils/navigationUtils` (`openInNewTab`, `redirect`, `getShareableUrl`, `<AppLink>`). Direct imports of `ensureAppRoot` / `makeUrl` from `src/utils/pathUtils` are forbidden outside `navigationUtils.ts` (enforced by a static-invariant test); contributors writing new code should use the focused helpers instead. No runtime behaviour change for existing callers — all 19 prior call sites have been migrated and four pre-existing double-prefix and missing-prefix bugs are fixed as part of the migration.
- [39925](https://github.com/apache/superset/pull/39925): `SupersetClient.getUrl()` now strips a single leading application-root segment from the supplied `endpoint` before building the request URL, so a caller that accidentally pre-prefixes its endpoint (for example by wrapping it with `ensureAppRoot` before passing it to the client) no longer produces a doubled `/superset/superset/...` URL under subdirectory deployment. The strip is **single-pass** — a genuine `/superset/superset/<slug>` route is preserved, not collapsed — and **silent** (no console warning); the static-invariant test remains the primary signal for pre-prefixing at the call site, and this runtime strip is a safety net beneath it. Code that intentionally targeted a literal `/<app_root>/<app_root>/...` endpoint through `getUrl` (a configuration that has no legitimate use under the prefixing model) would have its first redundant segment removed.
@@ -170,16 +153,6 @@ virtual-dataset SQL) raises a parse error in SQL Lab and dashboard-generated
queries. Deployments that legitimately run queries above this size should raise
the value, and `SQL_MAX_PARSE_LENGTH = None` disables the check entirely.
### Ant Design upgraded from v5 to v6
The frontend now builds against Ant Design 6, and `@superset-ui/core` / `@apache-superset/core` peer-depend on `antd ^6`. Custom plugins, extensions, and themes that interact with Ant Design need review:
- **Internal DOM classes were renamed**, so any custom CSS targeting `.ant-*` internals silently stops matching. Notable renames: `.ant-tabs-content-holder``.ant-tabs-body-holder`, `.ant-tabs-content``.ant-tabs-body`, `.ant-tabs-tabpane``.ant-tabs-content`; `.ant-select-selector``.ant-select-content`, `.ant-select-selection-placeholder``.ant-select-placeholder`, `.ant-select-arrow``.ant-select-suffix`; `.ant-tooltip-inner``.ant-tooltip-container`; `.ant-popover-inner``.ant-popover-container`; `.ant-steps-item-tail``.ant-steps-item-rail`.
- **Some component props changed or were removed** — e.g. `Select` no longer accepts `dropdownAlign`, `visible`/`onVisibleChange` are `open`/`onOpenChange`, `Dropdown` `overlay` is `menu`, `Steps.Step` children are the `items` prop, and `styles.body` on Tooltip/Popover is `styles.container`.
- **CSS variables are on by default** in antd 6, and `ThemeConfig.cssVar` no longer accepts a boolean; Superset theme configs using `cssVar: true`/`false` are coerced (`true``{}`, `false` → omitted).
Theme tokens are unaffected — antd 6 removed none of the tokens Superset exposes, so existing theme configurations continue to work. See the [Ant Design v6 migration guide](https://ant.design/docs/react/migration-v6) for the complete upstream list.
### Guest-token RLS rules reject unknown fields
The `rls` rules passed to `POST /api/v1/security/guest_token/` are now validated strictly: a rule may only contain `dataset` and `clause`. Previously unknown fields were silently dropped, so a mistyped or legacy scope key (most commonly `datasource` instead of `dataset`) produced a rule with no `dataset`, which is treated as a *global* rule applied to every dataset the embedded resource can reach. Such a request now returns HTTP 400 identifying the offending field instead of issuing a token with an unintended global rule. Integrators that were sending extra fields in RLS rules must remove them; valid dataset-scoped (`{"dataset": 41, "clause": "..."}`) and global (`{"clause": "..."}`) rules are unaffected.
@@ -209,10 +182,6 @@ helm upgrade <release-name> superset/superset
Alternatively, perform a fresh install. This is a one-time migration; subsequent upgrades are unaffected.
### Time-series tooltips follow the selected time grain
Tooltips on the Time-series and Mixed Time-series ECharts plugins now respect the chart's time grain (and any dashboard-level time-grain override delivered via `extra_form_data`) when the tooltip time format is left on Adaptive formatting (the default). Tooltips read grain-appropriate labels such as `Jan 2021` (month), `2021 Q1` (quarter), `2021` (year), and weekly date ranges, becoming grain-aware like the x-axis, though the two are formatted independently and their labels may not always match exactly. Only a custom, explicitly-set tooltip time format (a d3 format string) is unaffected — that always wins over the grain.
### 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.
@@ -231,12 +200,6 @@ The `thumbnail_url` field has been removed from `GET /api/v1/dashboard/` list re
The thumbnail endpoint redirects to the current digest URL regardless of whether the supplied digest is exact. If the image is not yet cached, that digest URL may return `202` and trigger async generation. Using `changed_on_utc` as the digest is sufficient for cache-busting purposes.
### Dashboard import can overwrite related charts, datasets, and databases
Re-importing an existing dashboard previously overwrote only the dashboard itself; its related charts, datasets, and databases were never updated (the importer hardcoded `overwrite=False` for them). They can now be overwritten as part of the import.
A new `overwrite_all` form field controls this, and defaults to `false` everywhere, so existing behavior is preserved: passing `overwrite=true` alone still overwrites only the dashboard, exactly as before. To also overwrite the related charts, datasets, and databases on the `/api/v1/dashboard/import/` endpoint, pass `overwrite_all=true` explicitly. The import modal in the UI exposes this as an "also overwrite all assets" checkbox, and the CLI `superset import-dashboards` and the `ImportDashboardsCommand` likewise default `overwrite_all` to `false`.
### Tagging fix for `create_all`-bootstrapped schemas
Only affects deployments whose metadata schema was created with SQLAlchemy's `create_all` (rather than `superset db upgrade`) on a foreign-key-enforcing backend — PostgreSQL, or MySQL with `FOREIGN_KEY_CHECKS=1`. Such schemas carry three invalid foreign keys on `tagged_object.object_id` that break tagging (`TAGGING_SYSTEM = True`) with a `ForeignKeyViolation`. Schemas built via `superset db upgrade` are unaffected.
@@ -262,19 +225,6 @@ A few save- and import-path internals change **unconditionally** (independent of
These are behavior changes that take effect on upgrade regardless of `ENABLE_VERSIONING_CAPTURE`; no operator action is required.
### Cross-entity version activity stream
A read-only companion to the version-history endpoints: each entity type gains a `GET /api/v1/{chart,dashboard,dataset}/<uuid>/activity/` endpoint returning a chronological, access-filtered stream of edits — the entity's own edits plus, for charts and dashboards, transitive edits to related entities during their association windows. Datasets have no related layer in V2, so `include=related` returns an empty stream for a dataset and `include=all` reduces to the dataset's own edits.
| Param | Type | Default | Purpose |
|---|---|---|---|
| `since` / `until` | ISO 8601 | — | Bound `issued_at` |
| `include` | `self` \| `related` \| `all` | `all` | Own edits, related edits, or both |
| `q` | string | — | Case-insensitive search over the full history, applied before pagination (so `count` reflects matches) |
| `page` / `page_size` | integer | `0` / `25` | Pagination (`page_size` clamped to 200) |
Authorization reuses the resource's `can_read` permission and per-object `raise_for_access`; related-entity rows are visibility-filtered to what the caller may see. The stream is empty unless version capture is on (`ENABLE_VERSIONING_CAPTURE`).
### Webhook alerts/reports block private/internal hosts by default
Webhook alert/report dispatch (`WebhookNotification.send`) now validates the target URL's host against the same private/internal-IP block applied to dataset import URLs. If the resolved host is in a loopback, link-local, private (RFC-1918), shared-CGNAT, or multicast range, the webhook is rejected with `NotificationParamException`.
@@ -771,7 +721,6 @@ See `superset/mcp_service/PRODUCTION.md` for deployment guides.
---
- [38358](https://github.com/apache/superset/pull/38358): Switched CrateDB PyPI package from `crate[sqlalchemy]` to `sqlalchemy-cratedb`.
- [35621](https://github.com/apache/superset/pull/35621): The default hash algorithm has changed from MD5 to SHA-256 for improved security and FedRAMP compliance. This affects cache keys for thumbnails, dashboard digests, chart digests, and filter option names. Existing cached data will be invalidated upon upgrade. To opt out of this change and maintain backward compatibility, set `HASH_ALGORITHM = "md5"` in your `superset_config.py`.
- [35062](https://github.com/apache/superset/pull/35062): Changed the function signature of `setupExtensions` to `setupCodeOverrides` with options as arguments.

View File

@@ -71,7 +71,7 @@ x-common-build: &common-build
context: .
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
cache_from:
- apache/superset-cache:3.11-slim-trixie
- apache/superset-cache:3.10-slim-trixie
args:
DEV_MODE: "true"
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}

View File

@@ -33,7 +33,7 @@ x-common-build: &common-build
context: .
target: dev
cache_from:
- apache/superset-cache:3.11-slim-trixie
- apache/superset-cache:3.10-slim-trixie
services:
redis:

View File

@@ -38,7 +38,7 @@ x-common-build: &common-build
context: .
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
cache_from:
- apache/superset-cache:3.11-slim-trixie
- apache/superset-cache:3.10-slim-trixie
args:
DEV_MODE: "true"
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}

View File

@@ -135,7 +135,7 @@ Superset sends an HTTP POST with `Content-Type: application/json`:
}
```
When a report includes file attachments (CSV, Excel, PDF, or PNG screenshots), the request is sent as `multipart/form-data` instead. In that case, each top-level payload field (`name`, `text`, `description`, `url`) becomes its own form field, and nested structures like `header` are serialized as a JSON-encoded string in their own field. Every attachment is added as a repeated form field named `files`:
When a report includes file attachments (CSV, PDF, or PNG screenshots), the request is sent as `multipart/form-data` instead. In that case, each top-level payload field (`name`, `text`, `description`, `url`) becomes its own form field, and nested structures like `header` are serialized as a JSON-encoded string in their own field. Every attachment is added as a repeated form field named `files`:
```
POST /webhook HTTP/1.1
@@ -361,7 +361,7 @@ This is the best source of information about the problem. In a docker compose d
### Check web browser and webdriver installation
To take a screenshot, the worker visits the dashboard or chart using a headless browser, then takes a screenshot. If you are able to send a chart as CSV, XLSX, or text but can't send as PNG, your problem may lie with the browser.
To take a screenshot, the worker visits the dashboard or chart using a headless browser, then takes a screenshot. If you are able to send a chart as CSV or text but can't send as PNG, your problem may lie with the browser.
If you are handling the installation of the headless browser on your own, do your own verification to ensure that the headless browser opens successfully in the worker environment.

View File

@@ -99,7 +99,7 @@ See [Connecting AI Clients](#connecting-ai-clients) for Claude Code, Claude Web,
## Prerequisites
- Apache Superset 5.0+ running and accessible
- Python 3.11+
- Python 3.10+
- The `fastmcp` package (`pip install fastmcp`)
---
@@ -529,7 +529,6 @@ MCP_RESPONSE_SIZE_CONFIG = {
"enabled": True,
"token_limit": 25000,
"warn_threshold_pct": 80,
"max_list_items": 100,
"excluded_tools": [
"health_check",
"get_chart_preview",
@@ -544,7 +543,6 @@ MCP_RESPONSE_SIZE_CONFIG = {
| `enabled` | `True` | Enable response size checking |
| `token_limit` | `25000` | Maximum estimated token count per response |
| `warn_threshold_pct` | `80` | Warn when response exceeds this percentage of the limit |
| `max_list_items` | `100` | Cap on list-field length (e.g. `charts`, `native_filters`) applied to the `get_*_info` tools before falling back to more aggressive truncation. Raised from a hardcoded 30 in earlier versions; the higher default only keeps more data before the same token-budget fallback kicks in, so it's not a breaking change, but tenants that tuned workflows around the old 30-item cap should lower this value explicitly. |
| `excluded_tools` | See above | Tools exempt from size checking (e.g., tools that return URLs, not data) |
### Caching

View File

@@ -379,7 +379,7 @@ functioning across environments.
Make sure your machine meets the [OS dependencies](https://superset.apache.org/docs/installation/pypi#os-dependencies) before following these steps.
You also need to install MySQL.
Ensure that you are using Python version 3.11 or 3.12, then proceed with:
Ensure that you are using Python version 3.9, 3.10 or 3.11, then proceed with:
```bash
# Create a virtual environment and activate it (recommended)

View File

@@ -82,7 +82,7 @@ If applicable, add screenshots or recordings.
### Environment
- Superset version: [e.g., 3.0.0]
- Python version: [e.g., 3.11.7]
- Python version: [e.g., 3.9.7]
- Node version: [e.g., 18.17.0]
- Database: [e.g., PostgreSQL 14]
- Browser: [e.g., Chrome 120]
@@ -125,7 +125,7 @@ No error messages in browser console or server logs.
### Environment
- Superset version: 3.0.0
- Python version: 3.11.16
- Python version: 3.9.16
- Database: PostgreSQL 14.9
- Browser: Chrome 120.0.6099.71
- OS: macOS 14.2

View File

@@ -52,7 +52,7 @@ Everything you need to contribute to the Apache Superset project. This section i
## Development Resources
### Prerequisites
- **Python**: 3.11 or 3.12
- **Python**: 3.9, 3.10, or 3.11
- **Node.js**: 18.x or 20.x
- **npm**: 9.x or 10.x
- **Git**: Basic understanding

View File

@@ -44,12 +44,12 @@
},
"dependencies": {
"@ant-design/icons": "^6.2.5",
"@docusaurus/core": "^3.10.2",
"@docusaurus/faster": "^3.10.2",
"@docusaurus/plugin-client-redirects": "^3.10.2",
"@docusaurus/preset-classic": "3.10.2",
"@docusaurus/theme-live-codeblock": "^3.10.2",
"@docusaurus/theme-mermaid": "^3.10.2",
"@docusaurus/core": "^3.10.1",
"@docusaurus/faster": "^3.10.1",
"@docusaurus/plugin-client-redirects": "^3.10.1",
"@docusaurus/preset-classic": "3.10.1",
"@docusaurus/theme-live-codeblock": "^3.10.1",
"@docusaurus/theme-mermaid": "^3.10.1",
"@emotion/core": "^11.0.0",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.14.1",
@@ -58,14 +58,14 @@
"@fontsource/inter": "^5.2.8",
"@mdx-js/react": "^3.1.1",
"@saucelabs/theme-github-codeblock": "^0.3.0",
"@storybook/addon-docs": "^10.5.0",
"@storybook/addon-docs": "^10.4.5",
"@superset-ui/core": "^0.20.4",
"@swc/core": "^1.15.43",
"antd": "^6.5.1",
"baseline-browser-mapping": "^2.10.43",
"caniuse-lite": "^1.0.30001805",
"docusaurus-plugin-openapi-docs": "^5.1.2",
"docusaurus-theme-openapi-docs": "^5.1.2",
"antd": "^6.5.0",
"baseline-browser-mapping": "^2.10.40",
"caniuse-lite": "^1.0.30001799",
"docusaurus-plugin-openapi-docs": "^5.1.0",
"docusaurus-theme-openapi-docs": "^5.1.0",
"js-yaml": "^5.2.0",
"json-bigint": "^1.0.0",
"prism-react-renderer": "^2.4.1",
@@ -77,28 +77,28 @@
"react-table": "^7.8.0",
"remark-import-partial": "^0.0.2",
"reselect": "^5.2.0",
"storybook": "^10.5.0",
"storybook": "^10.4.5",
"swagger-ui-react": "^5.32.8",
"swc-loader": "^0.2.7",
"tinycolor2": "^1.4.2",
"unist-util-visit": "^5.1.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.10.2",
"@docusaurus/tsconfig": "^3.10.2",
"@docusaurus/module-type-aliases": "^3.10.1",
"@docusaurus/tsconfig": "^3.10.1",
"@eslint/js": "^9.39.2",
"@types/js-yaml": "^4.0.9",
"@types/react": "^19.1.8",
"@typescript-eslint/eslint-plugin": "^8.64.0",
"@typescript-eslint/parser": "^8.64.0",
"@typescript-eslint/eslint-plugin": "^8.59.3",
"@typescript-eslint/parser": "^8.61.0",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-react": "^7.37.5",
"globals": "^17.7.0",
"prettier": "^3.9.5",
"prettier": "^3.9.1",
"typescript": "~6.0.3",
"typescript-eslint": "^8.63.0",
"typescript-eslint": "^8.62.0",
"webpack": "^5.108.2"
},
"browserslist": {
@@ -124,6 +124,8 @@
"serialize-javascript": "7.0.5",
"d3-color": "3.1.0",
"ws": "^8.21.0",
"@docusaurus/core/@docusaurus/utils/gray-matter/js-yaml": "^3.15.0",
"@docusaurus/core/**/js-yaml": "^4.3.0",
"docusaurus-plugin-openapi-docs/**/js-yaml": "^4.3.0"
},
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"

View File

@@ -3672,7 +3672,7 @@
"drivers": [
{
"name": "crate",
"pypi_package": "sqlalchemy-cratedb",
"pypi_package": "crate[sqlalchemy]",
"connection_string": "crate://{host}:{port}",
"is_recommended": true
}

View File

@@ -291,7 +291,7 @@ This is the best source of information about the problem. In a docker compose d
### Check web browser and webdriver installation
To take a screenshot, the worker visits the dashboard or chart using a headless browser, then takes a screenshot. If you are able to send a chart as CSV, XLSX, or text but can't send as PNG, your problem may lie with the browser.
To take a screenshot, the worker visits the dashboard or chart using a headless browser, then takes a screenshot. If you are able to send a chart as CSV or text but can't send as PNG, your problem may lie with the browser.
Superset docker images that have a tag ending with `-dev` have the Firefox headless browser and geckodriver already installed. You can test that these are installed and in the proper path by entering your Superset worker and running `firefox --headless` and then `geckodriver`. Both commands should start those applications.

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ maintainers:
- name: craig-rueda
email: craig@craigrueda.com
url: https://github.com/craig-rueda
version: 0.22.0 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
version: 0.20.0 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
dependencies:
- name: postgresql
version: 16.7.27

View File

@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
# superset
![Version: 0.22.0](https://img.shields.io/badge/Version-0.22.0-informational?style=flat-square)
![Version: 0.20.0](https://img.shields.io/badge/Version-0.20.0-informational?style=flat-square)
Apache Superset is a modern, enterprise-ready business intelligence web application
@@ -125,13 +125,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| fullnameOverride | string | `nil` | Provide a name to override the full names of resources |
| globalPodAnnotations | object | `{}` | Global pod annotations to be added to all pods Use this to set annotations that apply to all Superset components Component-specific podAnnotations will be merged with these global annotations |
| hostAliases | list | `[]` | Custom hostAliases for all superset pods # https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ |
| httproute | object | see `values.yaml` | Gateway API HTTPRoute for exposing Superset via a Gateway. Requires the Gateway API CRDs (gateway.networking.k8s.io/v1) installed in the cluster. |
| httproute.annotations | object | `{}` | Annotations to add to the HTTPRoute |
| httproute.apiVersion | string | `"gateway.networking.k8s.io/v1"` | HTTPRoute apiVersion. Override to gateway.networking.k8s.io/v1beta1 for older Gateway API installations that have not promoted HTTPRoute to v1. |
| httproute.hostnames | list | `[]` | Hostnames that match against the HTTP Host header (templated) |
| httproute.labels | object | `{}` | Additional labels to add to the HTTPRoute |
| httproute.parentRefs | list | `[]` | Gateways this HTTPRoute attaches to |
| httproute.rules | list | `[{"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | Routing rules. Each rule is backed by the Superset service. Set `weight` per rule to leave room for traffic splitting (defaults to 1). When `supersetWebsockets.enabled` is true, an extra rule routing `supersetWebsockets.ingress.path` to the `-ws` service is appended automatically, mirroring the ingress behavior. |
| image.pullPolicy | string | `"IfNotPresent"` | |
| image.repository | string | `"apachesuperset.docker.scarf.sh/apache/superset"` | |
| image.tag | string | `nil` | |
@@ -156,7 +149,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| init.createAdmin | bool | `true` | |
| init.enabled | bool | `true` | |
| init.extraContainers | list | `[]` | Launch additional containers into init job pod |
| init.extraInitContainers | list | `[]` | Extra init containers appended after init job initContainers |
| init.initContainers | list | a container waiting for postgres | List of initContainers |
| init.initscript | string | unused; kept for backwards-compatibility only | DEPRECATED: this field is no longer used by the chart. The init script is rendered entirely from the internal `superset.initScript` template (which runs `superset db upgrade`, `superset init`, admin creation, and examples). Any customization placed here is silently ignored. See UPGRADING.md. |
| init.jobAnnotations."helm.sh/hook" | string | `"post-install,post-upgrade"` | |
@@ -194,7 +186,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetCeleryBeat.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat deployment |
| supersetCeleryBeat.enabled | bool | `false` | This is only required if you intend to use alerts and reports |
| supersetCeleryBeat.extraContainers | list | `[]` | Launch additional containers into supersetCeleryBeat pods |
| supersetCeleryBeat.extraInitContainers | list | `[]` | Extra init containers appended after supersetCeleryBeat initContainers |
| supersetCeleryBeat.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetCeleryBeat.initContainers | list | a container waiting for postgres | List of init containers |
| supersetCeleryBeat.podAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat pods |
@@ -214,7 +205,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetCeleryFlower.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryFlower deployment |
| supersetCeleryFlower.enabled | bool | `false` | Enables a Celery flower deployment (management UI to monitor celery jobs) WARNING: on superset 1.x, this requires a Superset image that has `flower<1.0.0` installed (which is NOT the case of the default images) flower>=1.0.0 requires Celery 5+ which Superset 1.5 does not support |
| supersetCeleryFlower.extraContainers | list | `[]` | Launch additional containers into supersetCeleryFlower pods |
| supersetCeleryFlower.extraInitContainers | list | `[]` | Extra init containers appended after supersetCeleryFlower initContainers |
| supersetCeleryFlower.initContainers | list | a container waiting for postgres and redis | List of init containers |
| supersetCeleryFlower.livenessProbe.failureThreshold | int | `3` | |
| supersetCeleryFlower.livenessProbe.httpGet.path | string | `"/api/workers"` | |
@@ -253,60 +243,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetCeleryFlower.startupProbe.successThreshold | int | `1` | |
| supersetCeleryFlower.startupProbe.timeoutSeconds | int | `1` | |
| supersetCeleryFlower.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryFlower deployments |
| supersetMcp.affinity | object | `{}` | Affinity to be added to supersetMcp deployment |
| supersetMcp.command | list | a `superset mcp run` command | Command |
| supersetMcp.containerSecurityContext | object | `{}` | |
| supersetMcp.deploymentAdditionalPodSpec | object | `{}` | Custom pod spec to be added to supersetMcp deployment |
| supersetMcp.deploymentAnnotations | object | `{}` | Annotations to be added to supersetMcp deployment |
| supersetMcp.deploymentLabels | object | `{}` | Labels to be added to supersetMcp deployment |
| supersetMcp.enabled | bool | `false` | Enables the Superset MCP Server. To expose it via the shared ingress at /mcp, also set supersetMcp.ingress.enabled=true. WARNING: this requires fastMCP to be installed, which can be done by installing `apache-superset[fastmcp]` |
| supersetMcp.extraContainers | list | `[]` | Launch additional containers into supersetMcp pods |
| supersetMcp.extraInitContainers | list | `[]` | Extra init containers appended after supersetMcp initContainers |
| supersetMcp.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetMcp.ingress.enabled | bool | `false` | If true, the MCP server will be exposed via the ingress /mcp subpath |
| supersetMcp.ingress.path | string | `"/mcp"` | |
| supersetMcp.ingress.pathType | string | `"Prefix"` | |
| supersetMcp.initContainers | list | a container waiting for postgres and redis | List of init containers |
| supersetMcp.lifecycle | object | `{}` | Container lifecycle hooks for the worker pod |
| supersetMcp.livenessProbe.failureThreshold | int | `3` | |
| supersetMcp.livenessProbe.httpGet.path | string | `"/health"` | |
| supersetMcp.livenessProbe.httpGet.port | string | `"mcp"` | |
| supersetMcp.livenessProbe.initialDelaySeconds | int | `15` | |
| supersetMcp.livenessProbe.periodSeconds | int | `15` | |
| supersetMcp.livenessProbe.successThreshold | int | `1` | |
| supersetMcp.livenessProbe.timeoutSeconds | int | `3` | |
| supersetMcp.podAnnotations | object | `{}` | Annotations to be added to supersetMcp pods |
| supersetMcp.podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":1}` | Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for supersetMcp pods |
| supersetMcp.podDisruptionBudget.enabled | bool | `false` | Whether the pod disruption budget should be created |
| supersetMcp.podDisruptionBudget.maxUnavailable | int | `1` | If set, minAvailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget |
| supersetMcp.podDisruptionBudget.minAvailable | int | `1` | If set, maxUnavailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget |
| supersetMcp.podLabels | object | `{}` | Labels to be added to supersetMcp pods |
| supersetMcp.podSecurityContext | object | `{}` | |
| supersetMcp.priorityClassName | string | `nil` | Set priorityClassName for supersetMcp pods |
| supersetMcp.readinessProbe.failureThreshold | int | `3` | |
| supersetMcp.readinessProbe.httpGet.path | string | `"/health"` | |
| supersetMcp.readinessProbe.httpGet.port | string | `"mcp"` | |
| supersetMcp.readinessProbe.initialDelaySeconds | int | `15` | |
| supersetMcp.readinessProbe.periodSeconds | int | `15` | |
| supersetMcp.readinessProbe.successThreshold | int | `1` | |
| supersetMcp.readinessProbe.timeoutSeconds | int | `3` | |
| supersetMcp.replicaCount | int | `1` | |
| supersetMcp.resources | object | `{}` | Resource settings for the supersetMcp pods - these settings overwrite might existing values from the global resources object defined above. |
| supersetMcp.service.annotations | object | `{}` | |
| supersetMcp.service.loadBalancerIP | string | `nil` | |
| supersetMcp.service.nodePort.http | int | `"nil"` | |
| supersetMcp.service.port | int | `5008` | |
| supersetMcp.service.type | string | `"ClusterIP"` | |
| supersetMcp.startupProbe.failureThreshold | int | `60` | |
| supersetMcp.startupProbe.httpGet.path | string | `"/health"` | |
| supersetMcp.startupProbe.httpGet.port | string | `"mcp"` | |
| supersetMcp.startupProbe.initialDelaySeconds | int | `15` | |
| supersetMcp.startupProbe.periodSeconds | int | `5` | |
| supersetMcp.startupProbe.successThreshold | int | `1` | |
| supersetMcp.startupProbe.timeoutSeconds | int | `3` | |
| supersetMcp.strategy | object | `{}` | |
| supersetMcp.terminationGracePeriodSeconds | string | `nil` | Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL |
| supersetMcp.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetMcp deployments |
| supersetNode.affinity | object | `{}` | Affinity to be added to supersetNode deployment |
| supersetNode.autoscaling.enabled | bool | `false` | |
| supersetNode.autoscaling.maxReplicas | int | `100` | |
@@ -320,7 +256,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetNode.deploymentLabels | object | `{}` | Labels to be added to supersetNode deployment |
| supersetNode.env | object | `{}` | |
| supersetNode.extraContainers | list | `[]` | Launch additional containers into supersetNode pod |
| supersetNode.extraInitContainers | list | `[]` | Extra init containers appended after supersetNode initContainers |
| supersetNode.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetNode.initContainers | list | a container waiting for postgres | Init containers |
| supersetNode.lifecycle | object | `{}` | Container lifecycle hooks, e.g. a preStop sleep so the Service/Ingress stops routing to the pod before gunicorn receives SIGTERM |
@@ -366,13 +301,11 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetWebsockets.deploymentAnnotations | object | `{}` | |
| supersetWebsockets.enabled | bool | `false` | This is only required if you intend to use `GLOBAL_ASYNC_QUERIES` in `ws` mode see https://superset.apache.org/docs/contributing/misc#async-chart-queries |
| supersetWebsockets.extraContainers | list | `[]` | Launch additional containers into supersetWebsockets pods |
| supersetWebsockets.extraInitContainers | list | `[]` | Extra init containers appended after supersetWebsockets initContainers |
| supersetWebsockets.image.pullPolicy | string | `"IfNotPresent"` | |
| supersetWebsockets.image.repository | string | `"oneacrefund/superset-websocket"` | There is no official image (yet), this one is community-supported |
| supersetWebsockets.image.tag | string | `"latest"` | |
| supersetWebsockets.ingress.path | string | `"/ws"` | |
| supersetWebsockets.ingress.pathType | string | `"Prefix"` | |
| supersetWebsockets.initContainers | list | a container waiting for redis | List of initContainers |
| supersetWebsockets.livenessProbe.failureThreshold | int | `3` | |
| supersetWebsockets.livenessProbe.httpGet.path | string | `"/health"` | |
| supersetWebsockets.livenessProbe.httpGet.port | string | `"ws"` | |
@@ -422,7 +355,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetWorker.deploymentAnnotations | object | `{}` | Annotations to be added to supersetWorker deployment |
| supersetWorker.deploymentLabels | object | `{}` | Labels to be added to supersetWorker deployment |
| supersetWorker.extraContainers | list | `[]` | Launch additional containers into supersetWorker pod |
| supersetWorker.extraInitContainers | list | `[]` | Extra init containers appended after supersetWorker initContainers |
| supersetWorker.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetWorker.healthCheck | object | `{"enabled":false,"livenessFile":"/tmp/celery_worker_alive","livenessHeartbeatInterval":10,"readinessFile":"/tmp/celery_worker_ready"}` | Celery worker file-based health check (worker writes readiness/liveness files via signals; point supersetWorker.readinessProbe/livenessProbe at these files to use them) |
| supersetWorker.healthCheck.enabled | bool | `false` | Enable the file-based Celery worker health check |

View File

@@ -761,9 +761,3 @@ app.kubernetes.io/name: {{ include "superset.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: worker
{{- end }}
{{- define "supersetMcp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "superset.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: mcp
{{- end }}

View File

@@ -75,14 +75,8 @@ spec:
{{- if .Values.supersetCeleryBeat.podSecurityContext }}
{{- toYaml .Values.supersetCeleryBeat.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetCeleryBeat.initContainers .Values.supersetCeleryBeat.extraInitContainers }}
initContainers:
{{- if .Values.supersetCeleryBeat.initContainers }}
{{- tpl (toYaml .Values.supersetCeleryBeat.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetCeleryBeat.extraInitContainers }}
{{- tpl (toYaml .Values.supersetCeleryBeat.extraInitContainers) . | nindent 6 }}
{{- end }}
initContainers: {{- tpl (toYaml .Values.supersetCeleryBeat.initContainers) . | nindent 6 }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}

View File

@@ -61,14 +61,8 @@ spec:
{{- if .Values.supersetCeleryFlower.podSecurityContext }}
{{- toYaml .Values.supersetCeleryFlower.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetCeleryFlower.initContainers .Values.supersetCeleryFlower.extraInitContainers }}
initContainers:
{{- if .Values.supersetCeleryFlower.initContainers }}
{{- tpl (toYaml .Values.supersetCeleryFlower.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetCeleryFlower.extraInitContainers }}
{{- tpl (toYaml .Values.supersetCeleryFlower.extraInitContainers) . | nindent 6 }}
{{- end }}
initContainers: {{- tpl (toYaml .Values.supersetCeleryFlower.initContainers) . | nindent 6 }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}

View File

@@ -1,197 +0,0 @@
{{/*
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.
*/}}
{{- if .Values.supersetMcp.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "superset.fullname" . }}-mcp
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.componentLabels" (dict "component" "mcp" "root" .) | nindent 4 }}
{{- if .Values.supersetMcp.deploymentAnnotations }}
annotations: {{- toYaml .Values.supersetMcp.deploymentAnnotations | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.supersetMcp.replicaCount }}
selector:
matchLabels:
{{- include "supersetMcp.selectorLabels" . | nindent 6 }}
{{- if .Values.supersetMcp.strategy }}
strategy: {{- toYaml .Values.supersetMcp.strategy | nindent 4 }}
{{- end }}
template:
metadata:
annotations:
checksum/superset_config.py: {{ include "superset.config" . | sha256sum }}
checksum/superset_bootstrap.sh: {{ tpl .Values.bootstrapScript . | sha256sum }}
checksum/database: {{ .Values.database | toYaml | sha256sum }}
checksum/redis: {{ .Values.cache | toYaml | sha256sum }}
checksum/config: {{ .Values.config | toYaml | sha256sum }}
checksum/featureFlags: {{ .Values.featureFlags | toYaml | sha256sum }}
checksum/extraConfigs: {{ .Values.extraConfigs | toYaml | sha256sum }}
checksum/extraSecrets: {{ .Values.extraSecrets | toYaml | sha256sum }}
checksum/extraSecretEnv: {{ .Values.extraSecretEnv | toYaml | sha256sum }}
checksum/configOverrides: {{ .Values.configOverrides | toYaml | sha256sum }}
checksum/configOverridesFiles: {{ .Values.configOverridesFiles | toYaml | sha256sum }}
{{- if .Values.supersetMcp.forceReload }}
# Optionally force the thing to reload
force-reload: {{ randAlphaNum 5 | quote }}
{{- end }}
{{- if .Values.supersetMcp.podAnnotations }}
{{- toYaml .Values.supersetMcp.podAnnotations | nindent 8 }}
{{- end }}
{{- with .Values.globalPodAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "supersetMcp.selectorLabels" . | nindent 8 }}
{{- if .Values.supersetMcp.podLabels }}
{{- toYaml .Values.supersetMcp.podLabels | nindent 8 }}
{{- end }}
spec:
{{- if .Values.supersetMcp.deploymentAdditionalPodSpec }}
{{- tpl (toYaml .Values.supersetMcp.deploymentAdditionalPodSpec) . | nindent 6 }}
{{- end }}
{{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }}
serviceAccountName: {{ template "superset.serviceAccountName" . }}
{{- end }}
securityContext:
runAsUser: {{ .Values.runAsUser }}
{{- if .Values.supersetMcp.podSecurityContext }}
{{- toYaml .Values.supersetMcp.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetMcp.initContainers .Values.supersetMcp.extraInitContainers }}
initContainers:
{{- if .Values.supersetMcp.initContainers }}
{{- tpl (toYaml .Values.supersetMcp.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetMcp.extraInitContainers }}
{{- tpl (toYaml .Values.supersetMcp.extraInitContainers) . | nindent 6 }}
{{- end }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}
{{- end }}
containers:
- name: "{{ .Chart.Name }}-mcp"
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.supersetMcp.containerSecurityContext }}
securityContext: {{- toYaml .Values.supersetMcp.containerSecurityContext | nindent 12 }}
{{- end }}
command: {{ tpl (toJson .Values.supersetMcp.command) . }}
env:
{{- range $key, $value := .Values.extraEnv }}
- name: {{ $key | quote}}
value: {{ $value | quote }}
{{- end }}
{{- if .Values.extraEnvRaw }}
{{- toYaml .Values.extraEnvRaw | nindent 12 }}
{{- end }}
envFrom:
- secretRef:
name: {{ tpl .Values.envFromSecret . | quote }}
{{- range .Values.envFromSecrets }}
- secretRef:
name: {{ tpl . $ | quote }}
{{- end }}
ports:
- name: mcp
containerPort: {{ .Values.supersetMcp.service.port }}
protocol: TCP
volumeMounts:
- name: superset-config
mountPath: {{ .Values.configMountPath | quote }}
readOnly: true
{{- if .Values.extraConfigs }}
- name: superset-extra-config
mountPath: {{ .Values.extraConfigMountPath | quote }}
readOnly: true
{{- end }}
{{- with .Values.extraVolumeMounts }}
{{- tpl (toYaml .) $ | nindent 12 -}}
{{- end }}
{{- if .Values.supersetMcp.startupProbe }}
startupProbe: {{- .Values.supersetMcp.startupProbe | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.readinessProbe }}
readinessProbe: {{- .Values.supersetMcp.readinessProbe | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.livenessProbe }}
livenessProbe: {{- .Values.supersetMcp.livenessProbe | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.lifecycle }}
lifecycle: {{- .Values.supersetMcp.lifecycle | toYaml | nindent 12 }}
{{- end }}
resources:
{{- if .Values.supersetMcp.resources }}
{{- toYaml .Values.supersetMcp.resources | nindent 12 }}
{{- else }}
{{- toYaml .Values.resources | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.extraContainers }}
{{- tpl (toYaml .Values.supersetMcp.extraContainers) . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }}
{{- end }}
{{- if or .Values.affinity .Values.supersetMcp.affinity }}
affinity:
{{- with .Values.affinity }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.supersetMcp.affinity }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.supersetMcp.priorityClassName }}
priorityClassName: {{ .Values.supersetMcp.priorityClassName }}
{{- end }}
{{- if or .Values.topologySpreadConstraints .Values.supersetMcp.topologySpreadConstraints }}
topologySpreadConstraints:
{{- with .Values.topologySpreadConstraints }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.supersetMcp.topologySpreadConstraints }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.tolerations }}
tolerations: {{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.supersetMcp.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.supersetMcp.terminationGracePeriodSeconds }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
{{- end }}
volumes:
- name: superset-config
secret:
secretName: {{ tpl .Values.configFromSecret . }}
{{- if .Values.extraConfigs }}
- name: superset-extra-config
configMap:
name: {{ template "superset.fullname" . }}-extra-config
{{- end }}
{{- with .Values.extraVolumes }}
{{- tpl (toYaml .) $ | nindent 8 -}}
{{- end }}
{{- end -}}

View File

@@ -81,14 +81,8 @@ spec:
{{- if .Values.supersetWorker.podSecurityContext }}
{{- toYaml .Values.supersetWorker.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetWorker.initContainers .Values.supersetWorker.extraInitContainers }}
initContainers:
{{- if .Values.supersetWorker.initContainers }}
{{- tpl (toYaml .Values.supersetWorker.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetWorker.extraInitContainers }}
{{- tpl (toYaml .Values.supersetWorker.extraInitContainers) . | nindent 6 }}
{{- end }}
initContainers: {{- tpl (toYaml .Values.supersetWorker.initContainers) . | nindent 6 }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}

View File

@@ -64,15 +64,6 @@ spec:
{{- if .Values.supersetWebsockets.podSecurityContext }}
{{- toYaml .Values.supersetWebsockets.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetWebsockets.initContainers .Values.supersetWebsockets.extraInitContainers }}
initContainers:
{{- if .Values.supersetWebsockets.initContainers }}
{{- tpl (toYaml .Values.supersetWebsockets.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetWebsockets.extraInitContainers }}
{{- tpl (toYaml .Values.supersetWebsockets.extraInitContainers) . | nindent 6 }}
{{- end }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}
{{- end }}

View File

@@ -83,14 +83,8 @@ spec:
{{- if .Values.supersetNode.podSecurityContext }}
{{- toYaml .Values.supersetNode.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetNode.initContainers .Values.supersetNode.extraInitContainers }}
initContainers:
{{- if .Values.supersetNode.initContainers }}
{{- tpl (toYaml .Values.supersetNode.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetNode.extraInitContainers }}
{{- tpl (toYaml .Values.supersetNode.extraInitContainers) . | nindent 6 }}
{{- end }}
initContainers: {{- tpl (toYaml .Values.supersetNode.initContainers) . | nindent 6 }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}

View File

@@ -1,83 +0,0 @@
{{/*
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.
*/}}
{{- if .Values.httproute.enabled -}}
{{- $fullName := include "superset.fullname" . -}}
apiVersion: {{ .Values.httproute.apiVersion | default "gateway.networking.k8s.io/v1" }}
kind: HTTPRoute
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "superset.name" . }}
chart: {{ template "superset.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- if .Values.extraLabels }}
{{- toYaml .Values.extraLabels | nindent 4 }}
{{- end }}
{{- with .Values.httproute.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httproute.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.httproute.parentRefs }}
parentRefs:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httproute.hostnames }}
hostnames:
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
rules:
{{- range .Values.httproute.rules }}
- backendRefs:
- group: ''
kind: Service
name: {{ $fullName }}
port: {{ $.Values.service.port }}
weight: {{ .weight | default 1 }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .matches }}
matches:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .timeouts }}
timeouts:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.supersetWebsockets.enabled }}
- backendRefs:
- group: ''
kind: Service
name: {{ $fullName }}-ws
port: {{ .Values.supersetWebsockets.service.port }}
weight: 1
matches:
- path:
type: PathPrefix
value: {{ .Values.supersetWebsockets.ingress.path }}
{{- end }}
{{- end }}

View File

@@ -64,15 +64,6 @@ spec:
port:
name: ws
{{- end }}
{{- if and $.Values.supersetMcp.enabled $.Values.supersetMcp.ingress.enabled }}
- path: {{ $.Values.supersetMcp.ingress.path }}
pathType: {{ $.Values.supersetMcp.ingress.pathType }}
backend:
service:
name: "{{ template "superset.fullname" $ }}-mcp"
port:
name: mcp
{{- end }}
{{- end }}
{{- if .Values.ingress.extraHostsRaw }}
{{- toYaml .Values.ingress.extraHostsRaw | nindent 4 }}

View File

@@ -56,14 +56,8 @@ spec:
{{- if .Values.init.podSecurityContext }}
{{- toYaml .Values.init.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.init.initContainers .Values.init.extraInitContainers }}
initContainers:
{{- if .Values.init.initContainers }}
{{- tpl (toYaml .Values.init.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.init.extraInitContainers }}
{{- tpl (toYaml .Values.init.extraInitContainers) . | nindent 6 }}
{{- end }}
initContainers: {{- tpl (toYaml .Values.init.initContainers) . | nindent 6 }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}

View File

@@ -1,42 +0,0 @@
{{/*
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.
*/}}
{{- with .Values.supersetMcp.podDisruptionBudget }}
{{- if .enabled -}}
{{- if and .minAvailable .maxUnavailable }}
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
{{- end}}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "superset.fullname" $ }}-mcp-pdb
labels:
{{- include "superset.componentLabels" (dict "component" "mcp" "root" $) | nindent 4 }}
spec:
{{- if .minAvailable }}
minAvailable: {{ .minAvailable }}
{{- end }}
{{- if .maxUnavailable }}
maxUnavailable: {{ .maxUnavailable }}
{{- end }}
selector:
matchLabels:
{{- include "supersetMcp.selectorLabels" $ | nindent 6 }}
{{- end }}
{{- end }}

View File

@@ -1,46 +0,0 @@
{{/*
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.
*/}}
{{- if .Values.supersetMcp.enabled }}
apiVersion: v1
kind: Service
metadata:
name: "{{ template "superset.fullname" . }}-mcp"
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.componentLabels" (dict "component" "mcp" "root" .) | nindent 4 }}
{{- with .Values.supersetMcp.service.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.supersetMcp.service.type }}
ports:
- port: {{ .Values.supersetMcp.service.port }}
targetPort: mcp
protocol: TCP
name: mcp
{{- if and (or (eq .Values.supersetMcp.service.type "NodePort") (eq .Values.supersetMcp.service.type "LoadBalancer")) (not (empty .Values.supersetMcp.service.nodePort.http)) }}
nodePort: {{ .Values.supersetMcp.service.nodePort.http }}
{{- end }}
selector:
{{- include "supersetMcp.selectorLabels" . | nindent 4 }}
{{- if .Values.supersetMcp.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.supersetMcp.service.loadBalancerIP }}
{{- end }}
{{- end }}

View File

@@ -21,7 +21,6 @@ templates:
- deployment-beat.yaml
- deployment-flower.yaml
- deployment-ws.yaml
- deployment-mcp.yaml
tests:
- it: main deployment has new config checksums, not the old connections checksum
template: deployment.yaml
@@ -131,24 +130,3 @@ tests:
- equal:
path: 'spec.template.metadata.annotations.team'
value: data
- it: mcp deployment has config and database checksums
template: deployment-mcp.yaml
set:
supersetMcp:
enabled: true
asserts:
- exists:
path: 'spec.template.metadata.annotations["checksum/database"]'
- exists:
path: 'spec.template.metadata.annotations["checksum/config"]'
- it: mcp deployment applies globalPodAnnotations
template: deployment-mcp.yaml
set:
supersetMcp:
enabled: true
globalPodAnnotations:
team: data
asserts:
- equal:
path: 'spec.template.metadata.annotations.team'
value: data

View File

@@ -1,206 +0,0 @@
#
# 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.
#
suite: init containers + extraInitContainers
templates:
- deployment.yaml
- deployment-worker.yaml
- deployment-beat.yaml
- deployment-flower.yaml
- deployment-ws.yaml
- deployment-mcp.yaml
- init-job.yaml
tests:
- it: renders only the default wait-for container by default
template: deployment.yaml
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 1
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres
- it: appends extraInitContainers after the default initContainers
template: deployment.yaml
set:
supersetNode.extraInitContainers:
- name: prepare-assets
image: busybox
command: ["sh", "-c", "echo preparing"]
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: templates values inside extraInitContainers
template: deployment.yaml
set:
image.repository: example/superset
supersetNode.extraInitContainers:
- name: prepare-assets
image: "{{ .Values.image.repository }}:test"
asserts:
- equal:
path: spec.template.spec.initContainers[1].image
value: example/superset:test
- it: keeps replace semantics for initContainers while appending extras
template: deployment.yaml
set:
supersetNode.initContainers:
- name: custom-wait
image: busybox
supersetNode.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: custom-wait
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: renders only extras when initContainers is cleared
template: deployment.yaml
set:
supersetNode.initContainers: []
supersetNode.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 1
- equal:
path: spec.template.spec.initContainers[0].name
value: prepare-assets
- it: appends worker extraInitContainers after wait-for-postgres-redis
template: deployment-worker.yaml
set:
supersetWorker.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends beat extraInitContainers after wait-for-postgres-redis
template: deployment-beat.yaml
set:
supersetCeleryBeat.enabled: true
supersetCeleryBeat.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends flower extraInitContainers after wait-for-postgres-redis
template: deployment-flower.yaml
set:
supersetCeleryFlower.enabled: true
supersetCeleryFlower.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends websockets extraInitContainers after wait-for-redis
template: deployment-ws.yaml
set:
supersetWebsockets.enabled: true
supersetWebsockets.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends mcp extraInitContainers after wait-for-postgres-redis
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
supersetMcp.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends init job extraInitContainers after wait-for-postgres
template: init-job.yaml
set:
init.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets

View File

@@ -21,11 +21,9 @@ templates:
- deployment-beat.yaml
- deployment-flower.yaml
- deployment-ws.yaml
- deployment-mcp.yaml
- service.yaml
- service-ws.yaml
- service-flower.yaml
- service-mcp.yaml
- init-job.yaml
- ingress.yaml
- configmap-superset.yaml
@@ -36,7 +34,6 @@ templates:
- pdb-beat.yaml
- pdb-flower.yaml
- pdb-ws.yaml
- pdb-mcp.yaml
# These tests validate that Kubernetes recommended labels are consistently applied
# across all chart resources per https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
@@ -188,36 +185,6 @@ tests:
path: metadata.labels["app.kubernetes.io/component"]
value: websocket
# =============================================================================
# MCP Deployment Labels
# =============================================================================
- it: should have all recommended labels on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- isNotNull:
path: metadata.labels["app.kubernetes.io/name"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/instance"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/version"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/managed-by"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/part-of"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/component"]
- it: should have correct component label on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: mcp
# =============================================================================
# Service Labels
# =============================================================================
@@ -282,27 +249,6 @@ tests:
path: metadata.labels["app.kubernetes.io/component"]
value: flower
- it: should have all recommended labels on mcp service
template: service-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- isNotNull:
path: metadata.labels["app.kubernetes.io/name"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/instance"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/component"]
- it: should have correct component label on mcp service
template: service-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: mcp
# =============================================================================
# Init Job Labels
# =============================================================================
@@ -420,51 +366,6 @@ tests:
path: spec.template.metadata.labels["app.kubernetes.io/component"]
value: worker
- it: should set selector matchLabels to concrete values on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/name"]
value: superset
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/component"]
value: mcp
- it: should match pod template labels to the selector on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: spec.template.metadata.labels["app.kubernetes.io/name"]
value: superset
- equal:
path: spec.template.metadata.labels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.template.metadata.labels["app.kubernetes.io/component"]
value: mcp
- it: should set selector to concrete values on mcp service
template: service-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: spec.selector["app.kubernetes.io/name"]
value: superset
- equal:
path: spec.selector["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.selector["app.kubernetes.io/component"]
value: mcp
# =============================================================================
# Extra Labels Support
# =============================================================================
@@ -604,26 +505,6 @@ tests:
path: spec.selector.matchLabels["app.kubernetes.io/component"]
value: websocket
- it: should have recommended labels and matching selector on mcp pdb
template: pdb-mcp.yaml
set:
supersetMcp.enabled: true
supersetMcp.podDisruptionBudget.enabled: true
supersetMcp.podDisruptionBudget.maxUnavailable: null
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: mcp
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/component"]
value: mcp
- it: should use recommended labels on init job pod template
template: init-job.yaml
set:

View File

@@ -246,40 +246,6 @@ ingress:
# hosts:
# - chart-example.local
# -- Gateway API HTTPRoute for exposing Superset via a Gateway.
# Requires the Gateway API CRDs (gateway.networking.k8s.io/v1) installed in the cluster.
# @default -- see `values.yaml`
httproute:
enabled: false
# -- HTTPRoute apiVersion. Override to gateway.networking.k8s.io/v1beta1 for
# older Gateway API installations that have not promoted HTTPRoute to v1.
apiVersion: gateway.networking.k8s.io/v1
# -- Additional labels to add to the HTTPRoute
labels: {}
# -- Annotations to add to the HTTPRoute
annotations: {}
# -- Gateways this HTTPRoute attaches to
parentRefs: []
# - name: my-gateway
# namespace: gateway-system
# sectionName: https
# -- Hostnames that match against the HTTP Host header (templated)
hostnames: []
# - chart-example.local
# -- Routing rules. Each rule is backed by the Superset service. Set `weight`
# per rule to leave room for traffic splitting (defaults to 1). When
# `supersetWebsockets.enabled` is true, an extra rule routing
# `supersetWebsockets.ingress.path` to the `-ws` service is appended
# automatically, mirroring the ingress behavior.
rules:
- matches:
- path:
type: PathPrefix
value: /
# weight: 1
# filters: []
# timeouts: {}
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
@@ -449,8 +415,6 @@ supersetNode:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetNode initContainers
extraInitContainers: []
# -- Launch additional containers into supersetNode pod
extraContainers: []
# -- Annotations to be added to supersetNode deployment
@@ -578,8 +542,6 @@ supersetWorker:
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetWorker initContainers
extraInitContainers: []
# -- Launch additional containers into supersetWorker pod
extraContainers: []
# -- Annotations to be added to supersetWorker deployment
@@ -701,8 +663,6 @@ supersetCeleryBeat:
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetCeleryBeat initContainers
extraInitContainers: []
# -- Launch additional containers into supersetCeleryBeat pods
extraContainers: []
# -- Annotations to be added to supersetCeleryBeat deployment
@@ -820,8 +780,6 @@ supersetCeleryFlower:
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetCeleryFlower initContainers
extraInitContainers: []
# -- Launch additional containers into supersetCeleryFlower pods
extraContainers: []
# -- Annotations to be added to supersetCeleryFlower deployment
@@ -901,38 +859,6 @@ supersetWebsockets:
# -- (int)
http: nil
command: []
# -- List of initContainers
# @default -- a container waiting for redis
initContainers:
- name: wait-for-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
envFrom:
- secretRef:
name: "{{ tpl .Values.envFromSecret . }}"
command:
- /bin/bash
- -c
- |
# See supersetNode.initContainers for the rationale.
SECONDS=0
until (exec 3<>/dev/tcp/"$REDIS_HOST"/"$REDIS_PORT") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for redis at $REDIS_HOST:$REDIS_PORT after 120s" >&2
exit 1
fi
echo "waiting for redis at $REDIS_HOST:$REDIS_PORT (elapsed ${SECONDS}s)"
sleep 2
done
echo "redis at $REDIS_HOST:$REDIS_PORT is up"
resources:
limits:
memory: "256Mi"
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetWebsockets initContainers
extraInitContainers: []
resources: {}
# -- Launch additional containers into supersetWebsockets pods
extraContainers: []
@@ -978,144 +904,6 @@ supersetWebsockets:
# -- Set priorityClassName for supersetWebsockets pods
priorityClassName: ~
supersetMcp:
# -- Enables the Superset MCP Server. To expose it via the shared ingress at /mcp,
# also set supersetMcp.ingress.enabled=true.
# WARNING: this requires fastMCP to be installed, which can be done by installing `apache-superset[fastmcp]`
enabled: false
replicaCount: 1
# -- Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for supersetMcp pods
podDisruptionBudget:
# -- Whether the pod disruption budget should be created
enabled: false
# -- If set, maxUnavailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget
minAvailable: 1
# -- If set, minAvailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget
maxUnavailable: 1
# -- Command
# @default -- a `superset mcp run` command
command:
- "/bin/sh"
- "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; superset mcp run --host 0.0.0.0 --port {{ .Values.supersetMcp.service.port }}"
# -- If true, forces deployment to reload on each upgrade
forceReload: false
ingress:
# -- If true, the MCP server will be exposed via the ingress /mcp subpath
enabled: false
path: /mcp
pathType: Prefix
service:
type: ClusterIP
annotations: {}
loadBalancerIP: ~
port: 5008
nodePort:
# -- (int)
http: nil
startupProbe:
httpGet:
path: /health
port: mcp
initialDelaySeconds: 15
timeoutSeconds: 3
failureThreshold: 60
periodSeconds: 5
successThreshold: 1
livenessProbe:
httpGet:
path: /health
port: mcp
initialDelaySeconds: 15
timeoutSeconds: 3
failureThreshold: 3
periodSeconds: 15
successThreshold: 1
readinessProbe:
httpGet:
path: /health
port: mcp
initialDelaySeconds: 15
timeoutSeconds: 3
failureThreshold: 3
periodSeconds: 15
successThreshold: 1
# -- List of init containers
# @default -- a container waiting for postgres and redis
initContainers:
- name: wait-for-postgres-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
envFrom:
- secretRef:
name: "{{ tpl .Values.envFromSecret . }}"
command:
- /bin/bash
- -c
- |
# See supersetNode.initContainers for the rationale.
SECONDS=0
wait_for() {
local host=$1 port=$2 name=$3
until (exec 3<>/dev/tcp/"$host"/"$port") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for $name at $host:$port after 120s" >&2
exit 1
fi
echo "waiting for $name at $host:$port (elapsed ${SECONDS}s)"
sleep 2
done
echo "$name at $host:$port is up"
}
wait_for "$DB_HOST" "$DB_PORT" postgres
wait_for "$REDIS_HOST" "$REDIS_PORT" redis
resources:
limits:
memory: "256Mi"
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetMcp initContainers
extraInitContainers: []
# -- Launch additional containers into supersetMcp pods
extraContainers: []
# -- Annotations to be added to supersetMcp deployment
deploymentAnnotations: {}
# -- Labels to be added to supersetMcp deployment
deploymentLabels: {}
# -- Custom pod spec to be added to supersetMcp deployment
deploymentAdditionalPodSpec: {}
# -- Affinity to be added to supersetMcp deployment
affinity: {}
# -- TopologySpreadConstrains to be added to supersetMcp deployments
topologySpreadConstraints: []
# -- Annotations to be added to supersetMcp pods
podAnnotations: {}
# -- Labels to be added to supersetMcp pods
podLabels: {}
strategy: {}
# type: RollingUpdate
# rollingUpdate:
# maxSurge: 25%
# maxUnavailable: 25%
# -- Container lifecycle hooks for the worker pod
lifecycle: {}
# -- Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL
terminationGracePeriodSeconds: ~
# -- Resource settings for the supersetMcp pods - these settings overwrite might existing values from the global resources object defined above.
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
podSecurityContext: {}
containerSecurityContext: {}
# -- Set priorityClassName for supersetMcp pods
priorityClassName: ~
init:
# Configure resources
# Warning: fab command consumes a lot of ram and can
@@ -1179,8 +967,6 @@ init:
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after init job initContainers
extraInitContainers: []
# -- DEPRECATED: this field is no longer used by the chart.
# The init script is rendered entirely from the internal `superset.initScript` template
# (which runs `superset db upgrade`, `superset init`, admin creation, and examples).

View File

@@ -24,12 +24,13 @@ name = "apache_superset"
description = "A modern, enterprise-ready business intelligence web application"
readme = "README.md"
dynamic = ["version", "scripts", "entry-points"]
requires-python = ">=3.11"
requires-python = ">=3.10"
license = { file="LICENSE.txt" }
authors = [
{ name = "Apache Software Foundation", email = "dev@superset.apache.org" },
]
classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
@@ -42,9 +43,9 @@ dependencies = [
# ``google-auth`` 2.53+ dropped it, so Superset must declare it
# explicitly to keep fresh ``pip install apache-superset`` working
# without the ``base.txt`` lock file (#40962).
"cachetools>=7.1.4, <8",
"cachetools>=6.2.1, <7",
"celery>=5.6.3, <6.0.0",
"click>=8.4.2",
"click>=8.4.0",
"click-option-group",
"colorama",
"flask-cors>=6.0.5, <7.0",
@@ -62,11 +63,11 @@ dependencies = [
"flask-session>=0.4.0, <1.0",
"flask-wtf>=1.3.0, <2.0",
"geopy",
"greenlet<=3.5.3, >=3.5.3",
"greenlet<=3.5.1, >=3.5.1",
"gunicorn>=26.0.0, <27; sys_platform != 'win32'",
"hashids>=1.3.1, <2",
# holidays>=0.45 required for security fix
"holidays>=0.99, <1",
"holidays>=0.45, <1",
"humanize",
"isodate",
"jsonpath-ng>=1.8.0, <2",
@@ -83,7 +84,7 @@ dependencies = [
"packaging",
# --------------------------
# pandas and related (wanting pandas[performance] without numba as it's 100+MB and not needed)
"pandas[excel]>=2.3.3, <2.4",
"pandas[excel]>=2.1.4, <2.4",
"bottleneck", # recommended performance dependency for pandas, see https://pandas.pydata.org/docs/getting_started/install.html#performance-dependencies-recommended
# --------------------------
"parsedatetime",
@@ -99,7 +100,7 @@ dependencies = [
"pyarrow>=24.0.0, <25", # before upgrading pyarrow, check that all db dependencies support this, see e.g. https://github.com/apache/superset/pull/34693
"pyyaml>=6.0.3, <7.0.0",
"PyJWT>=2.4.0, <3.0",
"redis>=5.0.0, <9.0",
"redis>=5.0.0, <6.0",
"rison>=2.0.1, <3.0",
"selenium>=4.45.0, <5.0",
"shillelagh[gsheetsapi]>=1.4.4, <2.0",
@@ -109,10 +110,10 @@ dependencies = [
"sqlalchemy>=1.4, <2",
"sqlalchemy-continuum>=1.6.0, <2.0.0",
"sqlalchemy-utils>=0.42.1, <0.43", # expanding lowerbound to work with pydoris
"sqlglot>=30.12.0, <31",
"sqlglot>=30.8.0, <31",
# newer pandas needs 0.9+
"tabulate>=0.10.0, <1.0",
"typing-extensions>=4.16.0, <5",
"typing-extensions>=4, <5",
"waitress; sys_platform == 'win32'",
"watchdog>=6.0.0",
"wtforms>=3.2.2, <4",
@@ -125,11 +126,11 @@ dependencies = [
athena = ["pyathena[pandas]>=2, <4"]
aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
bigquery = [
"pandas-gbq>=0.35.0",
"pandas-gbq>=0.19.1",
"sqlalchemy-bigquery>=1.17.0",
"google-cloud-bigquery>=3.42.1",
]
clickhouse = ["clickhouse-connect>=1.4.2, <2.0"]
clickhouse = ["clickhouse-connect>=1.1.1, <2.0"]
cockroachdb = ["cockroachdb>=0.3.5, <0.4"]
crate = ["sqlalchemy-cratedb>=0.41.0, <1"]
d1 = [
@@ -148,13 +149,13 @@ dremio = ["sqlalchemy-dremio>=1.2.1, <4"]
drill = ["sqlalchemy-drill>=1.1.10, <2"]
druid = ["pydruid>=0.6.5,<0.7"]
duckdb = ["duckdb>=1.5.4,<2", "duckdb-engine>=0.17.0"]
dynamodb = ["pydynamodb>=0.8.2"]
dynamodb = ["pydynamodb>=0.4.2"]
solr = ["sqlalchemy-solr >= 0.2.4.3"]
elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"]
exasol = ["sqlalchemy-exasol>=2.4.0, <8.0"]
excel = ["xlrd>=2.0.2, <2.1"]
fastmcp = [
"fastmcp>=3.4.3,<4.0",
"fastmcp>=3.4.2,<4.0",
# tiktoken backs the response-size-guard token estimator. Without
# it, the middleware falls back to a coarser character-based
# heuristic that under-counts JSON-heavy MCP responses.
@@ -164,8 +165,9 @@ firebird = ["sqlalchemy-firebird>=0.8.0, <2.2"]
firebolt = ["firebolt-sqlalchemy>=1.0.0, <2"]
gevent = ["gevent>=26.4.0"]
gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"]
hana = ["hdbcli==2.29.25", "sqlalchemy_hana==3.0.3"]
hana = ["hdbcli==2.28.21", "sqlalchemy_hana==3.0.3"]
hive = [
"pyhive[hive]>=0.6.5;python_version<'3.11'",
"pyhive[hive_pure_sasl]>=0.7.0",
"tableschema",
"thrift>=0.23.0, <1.0.0",
@@ -190,15 +192,16 @@ pinot = ["pinotdb>=5.0.0, <10.0.0"]
playwright = ["playwright>=1.61.0, <2"]
postgres = ["psycopg2-binary==2.9.12"]
presto = ["pyhive[presto]>=0.6.5"]
trino = ["trino>=0.338.0"]
trino = ["trino>=0.337.0"]
prophet = ["prophet>=1.1.6, <2"]
redshift = ["sqlalchemy-redshift>=0.8.1, <0.9"]
risingwave = ["sqlalchemy-risingwave"]
shillelagh = ["shillelagh[all]>=1.4.4, <2"]
singlestore = ["sqlalchemy-singlestoredb>=1.2.1, <2"]
snowflake = ["snowflake-sqlalchemy>=1.10.2, <2"]
sqlite = ["syntaqlite>=0.7.0,<0.8.0"]
sqlite = ["syntaqlite>=0.1.0,<0.5.0"]
spark = [
"pyhive[hive]>=0.6.5;python_version<'3.11'",
"pyhive[hive_pure_sasl]>=0.7",
"tableschema",
"thrift>=0.23.0, <1",
@@ -210,9 +213,9 @@ tdengine = [
teradata = ["teradatasql>=20.0.0.62"]
thumbnails = [] # deprecated, will be removed in 7.0
vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"]
netezza = ["nzalchemy>= 11.1.2, < 11.2"]
netezza = ["nzalchemy>=11.0.2, < 11.2"]
starrocks = ["starrocks>=1.3.3, <2"]
doris = ["pydoris>=1.2.0, <2.0.0"]
doris = ["pydoris>=1.0.0, <2.0.0"]
oceanbase = ["oceanbase_py>=0.0.1.2"]
ydb = ["ydb-sqlalchemy>=0.1.22", "ydb-sqlglot-plugin>=0.2.8"]
development = [
@@ -241,7 +244,7 @@ development = [
"ruff",
"sqloxide",
"statsd",
"syntaqlite>=0.7.0,<0.8.0",
"syntaqlite>=0.4.2,<0.5.0",
]
[project.urls]
@@ -341,8 +344,8 @@ exclude = [
line-length = 88
indent-width = 4
# Assume Python 3.11
target-version = "py311"
# Assume Python 3.10
target-version = "py310"
[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.

View File

@@ -29,18 +29,19 @@ filterwarnings =
ignore
always::sqlalchemy.exc.RemovedIn20Warning
error:Passing a string to Connection.execute\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:The autoload parameter is deprecated:sqlalchemy.exc.RemovedIn20Warning
error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
error:The connection.execute\(\) method:sqlalchemy.exc.RemovedIn20Warning
# error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:The ``as_declarative\(\)`` function is now available:sqlalchemy.exc.RemovedIn20Warning
# error:The autoload parameter is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:The connection.execute\(\) method:sqlalchemy.exc.RemovedIn20Warning
# error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
error:The ``declarative_base\(\)`` function is now available:sqlalchemy.exc.RemovedIn20Warning
error:The Engine.execute\(\) method is considered legacy:sqlalchemy.exc.RemovedIn20Warning
# error:The `database` package is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:The ``declarative_base\(\)`` function is now available:sqlalchemy.exc.RemovedIn20Warning
# error:The Engine.execute\(\) method is considered legacy:sqlalchemy.exc.RemovedIn20Warning
error:The legacy calling style of select\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
error:The "whens" argument to case:sqlalchemy.exc.RemovedIn20Warning
# error:"User" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning

View File

@@ -44,7 +44,7 @@ cachelib==0.13.0
# via
# flask-caching
# flask-session
cachetools==7.1.4
cachetools==6.2.1
# via apache-superset (pyproject.toml)
cattrs==25.1.1
# via requests-cache
@@ -60,7 +60,7 @@ cffi==2.0.0
# pynacl
charset-normalizer==3.4.2
# via requests
click==8.4.2
click==8.4.1
# via
# apache-superset (pyproject.toml)
# celery
@@ -164,7 +164,7 @@ google-auth==2.53.0
# via
# -r requirements/base.in
# shillelagh
greenlet==3.5.3
greenlet==3.5.1
# via
# apache-superset (pyproject.toml)
# shillelagh
@@ -175,7 +175,7 @@ h11==0.16.0
# via wsproto
hashids==1.3.1
# via apache-superset (pyproject.toml)
holidays==0.100
holidays==0.82
# via apache-superset (pyproject.toml)
humanize==4.12.3
# via apache-superset (pyproject.toml)
@@ -275,7 +275,7 @@ packaging==25.0
# kombu
# limits
# shillelagh
pandas==2.3.3
pandas==2.1.4
# via apache-superset (pyproject.toml)
paramiko==3.5.1
# via
@@ -321,6 +321,7 @@ pyjwt==2.13.0
# apache-superset (pyproject.toml)
# flask-appbuilder
# flask-jwt-extended
# redis
pynacl==1.6.2
# via paramiko
pyopenssl==26.3.0
@@ -331,8 +332,6 @@ pyparsing==3.2.3
# via apache-superset (pyproject.toml)
pysocks==1.7.1
# via urllib3
python-calamine==0.8.2
# via pandas
python-dateutil==2.9.0.post0
# via
# apache-superset (pyproject.toml)
@@ -354,7 +353,7 @@ pyyaml==6.0.3
# via
# apache-superset (pyproject.toml)
# apispec
redis==8.0.1
redis==5.3.1
# via apache-superset (pyproject.toml)
referencing==0.36.2
# via
@@ -415,7 +414,7 @@ sqlalchemy-utils==0.42.1
# apache-superset (pyproject.toml)
# apache-superset-core
# flask-appbuilder
sqlglot==30.12.0
sqlglot==30.8.0
# via
# apache-superset (pyproject.toml)
# apache-superset-core
@@ -429,7 +428,7 @@ trio==0.33.0
# trio-websocket
trio-websocket==0.12.2
# via selenium
typing-extensions==4.16.0
typing-extensions==4.15.0
# via
# apache-superset (pyproject.toml)
# alembic

View File

@@ -97,7 +97,7 @@ cachelib==0.13.0
# -c requirements/base-constraint.txt
# flask-caching
# flask-session
cachetools==7.1.4
cachetools==6.2.1
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -130,7 +130,7 @@ charset-normalizer==3.4.2
# via
# -c requirements/base-constraint.txt
# requests
click==8.4.2
click==8.4.1
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -238,9 +238,9 @@ et-xmlfile==2.0.0
# openpyxl
exceptiongroup==1.3.0
# via fastmcp-slim
fastmcp==3.4.4
fastmcp==3.4.2
# via apache-superset
fastmcp-slim==3.4.4
fastmcp-slim==3.4.2
# via fastmcp
filelock==3.20.3
# via
@@ -340,6 +340,7 @@ gevent==26.4.0
google-api-core==2.23.0
# via
# google-cloud-bigquery
# google-cloud-bigquery-storage
# google-cloud-core
# pandas-gbq
# sqlalchemy-bigquery
@@ -349,6 +350,7 @@ google-auth==2.53.0
# google-api-core
# google-auth-oauthlib
# google-cloud-bigquery
# google-cloud-bigquery-storage
# google-cloud-core
# pandas-gbq
# pydata-google-auth
@@ -363,6 +365,8 @@ google-cloud-bigquery==3.42.1
# apache-superset
# pandas-gbq
# sqlalchemy-bigquery
google-cloud-bigquery-storage==2.26.0
# via pandas-gbq
google-cloud-core==2.4.1
# via google-cloud-bigquery
google-crc32c==1.6.0
@@ -373,7 +377,7 @@ googleapis-common-protos==1.66.0
# via
# google-api-core
# grpcio-status
greenlet==3.5.3
greenlet==3.5.1
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -403,7 +407,7 @@ hashids==1.3.1
# via
# -c requirements/base-constraint.txt
# apache-superset
holidays==0.100
holidays==0.82
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -634,11 +638,10 @@ packaging==25.0
# kombu
# limits
# matplotlib
# pandas-gbq
# pytest
# shillelagh
# sqlalchemy-bigquery
pandas==2.3.3
pandas==2.1.4
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -646,7 +649,7 @@ pandas==2.3.3
# db-dtypes
# pandas-gbq
# prophet
pandas-gbq==0.35.0
pandas-gbq==0.19.1
# via apache-superset
parameterized==0.9.0
# via apache-superset
@@ -702,17 +705,18 @@ prompt-toolkit==3.0.51
prophet==1.2.0
# via apache-superset
proto-plus==1.25.0
# via google-api-core
# via
# google-api-core
# google-cloud-bigquery-storage
protobuf==5.29.6
# via
# google-api-core
# google-cloud-bigquery-storage
# googleapis-common-protos
# grpcio-status
# proto-plus
psutil==6.1.0
# via
# apache-superset
# pandas-gbq
# via apache-superset
psycopg2-binary==2.9.12
# via apache-superset
py-key-value-aio==0.4.4
@@ -780,6 +784,7 @@ pyjwt==2.13.0
# flask-appbuilder
# flask-jwt-extended
# mcp
# redis
pylint==3.3.7
# via apache-superset
pynacl==1.6.2
@@ -819,10 +824,6 @@ pytest-mock==3.10.0
# via
# apache-superset
# apache-superset-extensions-cli
python-calamine==0.8.2
# via
# -c requirements/base-constraint.txt
# pandas
python-dateutil==2.9.0.post0
# via
# -c requirements/base-constraint.txt
@@ -869,7 +870,7 @@ pyyaml==6.0.3
# fastmcp-slim
# jsonschema-path
# pre-commit
redis==8.0.1
redis==5.3.1
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -997,7 +998,7 @@ sqlalchemy-utils==0.42.1
# apache-superset
# apache-superset-core
# flask-appbuilder
sqlglot==30.12.0
sqlglot==30.8.0
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -1016,7 +1017,7 @@ starlette==1.3.1
# mcp
statsd==4.0.1
# via apache-superset
syntaqlite==0.7.1
syntaqlite==0.4.2
# via apache-superset
tabulate==0.10.0
# via
@@ -1032,7 +1033,7 @@ tqdm==4.67.1
# via
# cmdstanpy
# prophet
trino==0.338.0
trino==0.337.0
# via apache-superset
trio==0.33.0
# via
@@ -1043,7 +1044,7 @@ trio-websocket==0.12.2
# via
# -c requirements/base-constraint.txt
# selenium
typing-extensions==4.16.0
typing-extensions==4.15.0
# via
# -c requirements/base-constraint.txt
# alembic

View File

@@ -1,16 +0,0 @@
# 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.

View File

@@ -153,11 +153,10 @@ def main( # noqa: C901
)
print(f"Migration goes from {down_revision} to {revision}")
with db.engine.connect() as conn:
current_revision = conn.execute(
text("SELECT version_num FROM alembic_version")
).scalar()
print(f"Current version of the DB is {current_revision}")
current_revision = db.engine.execute(
text("SELECT version_num FROM alembic_version")
).scalar()
print(f"Current version of the DB is {current_revision}")
if current_revision != down_revision:
if not force:

View File

@@ -20,21 +20,9 @@ import json
import os
import re
import subprocess
import time
from typing import List, Optional
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
# The change detector gates the entire CI matrix, so a single transient GitHub
# API hiccup should not fail the build. Retry server errors and network blips
# with exponential backoff before giving up.
MAX_RETRIES: int = 4
RETRY_BACKOFF_SECONDS: int = 2
REQUEST_TIMEOUT_SECONDS: int = 30
# GitHub returns 429 (and 403 for secondary rate limits) when throttling, which
# is transient and worth retrying alongside 5xx server errors.
RETRYABLE_STATUS_CODES: frozenset[int] = frozenset({403, 429})
# Define patterns for each group of files you're interested in
PATTERNS = {
"python": [
@@ -69,34 +57,15 @@ GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
def fetch_files_github_api(url: str): # type: ignore
"""Fetches data using GitHub API, retrying on transient failures."""
"""Fetches data using GitHub API."""
req = Request(url) # noqa: S310
req.add_header("Authorization", f"Bearer {GITHUB_TOKEN}")
req.add_header("Accept", "application/vnd.github.v3+json")
print(f"Fetching from {url}")
for attempt in range(1, MAX_RETRIES + 1):
try:
with urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as response: # noqa: S310
body = response.read()
return json.loads(body)
except (HTTPError, URLError) as err:
# Retry transient failures: network errors (URLError has no status
# code), 5xx server errors, and GitHub rate-limit responses. Other
# 4xx client errors are deterministic, so re-raise immediately. Also
# re-raise once the retry budget is exhausted.
status = getattr(err, "code", None)
is_transient = (
status is None or status >= 500 or status in RETRYABLE_STATUS_CODES
)
if not is_transient or attempt == MAX_RETRIES:
raise
wait = RETRY_BACKOFF_SECONDS * 2 ** (attempt - 1)
print(
f"Attempt {attempt}/{MAX_RETRIES} failed ({err}); "
f"retrying in {wait}s..."
)
time.sleep(wait)
with urlopen(req) as response: # noqa: S310
body = response.read()
return json.loads(body)
def fetch_changed_files_pr(repo: str, pr_number: str) -> List[str]:

View File

@@ -133,8 +133,8 @@ def main(docker: bool, frontend: bool, backend: bool) -> None: # noqa: C901
requirements = [
Requirement(
"python",
(Version("3.11.0"), Version("3.11.999")),
(Version("3.11.0"), Version("3.12.999")),
(Version("3.10.0"), Version("3.10.999")),
(Version("3.9.0"), Version("3.11.999")),
"backend",
"python --version",
),

View File

@@ -1,49 +0,0 @@
#!/usr/bin/env bash
# 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.
set -e
script_dir="$(dirname "$(realpath "$0")")"
root_dir="$(dirname "$script_dir")"
frontend_dir=superset-frontend
if [[ ! -d "$root_dir/$frontend_dir" ]]; then
echo "Error: $frontend_dir directory not found in $root_dir" >&2
exit 1
fi
cd "$root_dir/$frontend_dir"
# Filter files to only include JS/TS files and remove the frontend dir prefix
js_ts_files=()
for file in "$@"; do
# Remove superset-frontend/ prefix if present
cleaned_file="${file#$frontend_dir/}"
# Only include JS/TS files (Emotion styles live in these)
if [[ "$cleaned_file" =~ \.(js|jsx|ts|tsx)$ ]]; then
js_ts_files+=("$cleaned_file")
fi
done
# Only run if we have JS/TS files to lint. --allow-empty-input keeps the hook
# green when every passed file is covered by .stylelintignore.
if [ ${#js_ts_files[@]} -gt 0 ]; then
npx stylelint --allow-empty-input "${js_ts_files[@]}"
else
echo "No JavaScript/TypeScript files to lint for styles"
fi

View File

@@ -92,33 +92,4 @@ do
fi
done
# A few UI labels ("% calculation" etc.) parse as accidentally-valid
# %-format directives (a space flag plus a conversion character), so
# babel auto-flags them python-format on every write and msgfmt then
# fatals on their translations. The app never %-formats them; strip the
# flag AFTER the update pass (babel re-adds it during the update, so
# this must run last). Line-targeted so canonical wrapping is untouched.
python3 - <<'PYEOF'
import glob
TARGETS = {'msgid "% calculation"\n', 'msgid "% of parent"\n', 'msgid "% of total"\n'}
paths = ["superset/translations/messages.pot"] + sorted(
glob.glob("superset/translations/*/LC_MESSAGES/messages.po")
)
for path in paths:
lines = open(path, encoding="utf-8").readlines()
changed = False
for i, line in enumerate(lines):
if line in TARGETS and i > 0 and lines[i - 1].startswith("#,"):
tokens = [t.strip() for t in lines[i - 1][2:].split(",")]
if "python-format" in tokens:
tokens = [t for t in tokens if t != "python-format"]
if "no-python-format" not in tokens:
tokens.append("no-python-format")
lines[i - 1] = "#, " + ", ".join(tokens) + "\n"
changed = True
if changed:
open(path, "w", encoding="utf-8").writelines(lines)
PYEOF
cd $CURRENT_DIR

View File

@@ -138,22 +138,6 @@ def _lang_name(code: str) -> str:
return LANGUAGE_NAMES.get(code, code)
# An ISO 639-1/639-2 code, optionally followed by an ISO 3166 region
# (``_BR``, two uppercase) or an ISO 15924 script (``_Latn``, titlecase). The
# script subtag matters for catalogs like ``sr_Latn`` (Serbian in Latin script);
# without it the code was rejected and the catalog silently skipped.
_LANG_CODE_RE: re.Pattern[str] = re.compile(r"[a-z]{2,3}(_([A-Z]{2}|[A-Z][a-z]{3}))?")
def _is_valid_lang_code(lang: str) -> bool:
"""Validate a language code before it lands, unsanitized, in a filesystem path.
Guards against path traversal while allowing the region and script subtags
Superset actually ships (e.g. ``pt_BR``, ``sr_Latn``).
"""
return bool(_LANG_CODE_RE.fullmatch(lang))
def _plural_key(msgid: str, msgid_plural: str) -> str:
"""Build the translation index key used for pluralized entries."""
return f"{msgid}\x00{msgid_plural}"
@@ -683,11 +667,13 @@ def backfill(
mark_fuzzy: bool = True,
) -> None:
"""Backfill missing translations in the target language's .po file."""
if not _is_valid_lang_code(lang):
# Defense against path traversal: ``lang`` lands in a filesystem path
# without further sanitization, so reject anything that isn't an
# ISO 639-1/639-2 code with an optional ISO 3166 region (e.g. ``pt_BR``).
if not re.fullmatch(r"[a-z]{2,3}(_[A-Z]{2})?", lang):
print(
f"Invalid language code: {lang!r} "
"(expected ISO 639 code, optionally with a _<REGION> or _<Script> "
"subtag, e.g. 'fr', 'pt_BR', or 'sr_Latn')",
"(expected ISO 639 code, optionally with _<REGION>, e.g. 'fr' or 'pt_BR')",
file=sys.stderr,
)
sys.exit(1)

View File

@@ -21,7 +21,7 @@ under the License.
[![PyPI version](https://badge.fury.io/py/apache-superset-core.svg)](https://badge.fury.io/py/apache-superset-core)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
The official core package for building Apache Superset backend extensions and integrations. This package provides essential building blocks including base classes, API utilities, type definitions, and decorators for both the host application and extensions.

View File

@@ -26,7 +26,7 @@ authors = [
]
license = "Apache-2.0"
license-files = ["LICENSE.txt"]
requires-python = ">=3.11"
requires-python = ">=3.10"
keywords = ["superset", "apache", "analytics", "business-intelligence", "extensions", "visualization"]
classifiers = [
"Development Status :: 3 - Alpha",
@@ -34,6 +34,7 @@ classifiers = [
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Database",

View File

@@ -96,26 +96,6 @@ describe("guest token refresh", () => {
expect(timing).toBe(DEFAULT_TOKEN_EXP_MS - REFRESH_TIMING_BUFFER_MS);
});
it("falls back to default timing for a completely malformed token", () => {
const timing = getGuestTokenRefreshTiming("not-a-jwt");
expect(timing).toBe(DEFAULT_TOKEN_EXP_MS - REFRESH_TIMING_BUFFER_MS);
});
it("falls back to default timing for an empty string token", () => {
const timing = getGuestTokenRefreshTiming("");
expect(timing).toBe(DEFAULT_TOKEN_EXP_MS - REFRESH_TIMING_BUFFER_MS);
});
it("falls back to default timing for a token with invalid base64 payload", () => {
const timing = getGuestTokenRefreshTiming(
"header.!!!invalid-base64!!!.signature",
);
expect(timing).toBe(DEFAULT_TOKEN_EXP_MS - REFRESH_TIMING_BUFFER_MS);
});
it("exposes a positive retry delay for failed token refreshes", () => {
// The refresh loop reschedules itself after this delay when a fetch
// fails or times out, so it must be a sane positive value.

View File

@@ -25,20 +25,16 @@ export const DEFAULT_TOKEN_REFRESH_RETRY_MS = 10000; // wait before retrying a f
// when do we refresh the guest token?
export function getGuestTokenRefreshTiming(currentGuestToken: string) {
try {
const parsedJwt = jwtDecode<Record<string, any>>(currentGuestToken);
// if exp is int, it is in seconds, but Date() takes milliseconds
const exp = new Date(
/[^0-9\.]/g.test(parsedJwt.exp)
? parsedJwt.exp
: parseFloat(parsedJwt.exp) * 1000,
);
const isValidDate = exp.toString() !== "Invalid Date";
const ttl = isValidDate
? Math.max(MIN_REFRESH_WAIT_MS, exp.getTime() - Date.now())
: DEFAULT_TOKEN_EXP_MS;
return ttl - REFRESH_TIMING_BUFFER_MS;
} catch {
return DEFAULT_TOKEN_EXP_MS - REFRESH_TIMING_BUFFER_MS;
}
const parsedJwt = jwtDecode<Record<string, any>>(currentGuestToken);
// if exp is int, it is in seconds, but Date() takes milliseconds
const exp = new Date(
/[^0-9\.]/g.test(parsedJwt.exp)
? parsedJwt.exp
: parseFloat(parsedJwt.exp) * 1000,
);
const isValidDate = exp.toString() !== "Invalid Date";
const ttl = isValidDate
? Math.max(MIN_REFRESH_WAIT_MS, exp.getTime() - Date.now())
: DEFAULT_TOKEN_EXP_MS;
return ttl - REFRESH_TIMING_BUFFER_MS;
}

View File

@@ -21,7 +21,7 @@ under the License.
[![PyPI version](https://badge.fury.io/py/apache-superset-extensions-cli.svg)](https://badge.fury.io/py/apache-superset-extensions-cli)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
Official command-line interface for building, bundling, and managing Apache Superset extensions. This CLI tool provides developers with everything needed to create, develop, and package extensions for the Superset ecosystem.

View File

@@ -25,7 +25,7 @@ authors = [
]
license = "Apache-2.0"
license-files = ["LICENSE.txt"]
requires-python = ">=3.11"
requires-python = ">=3.10"
keywords = ["superset", "apache", "cli", "extensions", "analytics", "business-intelligence", "development-tools"]
classifiers = [
"Development Status :: 3 - Alpha",
@@ -33,6 +33,7 @@ classifiers = [
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Database",

View File

@@ -22,7 +22,7 @@ import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import reducerIndex from 'spec/helpers/reducerIndex';
import { Global } from '@emotion/react';
import { App, Layout } from 'antd';
import { App, Layout, Space, Content } from 'antd';
import 'src/theme.ts';
import './storybook.css';

Some files were not shown because too many files have changed in this diff Show More