Compare commits

...

24 Commits

Author SHA1 Message Date
Đỗ Trọng Hải
a9fd295df4 Merge branch 'master' into feat/migrate-from-prettier-to-oxfmt 2026-08-02 23:55:57 +07:00
Joe Li
120b4420b9 fix(versioning): narrow UUIDs in restore tests (#42654) 2026-08-02 23:54:30 +07:00
Đỗ Trọng Hải
fd6b390b6c Merge branch 'master' into feat/migrate-from-prettier-to-oxfmt 2026-08-02 23:48:08 +07:00
dependabot[bot]
0628b0b813 chore(deps-dev): update thrift requirement from <1.0.0,>=0.23.0 to >=0.24.0,<1.0.0 (#42667)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-02 23:45:06 +07:00
dependabot[bot]
378634cceb chore(deps-dev): update pyathena requirement from <4,>=2 to >=3.35.2,<4 (#42665)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-02 23:44:48 +07:00
dependabot[bot]
af7472fd7e chore(deps-dev): update databricks-sql-connector requirement from <4.4.0,>=4.2.6 to >=4.4.0,<4.5.0 (#42668)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-02 23:36:20 +07:00
hainenber
0fd971bba1 fix(ci): ignore MDX files from being formatted with Oxfmt
This was due to Oxfmt escaping the MDX/JSX comment syntax with literal backlash, failing MDX loader used by @docusaurus

Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-08-02 23:35:58 +07:00
hainenber
eb52dc6089 chore: format eslint-rules package.json
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-08-02 18:12:51 +07:00
hainenber
bcec75b3a9 feat(build): complete migration to Oxfmt for remaining sub-projects 2026-08-02 17:32:52 +07:00
dependabot[bot]
36e3ebecfa chore(deps): bump croniter from 6.2.2 to 6.2.4 (#42664)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-02 17:22:56 +07:00
dependabot[bot]
3f201c1c77 chore(deps): bump polyline from 2.0.2 to 2.0.4 (#42666)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-02 17:22:48 +07:00
hainenber
72278c96fc chore: format newly added codes 2026-08-02 17:22:24 +07:00
hainenber
d1e6b8c500 Merge branch 'master' into feat/migrate-from-prettier-to-oxfmt 2026-08-02 17:20:24 +07:00
dependabot[bot]
cc4cd3e98a chore(deps): bump cachetools from 7.1.4 to 7.1.6 (#42663)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-02 17:06:14 +07:00
dependabot[bot]
322ae841e5 chore(deps-dev): update clickhouse-connect requirement from <2.0,>=1.4.2 to >=1.6.0,<2.0 (#42669)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-02 17:05:57 +07:00
dependabot[bot]
5ccccc8c69 chore(deps): bump greenlet from 3.5.3 to 3.5.4 (#42670)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-02 17:05:34 +07:00
dependabot[bot]
3d0ee8b4c5 chore(deps-dev): bump prophet from 1.2.0 to 1.3.0 (#42672)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-02 17:05:20 +07:00
yousoph
ff9bec2b99 fix(dashboard): make chart error messages expandable again (#42491)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-01 15:26:31 -07:00
Beto Dealmeida
9f66cb566b feat(semantic layers): don't show samples tab in explore (#41509) 2026-08-01 16:03:20 -04:00
0xdorian-sm
29ac93862e fix(i18n-fr): translate the 85 remaining untranslated strings (#42577)
Signed-off-by: Dorian Saint-Martin <dorian.saintmartin@outlook.fr>
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-08-01 10:39:59 -07:00
Evan Rusackas
c9b159b4e7 docs(db_engine_specs): link upstream Pinot timestamp fix in TODO (#42623)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-08-01 10:39:14 -07:00
Evan Rusackas
d336d2a8b6 feat(ci): auto-label PRs with merge conflicts using requires:rebase (#42504)
Co-authored-by: Superset Dev <dev@superset.apache.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 10:38:02 -07:00
hainenber
1bbc63099b feat(build): migrate from Prettier to Oxfmt for docs
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-28 21:39:01 +07:00
hainenber
af9729a861 feat(build): migrate from Prettier to Oxfmt for performant code formatting
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-26 15:09:51 +07:00
2355 changed files with 91400 additions and 33306 deletions

View File

@@ -105,9 +105,9 @@ Charts built from enriched datasets containing:
pre-commit install
# Quick validation (faster than --all-files)
pre-commit run # Staged files only
pre-commit run # Staged files only
pre-commit run mypy # Python type checking
pre-commit run prettier # Code formatting
pre-commit run format # Code formatting
pre-commit run eslint # Frontend linting
```

View File

@@ -32,7 +32,6 @@
"ms-python.vscode-pylance",
"charliermarsh.ruff",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
}

View File

@@ -59,7 +59,6 @@
"ms-python.vscode-pylance",
"charliermarsh.ruff",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
}

View File

@@ -0,0 +1,54 @@
name: Label Merge Conflicts
# Sweeps every open PR and labels the ones GitHub reports as CONFLICTING with
# `requires:rebase` (removing it once a rebase makes the PR mergeable again),
# so the label can be used to filter the PR backlog for the ones that need a
# rebase before they can be reviewed/merged.
#
# The action itself always re-checks *every* open PR via GraphQL on each run
# regardless of what triggered it (see eps1lon/actions-label-merge-conflict's
# sources/main.ts) - there's no way to scope it to "just this PR". The
# project's own README suggests triggering on `push` (to the default branch)
# plus `pull_request_target: [synchronize]`, but on a repo with Superset's PR
# volume that combination would re-sweep the entire open-PR list on every
# merge to master *and* every push to *any* open PR - many times an hour.
# A schedule bounds that to a fixed, predictable cadence instead; adjust it
# if 2 hours turns out to be too slow or too chatty in practice.
on:
schedule:
- cron: "0 */2 * * *"
workflow_dispatch:
# Avoid two full backlog sweeps racing (a manual workflow_dispatch landing
# mid-schedule-tick, say); queue rather than cancel so an in-progress
# paginated sweep always runs to completion.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions: {}
jobs:
label-merge-conflicts:
# Scheduled/dispatch workflows still run on forks that carry this file;
# skip anywhere but the canonical repo.
if: github.repository == 'apache/superset'
name: Label Merge Conflicts
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # to add/remove requires:rebase and need:merge
steps:
# ASF Infra allowlists this whole action via a wildcard
# (eps1lon/actions-label-merge-conflict@*), so any pinned SHA/version
# is already fine here - no Infra ticket needed for future bumps.
- uses: eps1lon/actions-label-merge-conflict@0273be72a0bbd58fcd71d0d6c02c209b50d1e5e1 # v3.1.0
with:
dirtyLabel: "requires:rebase"
# A conflicting PR isn't actually ready to merge; strip that signal
# if it was previously set so reviewers don't act on a stale one.
removeOnDirtyLabel: "need:merge"
repoToken: ${{ secrets.GITHUB_TOKEN }}
# Intentionally no commentOnDirty/commentOnClean: the label alone is
# the signal (matches the label's existing description, and avoids
# a one-time comment storm across the whole backlog on first run).

View File

@@ -41,9 +41,9 @@ jobs:
- name: typescript checks
working-directory: ./superset-websocket
run: npm run type
- name: prettier
- name: code format check
working-directory: ./superset-websocket
run: npm run prettier-check
run: npm run format-check
- name: unit tests
working-directory: ./superset-websocket
run: npm run test

View File

@@ -62,9 +62,9 @@ repos:
args: ["--markdown-linebreak-ext=md"]
- repo: local
hooks:
- id: prettier-frontend
name: prettier (frontend)
entry: bash -c 'cd superset-frontend && files=(); for f in "$@"; do files+=("${f#superset-frontend/}"); done; npx prettier --write -- "${files[@]}"' --
- id: oxfmt-frontend
name: oxfmt (frontend)
entry: bash -c 'cd superset-frontend && files=(); for f in "$@"; do files+=("${f#superset-frontend/}"); done; npx oxfmt --write -- "${files[@]}"' --
language: system
pass_filenames: true
files: ^superset-frontend/.*\.(js|jsx|ts|tsx|css|scss|sass|json)$

View File

@@ -10,7 +10,6 @@
.stylelintignore
.flake8
.nvmrc
.prettierrc
.rat-excludes
.swcrc
.*log
@@ -64,7 +63,6 @@ tsconfig.tsbuildinfo
.*yml
.*iml
.esprintrc
.prettierignore
generator-superset/*
temporary_superset_ui/*

View File

@@ -19,7 +19,7 @@ git commit --amend # or new commit
```
Common pre-commit failures:
- **Formatting** - black, prettier, eslint will auto-fix
- **Formatting** - black, oxfmt, eslint will auto-fix
- **Type errors** - mypy failures need manual fixes
- **Linting** - ruff, pylint issues need manual fixes
@@ -263,7 +263,7 @@ git add . # Pre-commit only checks staged files
# Quick validation (faster than --all-files)
pre-commit run # Staged files only
pre-commit run mypy # Python type checking
pre-commit run prettier # Code formatting
pre-commit run format # Code formatting
pre-commit run eslint # Frontend linting
```

View File

@@ -95,7 +95,7 @@ py-format: pre-commit
pre-commit run black --all-files
js-format:
cd superset-frontend; npm run prettier
cd superset-frontend; npm run format
flask-app:
flask run -p 8088 --reload --debugger

View File

@@ -9,11 +9,13 @@ When working on the Storybook-to-MDX documentation system:
## Why This Matters
The generator (`scripts/generate-superset-components.mjs`) should be lightweight - it extracts data from stories and passes it through. When you add special cases to the generator:
- It becomes harder to maintain
- Stories diverge from their docs representation
- Future stories need to know about generator quirks
When you fix stories to match the expected patterns:
- Stories work identically in Storybook and Docs
- The generator stays simple and predictable
- Patterns are consistent and learnable
@@ -21,6 +23,7 @@ When you fix stories to match the expected patterns:
## Story Patterns for Docs Generation
### Required Structure
```tsx
// Use inline export default (NOT const meta = ...; export default meta)
export default {
@@ -45,6 +48,7 @@ export const InteractiveMyComponent: Story = {
```
### For Components with Variants (size × style grids)
```tsx
const sizes = ['small', 'medium', 'large'];
const variants = ['primary', 'secondary', 'danger'];
@@ -63,16 +67,20 @@ InteractiveButton.parameters = {
```
### For Components Requiring Children
```tsx
InteractiveIconTooltip.parameters = {
docs: {
// Component descriptors with dot notation for nested components
sampleChildren: [{ component: 'Icons.InfoCircleOutlined', props: { iconSize: 'l' } }],
sampleChildren: [
{ component: 'Icons.InfoCircleOutlined', props: { iconSize: 'l' } },
],
},
};
```
### For Custom Live Code Examples
```tsx
InteractiveMyComponent.parameters = {
docs: {
@@ -84,6 +92,7 @@ InteractiveMyComponent.parameters = {
```
### For Complex Props (objects, arrays)
```tsx
InteractiveMenu.parameters = {
docs: {
@@ -99,13 +108,13 @@ InteractiveMenu.parameters = {
## Common Issues and How to Fix Them (in the Story)
| Issue | Wrong Approach | Right Approach |
|-------|---------------|----------------|
| Component not generated | Add pattern to generator | Change story to use inline `export default` |
| Issue | Wrong Approach | Right Approach |
| --------------------------------------- | ----------------------------- | ------------------------------------------------- |
| Component not generated | Add pattern to generator | Change story to use inline `export default` |
| Control shows as text instead of select | Add special case in generator | Add `argTypes` with `control: { type: 'select' }` |
| Missing children/content | Modify StorybookWrapper | Add `parameters.docs.sampleChildren` |
| Gallery not showing | Add to generator output | Add `parameters.docs.gallery` config |
| Wrong live example | Hardcode in generator | Add `parameters.docs.liveExample` |
| Missing children/content | Modify StorybookWrapper | Add `parameters.docs.sampleChildren` |
| Gallery not showing | Add to generator output | Add `parameters.docs.gallery` config |
| Wrong live example | Hardcode in generator | Add `parameters.docs.liveExample` |
## Files

9
docs/.oxfmtrc.json Normal file
View File

@@ -0,0 +1,9 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid",
"printWidth": 80,
"sortPackageJson": false,
"ignorePatterns": ["**/*.mdx"]
}

View File

@@ -1,5 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid"
}

View File

@@ -69,6 +69,7 @@ yarn eslint # Lint TypeScript/JavaScript files
## 📁 Documentation Structure
### Main Documentation (`/docs`)
The primary documentation lives in `/docs` with this structure:
```
@@ -104,54 +105,57 @@ docs/
```
### Admin Docs (`/admin_docs`)
Admin-focused content: installation, configuration, security.
### Developer Docs (`/developer_docs`)
Developer-focused content: API documentation, architecture guides, CLI tools, code examples.
### Component Playground (`/components`)
Interactive component examples for UI development.
## 📝 Documentation Standards
### File Types
- **`.md` files**: Basic Markdown documents
- **`.mdx` files**: Markdown with JSX - can include React components
- **`.tsx` files in `/src`**: Custom React components and pages
### Frontmatter Structure
Every documentation page should have frontmatter:
```yaml
---
title: Page Title
description: Brief description for SEO
sidebar_position: 1 # Optional: controls order in sidebar
sidebar_position: 1 # Optional: controls order in sidebar
---
```
### MDX Component Usage
MDX files can import and use React components:
```mdx
````mdx
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="npm" label="npm" default>
```bash
npm install superset
```
```bash npm install superset ```
</TabItem>
<TabItem value="yarn" label="yarn">
```bash
yarn add superset
```
```bash yarn add superset ```
</TabItem>
</Tabs>
```
````
### Code Blocks
Use triple backticks with language identifiers:
````markdown
@@ -171,6 +175,7 @@ pip install apache-superset
````
### Admonitions
Docusaurus supports various admonition types:
```markdown
@@ -198,20 +203,21 @@ This is an info box
## 🔄 Version Management
### Version Configuration
Versions are managed through `versions-config.json`:
```json
{
"docs": {
"disabled": false,
"lastVersion": "6.0.0", // Default version shown
"includeCurrentVersion": true, // Show "Next" version
"lastVersion": "6.0.0", // Default version shown
"includeCurrentVersion": true, // Show "Next" version
"onlyIncludeVersions": ["current", "6.0.0"],
"versions": {
"current": {
"label": "Next",
"path": "",
"banner": "unreleased" // Shows warning banner
"banner": "unreleased" // Shows warning banner
},
"6.0.0": {
"label": "6.0.0",
@@ -224,6 +230,7 @@ Versions are managed through `versions-config.json`:
```
### Creating New Versions
**IMPORTANT**: Always use the custom scripts, NOT native Docusaurus commands:
```bash
@@ -235,8 +242,10 @@ yarn docusaurus docs:version 6.1.0
```
### Version Files Created
When versioning, these files are created (per section, with the
section's plugin id as prefix):
- `<section>_versioned_docs/version-X.X.X/` - Snapshot of current docs
- `<section>_versioned_sidebars/version-X.X.X-sidebars.json` - Sidebar config
- `<section>_versions.json` - List of all versions
@@ -246,6 +255,7 @@ Section plugin ids: `user_docs`, `admin_docs`, `developer_docs`, `components`.
## 🎨 Styling and Theming
### Custom CSS
Add custom styles in `/src/css/custom.css`:
```css
@@ -256,13 +266,14 @@ Add custom styles in `/src/css/custom.css`:
```
### Custom Components
Create React components in `/src/components/`:
```tsx
// src/components/FeatureCard.tsx
import React from 'react';
export default function FeatureCard({title, description}) {
export default function FeatureCard({ title, description }) {
return (
<div className="card">
<h3>{title}</h3>
@@ -277,10 +288,7 @@ Use in MDX:
```mdx
import FeatureCard from '@site/src/components/FeatureCard';
<FeatureCard
title="Fast"
description="Lightning fast queries"
/>
<FeatureCard title="Fast" description="Lightning fast queries" />
```
## 📦 Key Dependencies
@@ -295,6 +303,7 @@ import FeatureCard from '@site/src/components/FeatureCard';
## 🔗 Linking Strategies
### Internal Links
Use relative paths for internal documentation:
```markdown
@@ -303,6 +312,7 @@ Use relative paths for internal documentation:
```
### External Links
Always use full URLs:
```markdown
@@ -310,6 +320,7 @@ Always use full URLs:
```
### Linking to Code
Reference code in the main repository:
```markdown
@@ -319,21 +330,24 @@ See the [main configuration file](https://github.com/apache/superset/blob/master
## 🛠️ Common Documentation Tasks
### Adding a New Guide
1. Create the `.mdx` file in the appropriate directory
2. Add frontmatter with title and description
3. Update sidebar if needed (for manual sidebar configs)
### Adding API Documentation
The API docs use Swagger UI embedded in `/docs/api.mdx`:
```mdx
import SwaggerUI from "swagger-ui-react";
import "swagger-ui-react/swagger-ui.css";
import SwaggerUI from 'swagger-ui-react';
import 'swagger-ui-react/swagger-ui.css';
<SwaggerUI url="/api/v1/openapi.json" />
```
### Adding Interactive Examples
Use MDX to create interactive documentation:
```mdx
@@ -360,6 +374,7 @@ When creating or updating documentation:
## 🔍 Searching and Navigation
### Sidebar Configuration
Sidebars are configured in `/sidebars.js`:
```javascript
@@ -385,6 +400,7 @@ module.exports = {
```
### Search
Docusaurus includes Algolia DocSearch integration configured in `docusaurus.config.ts`.
## 🚫 Common Pitfalls to Avoid
@@ -398,6 +414,7 @@ Docusaurus includes Algolia DocSearch integration configured in `docusaurus.conf
## 🔧 Troubleshooting
### Dev Server Issues
```bash
yarn stop # Kill any running servers
yarn clear # Clear cache
@@ -405,6 +422,7 @@ yarn start # Restart
```
### Build Failures
```bash
# Check for broken links
yarn build
@@ -417,7 +435,9 @@ yarn eslint
```
### Version Issues
If versions don't appear in dropdown:
1. Check `versions-config.json` includes the version
2. Verify version files exist in `<section>_versioned_docs/`
3. Restart dev server
@@ -432,9 +452,10 @@ If versions don't appear in dropdown:
## 📖 Real Examples and Patterns
### Example: Configuration Documentation Pattern
From `docs/configuration/configuring-superset.mdx`:
```mdx
````mdx
---
title: Configuring Superset
hide_title: true
@@ -452,7 +473,9 @@ Superset exposes hundreds of configurable parameters through its
```bash
export SUPERSET_CONFIG_PATH=/app/superset_config.py
```
```
````
````
**Key patterns:**
- Links to source code for reference
@@ -476,9 +499,10 @@ documentation at [docs.preset.io](https://docs.preset.io/).
### Connecting to a new database
<img src={useBaseUrl("/img/tutorial/tutorial_01_add_database_connection.png")} width="600" />
```
````
**Key patterns:**
- Import Docusaurus hooks for dynamic URLs
- Use of admonitions (:::tip) for helpful information
- Screenshots with useBaseUrl for proper path resolution
@@ -486,11 +510,12 @@ documentation at [docs.preset.io](https://docs.preset.io/).
- Step-by-step visual guides
### Example: API Documentation Pattern
From `docs/api.mdx`:
```mdx
import SwaggerUI from "swagger-ui-react";
import "swagger-ui-react/swagger-ui.css";
import SwaggerUI from 'swagger-ui-react';
import 'swagger-ui-react/swagger-ui.css';
## API Documentation
@@ -498,6 +523,7 @@ import "swagger-ui-react/swagger-ui.css";
```
**Key patterns:**
- Embedding interactive Swagger UI
- Importing necessary CSS
- Direct API spec integration
@@ -508,49 +534,39 @@ import "swagger-ui-react/swagger-ui.css";
// For images in static folder
import useBaseUrl from "@docusaurus/useBaseUrl";
<img src={useBaseUrl("/img/feature-screenshot.png")} width="600" />
<img src={useBaseUrl('/img/feature-screenshot.png')} width="600" />
// With caption
<figure>
<img src={useBaseUrl("/img/dashboard.png")} alt="Dashboard view" />
<img src={useBaseUrl('/img/dashboard.png')} alt="Dashboard view" />
<figcaption>Superset Dashboard Interface</figcaption>
</figure>
```
### Multi-Tab Code Examples
```mdx
````mdx
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs
defaultValue="docker"
values={[
{label: 'Docker', value: 'docker'},
{label: 'Kubernetes', value: 'k8s'},
{label: 'PyPI', value: 'pypi'},
]}>
<TabItem value="docker">
```bash
docker-compose up
```
</TabItem>
<TabItem value="k8s">
```bash
kubectl apply -f superset.yaml
```
</TabItem>
<TabItem value="pypi">
```bash
pip install apache-superset
```
</TabItem>
{ label: 'Docker', value: 'docker' },
{ label: 'Kubernetes', value: 'k8s' },
{ label: 'PyPI', value: 'pypi' },
]}
>
<TabItem value="docker">```bash docker-compose up ```</TabItem>
<TabItem value="k8s">```bash kubectl apply -f superset.yaml ```</TabItem>
<TabItem value="pypi">```bash pip install apache-superset ```</TabItem>
</Tabs>
```
````
### Configuration File Examples
```mdx
````mdx
```python title="superset_config.py"
# Database connection example
SQLALCHEMY_DATABASE_URI = 'postgresql://user:password@localhost/superset'
@@ -565,7 +581,9 @@ FEATURE_FLAGS = {
'DASHBOARD_NATIVE_FILTERS': True,
}
```
```
````
````
### Cross-Referencing Pattern
@@ -578,11 +596,11 @@ For detailed configuration options, see:
External resources:
- [SQLAlchemy Documentation](https://docs.sqlalchemy.org/)
- [Flask Configuration](https://flask.palletsprojects.com/config/)
```
````
### Writing Installation Guides
```mdx
````mdx
## Prerequisites
:::warning
@@ -596,8 +614,10 @@ Ensure you have Python 3.9+ and Node.js 16+ installed before proceeding.
git clone https://github.com/apache/superset.git
cd superset
```
````
2. **Install Python dependencies**
```bash
pip install -e .
```
@@ -611,7 +631,8 @@ Ensure you have Python 3.9+ and Node.js 16+ installed before proceeding.
:::tip Success Check
Navigate to http://localhost:8088 and login with admin/admin
:::
```
````
### Documenting API Endpoints
@@ -630,9 +651,10 @@ Returns a list of charts.
```bash
curl -X GET "http://localhost:8088/api/v1/chart/" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
````
**Example Response:**
```json
{
"count": 42,
@@ -645,8 +667,10 @@ curl -X GET "http://localhost:8088/api/v1/chart/" \
]
}
```
```
---
**Note**: This documentation site serves as the primary resource for Superset users, administrators, and contributors. Always prioritize clarity, accuracy, and completeness when creating or updating documentation.
```

View File

@@ -66,6 +66,7 @@ yarn version:add:components 1.2.0
```
What the script does:
1. Refreshes auto-generated content via `generate:smart` (database pages, API reference, component pages).
2. Calls `yarn docusaurus docs:version` (or the per-section equivalent) to snapshot the section.
3. Freezes any data-file imports (`@site/static/*.json`, `../../data/*.json`) into a snapshot-local `_versioned_data/` dir so the historical version doesn't silently mutate when the source files change.
@@ -73,6 +74,7 @@ What the script does:
5. Updates `versions-config.json` and `<section>_versions.json`.
**Do NOT use** the native Docusaurus commands directly (`yarn docusaurus docs:version`), as they will:
- ❌ Create version files but NOT update `versions-config.json`
- ❌ Skip auto-gen refresh, freezing whatever was on disk
- ❌ Skip data-import freezing, leaving the snapshot pointed at live data
@@ -82,9 +84,11 @@ What the script does:
### Managing Versions
#### With Automated Scripts
The automated scripts handle all configuration updates automatically. No manual editing required!
#### Manual Configuration
If creating versions manually, you'll need to:
1. **Update `versions-config.json`** (or `docusaurus.config.ts` if not using dynamic config):
@@ -109,6 +113,7 @@ If creating versions manually, you'll need to:
### Removing a Version
#### Using Automated Scripts (Recommended)
```bash
# Main Documentation
yarn version:remove:user_docs 1.0.0
@@ -124,6 +129,7 @@ yarn version:remove:components 1.0.0
```
#### Manual Removal
To manually remove a version:
1. **Delete the version folder** from the appropriate location:
@@ -153,6 +159,7 @@ To manually remove a version:
### Version Configuration Examples
#### Main Documentation (default plugin)
```typescript
docs: {
includeCurrentVersion: true,
@@ -174,6 +181,7 @@ docs: {
```
#### Developer Docs & Components (custom plugins)
```typescript
{
id: 'developer_docs',
@@ -210,23 +218,28 @@ docs: {
#### Version Not Showing After Creation
If you accidentally used `yarn docusaurus docs:version` instead of `yarn version:add`:
1. **Problem**: The version files were created but `versions-config.json` wasn't updated
2. **Solution**: Either:
- Revert the changes: `git restore user_docs_versions.json && rm -rf user_docs_versioned_docs/ user_docs_versioned_sidebars/`
- Then use the correct command: `yarn version:add:user_docs <version>`
For other issues:
- **Restart the server**: Changes to version configuration require a server restart
- **Check config file**: Ensure `versions-config.json` includes the new version
- **Verify files exist**: Check that versioned docs folder was created
#### Broken Links in Versioned Documentation
When creating a new version, links in the documentation are preserved as-is. Common issues:
- **Cross-section links**: Links between sections (e.g., from developer_docs to docs) need to be version-aware
- **Absolute vs relative paths**: Use relative paths within the same section
- **Version-specific URLs**: Update hardcoded URLs to use version variables
To fix broken links:
1. Use `type: 'doc'` with `docId` for version-aware navigation in navbar
2. Use relative paths within the same documentation section
3. Test all versions after creation to identify broken links

View File

@@ -9,8 +9,8 @@ version: 2
Users can configure automated alerts and reports to send dashboards or charts to an email recipient or Slack channel.
- *Alerts* are sent when a SQL condition is reached
- *Reports* are sent on a schedule
- _Alerts_ are sent when a SQL condition is reached
- _Reports_ are sent on a schedule
Alerts and reports are disabled by default. To turn them on, you'll need to change configuration settings and install a suitable headless browser in your environment.
@@ -26,16 +26,17 @@ Alerts and reports are disabled by default. To turn them on, you'll need to chan
- emails: `SMTP_*` settings
- Slack messages: `SLACK_API_TOKEN`
- Users can customize the email subject by including date code placeholders, which will automatically be replaced with the corresponding UTC date when the email is sent. To enable this functionality, activate the `"DATE_FORMAT_IN_EMAIL_SUBJECT"` [feature flag](/admin-docs/configuration/configuring-superset#feature-flags). This enables date formatting in email subjects, preventing all reporting emails from being grouped into the same thread (optional for the reporting feature).
- Use date codes from [strftime.org](https://strftime.org/) to create the email subject.
- If no date code is provided, the original string will be used as the email subject.
- Use date codes from [strftime.org](https://strftime.org/) to create the email subject.
- If no date code is provided, the original string will be used as the email subject.
##### Disable dry-run mode
Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `docker/pythonpath_dev/superset_config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py).
Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `docker/pythonpath_dev/superset_config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py).
#### In your `Dockerfile`
You'll need to extend the Superset image to include a headless browser. Your options include:
- Use Playwright with Chromium: this is the recommended approach as of version 4.1.x or greater. Playwright always uses Chromium — the `WEBDRIVER_TYPE` config setting has no effect when Playwright is active. A working example of a Dockerfile that installs these tools is provided under "Building your own production Docker image" on the [Docker Builds](/admin-docs/installation/docker-builds#building-your-own-production-docker-image) page. Enable the `PLAYWRIGHT_REPORTS_AND_THUMBNAILS` feature flag in your config to activate it.
- Use Firefox (Selenium): you'll need to install geckodriver and Firefox. Set `WEBDRIVER_TYPE` to `"firefox"` in your `superset_config.py`.
- Use Chrome (Selenium): you'll need to install Chrome. Set `WEBDRIVER_TYPE` to `"chrome"` in your `superset_config.py`.
@@ -204,7 +205,7 @@ You need to replace default values with your custom Redis, Slack and/or SMTP con
Superset uses Celery beat and Celery worker(s) to send alerts and reports.
- The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report.
- The worker will process the tasks that need to be performed when an alert or report is fired.
- The worker will process the tasks that need to be performed when an alert or report is fired.
In the `CeleryConfig`, only the `beat_schedule` is relevant to this feature, the rest of the `CeleryConfig` can be changed for your needs.
@@ -313,7 +314,7 @@ Please refer to `ExecutorType` in the codebase for other executor types.
It's also possible to specify a minimum interval between each report's execution through the config file:
``` python
```python
# Set a minimum interval threshold between executions (for each Alert/Report)
# Value should be an integer
ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=10).total_seconds())
@@ -322,7 +323,7 @@ REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=5).total_seconds())
Alternatively, you can assign a function to `ALERT_MINIMUM_INTERVAL` and/or `REPORT_MINIMUM_INTERVAL`. This is useful to dynamically retrieve a value as needed:
``` python
```python
def alert_dynamic_minimal_interval(**kwargs) -> int:
"""
Define logic here to retrieve the value dynamically
@@ -335,7 +336,7 @@ ALERT_MINIMUM_INTERVAL = alert_dynamic_minimal_interval
For security, Superset rewrites external links in alert/report email HTML so
they go through a warning page before the user is navigated to the external
site. Internal links (matching your configured base URL) are not affected.
site. Internal links (matching your configured base URL) are not affected.
```python
# Disable external link redirection entirely (default: True)
@@ -347,17 +348,17 @@ to determine which hosts are internal.
## Troubleshooting
There are many reasons that reports might not be working. Try these steps to check for specific issues.
There are many reasons that reports might not be working. Try these steps to check for specific issues.
### Confirm feature flag is enabled and you have sufficient permissions
If you don't see "Alerts & Reports" under the *Manage* section of the Settings dropdown in the Superset UI, you need to enable the `ALERT_REPORTS` feature flag (see above). Enable another feature flag and check to see that it took effect, to verify that your config file is getting loaded.
If you don't see "Alerts & Reports" under the _Manage_ section of the Settings dropdown in the Superset UI, you need to enable the `ALERT_REPORTS` feature flag (see above). Enable another feature flag and check to see that it took effect, to verify that your config file is getting loaded.
Log in as an admin user to ensure you have adequate permissions.
### Check the logs of your Celery worker
This is the best source of information about the problem. In a docker compose deployment, you can do this with a command like `docker logs superset_worker --since 1h`.
This is the best source of information about the problem. In a docker compose deployment, you can do this with a command like `docker logs superset_worker --since 1h`.
### Check web browser and webdriver installation
@@ -369,7 +370,7 @@ If you are handling the installation of the headless browser on your own, do you
One symptom of an invalid connection to an email server is receiving an error of `[Errno 110] Connection timed out` in your logs when the report tries to send.
Confirm via testing that your outbound email configuration is correct. Here is the simplest test, for an un-authenticated email SMTP email service running on port 25. If you are sending over SSL, for instance, study how [Superset's codebase sends emails](https://github.com/apache/superset/blob/master/superset/utils/core.py#L818) and then test with those commands and arguments.
Confirm via testing that your outbound email configuration is correct. Here is the simplest test, for an un-authenticated email SMTP email service running on port 25. If you are sending over SSL, for instance, study how [Superset's codebase sends emails](https://github.com/apache/superset/blob/master/superset/utils/core.py#L818) and then test with those commands and arguments.
Start Python in your worker environment, replace all example values, and run:
@@ -395,16 +396,16 @@ This should send an email.
Possible fixes:
- Some cloud hosts disable outgoing unauthenticated SMTP email to prevent spam. For instance, [Azure blocks port 25 by default on some machines](https://learn.microsoft.com/en-us/azure/virtual-network/troubleshoot-outbound-smtp-connectivity). Enable that port or use another sending method.
- Some cloud hosts disable outgoing unauthenticated SMTP email to prevent spam. For instance, [Azure blocks port 25 by default on some machines](https://learn.microsoft.com/en-us/azure/virtual-network/troubleshoot-outbound-smtp-connectivity). Enable that port or use another sending method.
- Use another set of SMTP credentials that you verify works in this setup.
### Browse to your report from the worker
The worker may be unable to reach the report. It will use the value of `WEBDRIVER_BASEURL` to browse to the report. If that route is invalid, or presents an authentication challenge that the worker can't pass, the report screenshot will fail.
The worker may be unable to reach the report. It will use the value of `WEBDRIVER_BASEURL` to browse to the report. If that route is invalid, or presents an authentication challenge that the worker can't pass, the report screenshot will fail.
Check this by attempting to `curl` the URL of a report that you see in the error logs of your worker. For instance, from the worker environment, run `curl http://superset_app:8088/superset/dashboard/1/`. You may get different responses depending on whether the dashboard exists - for example, you may need to change the `1` in that URL. If there's a URL in your logs from a failed report screenshot, that's a good place to start. The goal is to determine a valid value for `WEBDRIVER_BASEURL` and determine if an issue like HTTPS or authentication is redirecting your worker.
In a deployment with authentication measures enabled like HTTPS and Single Sign-On, it may make sense to have the worker navigate directly to the Superset application running in the same location, avoiding the need to sign in. For instance, you could use `WEBDRIVER_BASEURL="http://superset_app:8088"` for a docker compose deployment, and set `"force_https": False,` in your `TALISMAN_CONFIG`.
In a deployment with authentication measures enabled like HTTPS and Single Sign-On, it may make sense to have the worker navigate directly to the Superset application running in the same location, avoiding the need to sign in. For instance, you could use `WEBDRIVER_BASEURL="http://superset_app:8088"` for a docker compose deployment, and set `"force_https": False,` in your `TALISMAN_CONFIG`.
### Duplicate report deliveries
@@ -512,6 +513,7 @@ schedule the queries that have `schedule_info` in their JSON metadata. For sched
Airflow, additional fields can be easily added to the configuration file above.
:::resources
- [Tutorial: Automated Alerts and Reporting via Slack/Email in Superset](https://dev.to/ngtduc693/apache-superset-topic-5-automated-alerts-and-reporting-via-slackemail-in-superset-2gbe)
- [Blog: Integrating Slack alerts and Apache Superset for better data observability](https://medium.com/affinityanswers-tech/integrating-slack-alerts-and-apache-superset-for-better-data-observability-fd2f9a12c350)
:::
:::

View File

@@ -104,5 +104,6 @@ celery --app=superset.tasks.celery_app:app flower
```
:::resources
- [Blog: How to Set Up Global Async Queries (GAQ) in Apache Superset](https://medium.com/@ngigilevis/how-to-set-up-global-async-queries-gaq-in-apache-superset-a-complete-guide-9d2f4a047559)
:::
:::

View File

@@ -13,7 +13,7 @@ Cross-account IAM role assumption via STS `AssumeRole` is supported, allowing a
## Prerequisites
- Enable the `AWS_DATABASE_IAM_AUTH` feature flag in `superset_config.py`. IAM authentication is gated behind this flag; if it is disabled, connections using `aws_iam` fail with *"AWS IAM database authentication is not enabled."*
- Enable the `AWS_DATABASE_IAM_AUTH` feature flag in `superset_config.py`. IAM authentication is gated behind this flag; if it is disabled, connections using `aws_iam` fail with _"AWS IAM database authentication is not enabled."_
```python
FEATURE_FLAGS = {
"AWS_DATABASE_IAM_AUTH": True,
@@ -48,14 +48,14 @@ IAM authentication is configured via the **encrypted_extra** field of the databa
}
```
| Field | Required | Description |
|-------|----------|-------------|
| `enabled` | Yes | Set to `true` to activate IAM auth |
| `role_arn` | No | ARN of the cross-account IAM role to assume via STS. Omit for same-account auth |
| `external_id` | No | External ID for the STS `AssumeRole` call, if required by the target role's trust policy |
| `region` | Yes | AWS region of the database cluster |
| `db_username` | Yes | The database username associated with the IAM identity |
| `session_duration` | No | STS session duration in seconds (default: `3600`) |
| Field | Required | Description |
| ------------------ | -------- | ---------------------------------------------------------------------------------------- |
| `enabled` | Yes | Set to `true` to activate IAM auth |
| `role_arn` | No | ARN of the cross-account IAM role to assume via STS. Omit for same-account auth |
| `external_id` | No | External ID for the STS `AssumeRole` call, if required by the target role's trust policy |
| `region` | Yes | AWS region of the database cluster |
| `db_username` | Yes | The database username associated with the IAM identity |
| `session_duration` | No | STS session duration in seconds (default: `3600`) |
### Redshift (Serverless)

View File

@@ -323,6 +323,7 @@ While database-backed operations work reliably, the Redis backend is recommended
deployments where low latency and reduced database load are important.
:::resources
- [Blog: The Data Engineer's Guide to Lightning-Fast Superset Dashboards](https://preset.io/blog/the-data-engineers-guide-to-lightning-fast-apache-superset-dashboards/)
- [Blog: Accelerating Dashboards with Materialized Views](https://preset.io/blog/accelerating-apache-superset-dashboards-with-materialized-views/)
:::
:::

View File

@@ -225,7 +225,7 @@ RequestHeader set X-Forwarded-Proto "https"
## Configuring the application root
*Please be advised that this feature is in BETA.*
_Please be advised that this feature is in BETA._
Superset supports running the application under a non-root path. The root path
prefix can be specified in one of three ways:
@@ -312,10 +312,13 @@ AUTH_USER_REGISTRATION_ROLE = "Public"
```
In case you want to assign the `Admin` role on new user registration, it can be assigned as follows:
```python
AUTH_USER_REGISTRATION_ROLE = "Admin"
```
If you encounter the [issue](https://github.com/apache/superset/issues/13243) of not being able to list users from the Superset main page settings, although a newly registered user has an `Admin` role, please re-run `superset init` to sync the required permissions. Below is the command to re-run `superset init` using docker compose.
```
docker-compose exec superset superset init
```
@@ -568,5 +571,6 @@ SUPERSET_DASHBOARD_POSITION_DATA_LIMIT = 131072 # double the default
Alternatively, split a very large dashboard into several smaller ones. Note that this check is enforced when saving layout edits in the UI; a dashboard imported from a ZIP with an oversized layout will load and render, but cannot be edited and re-saved until the limit is raised.
:::resources
- [Blog: Feature Flags in Apache Superset](https://preset.io/blog/feature-flags-in-apache-superset-and-preset/)
:::
:::

View File

@@ -22,10 +22,10 @@ The current list of countries can be found in the src
The Country Maps visualization already ships with the maps for the following countries:
<ul style={{columns: 3}}>
{countriesData.countries.map((country, index) => (
<li key={index}>{country}</li>
))}
<ul style={{ columns: 3 }}>
{countriesData.countries.map((country, index) => (
<li key={index}>{country}</li>
))}
</ul>
## Adding a New Country

View File

@@ -7,7 +7,7 @@ version: 1
import featureFlags from '@site/static/feature-flags.json';
export const FlagTable = ({flags}) => (
export const FlagTable = ({ flags }) => (
<table>
<thead>
<tr>
@@ -17,14 +17,21 @@ export const FlagTable = ({flags}) => (
</tr>
</thead>
<tbody>
{flags.map((flag) => (
{flags.map(flag => (
<tr key={flag.name}>
<td><code>{flag.name}</code></td>
<td><code>{flag.default ? 'True' : 'False'}</code></td>
<td>
<code>{flag.name}</code>
</td>
<td>
<code>{flag.default ? 'True' : 'False'}</code>
</td>
<td>
{flag.description}
{flag.docs && (
<> (<a href={flag.docs}>docs</a>)</>
<>
{' '}
(<a href={flag.docs}>docs</a>)
</>
)}
</td>
</tr>
@@ -50,12 +57,12 @@ FEATURE_FLAGS = {
Feature flags progress through lifecycle stages:
| Stage | Description |
|-------|-------------|
| Stage | Description |
| --------------- | ------------------------------------------------------------------------------ |
| **Development** | Experimental features under active development. May be incomplete or unstable. |
| **Testing** | Feature complete but undergoing testing. Usable but may contain bugs. |
| **Stable** | Production-ready features. Safe for all deployments. |
| **Deprecated** | Features scheduled for removal. Migrate away from these. |
| **Testing** | Feature complete but undergoing testing. Usable but may contain bugs. |
| **Stable** | Production-ready features. Safe for all deployments. |
| **Deprecated** | Features scheduled for removal. Migrate away from these. |
---

View File

@@ -148,10 +148,10 @@ datasets by saving the following YAML to file and then running the **import_data
```yaml
databases:
- database_name: main
tables:
- table_name: random_time_series
columns:
- column_name: ds
verbose_name: datetime
- database_name: main
tables:
- table_name: random_time_series
columns:
- column_name: ds
verbose_name: datetime
```

View File

@@ -18,7 +18,9 @@ DECKGL_BASE_MAP = [
['tile://https://your_personal_url/{z}/{x}/{y}.png', 'MyTile']
]
```
Openstreetmap tiles url can be added without prefix.
```python
DECKGL_BASE_MAP = [
['https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', 'OpenStreetMap']
@@ -53,6 +55,7 @@ DECKGL_BASE_MAP = [
```
Default values are:
```python
DECKGL_BASE_MAP = [
['https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'Streets (OSM)'],
@@ -73,6 +76,7 @@ Setting `DECKGL_BASE_MAP` overwrite default values
:::
After defining your map tiles, set them in these variables:
- `CORS_OPTIONS`
- `connect-src` of `TALISMAN_CONFIG` and `TALISMAN_CONFIG_DEV` variables.

View File

@@ -55,11 +55,11 @@ The MCP server runs as a separate process alongside Superset:
superset mcp run --host 127.0.0.1 --port 5008
```
| Flag | Default | Description |
|------|---------|-------------|
| `--host` | `127.0.0.1` | Host to bind to |
| `--port` | `5008` | Port to bind to |
| `--debug` | off | Enable debug logging |
| Flag | Default | Description |
| --------- | ----------- | -------------------- |
| `--host` | `127.0.0.1` | Host to bind to |
| `--port` | `5008` | Port to bind to |
| `--debug` | off | Enable debug logging |
The endpoint is available at `http://<host>:<port>/mcp`.
@@ -193,22 +193,24 @@ MCP_JWT_AUDIENCE = "your-audience"
:::warning
Store `MCP_JWT_SECRET` securely. Never commit it to version control. Use environment variables:
```python
import os
MCP_JWT_SECRET = os.environ.get("MCP_JWT_SECRET")
```
:::
#### JWT claims
The MCP server validates these standard claims:
| Claim | Config Key | Description |
|-------|-----------|-------------|
| `exp` | -- | Expiration time (always validated) |
| `iss` | `MCP_JWT_ISSUER` | Token issuer (optional but recommended) |
| `aud` | `MCP_JWT_AUDIENCE` | Token audience (optional but recommended) |
| `sub` | -- | Subject -- primary claim used to resolve the Superset user |
| Claim | Config Key | Description |
| ----- | ------------------ | ---------------------------------------------------------- |
| `exp` | -- | Expiration time (always validated) |
| `iss` | `MCP_JWT_ISSUER` | Token issuer (optional but recommended) |
| `aud` | `MCP_JWT_AUDIENCE` | Token audience (optional but recommended) |
| `sub` | -- | Subject -- primary claim used to resolve the Superset user |
#### User resolution
@@ -435,7 +437,7 @@ services:
superset:
image: apache/superset:latest
ports:
- "8088:8088"
- '8088:8088'
volumes:
- ./superset_config.py:/app/superset_config.py
environment:
@@ -443,9 +445,9 @@ services:
mcp:
image: apache/superset:latest
command: ["superset", "mcp", "run", "--host", "0.0.0.0", "--port", "5008"]
command: ['superset', 'mcp', 'run', '--host', '0.0.0.0', '--port', '5008']
ports:
- "5008:5008"
- '5008:5008'
volumes:
- ./superset_config.py:/app/superset_config.py
environment:
@@ -494,31 +496,31 @@ All MCP settings go in `superset_config.py`. Defaults are defined in `superset/m
### Core
| Setting | Default | Description |
|---------|---------|-------------|
| `MCP_SERVICE_HOST` | `"localhost"` | Host the MCP server binds to |
| `MCP_SERVICE_PORT` | `5008` | Port the MCP server binds to |
| `MCP_SERVICE_URL` | `None` | Public base URL for MCP-generated links (set this when behind a reverse proxy) |
| `MCP_DEBUG` | `False` | Enable debug logging |
| `MCP_DEV_USERNAME` | -- | Superset username for development mode (no auth) |
| `MCP_RBAC_ENABLED` | `True` | Enforce Superset's role-based access control on MCP tool calls. When `True`, each tool checks that the authenticated user has the required FAB permission before executing. Disable only for testing or trusted-network deployments. |
| `MCP_DISABLED_TOOLS` | `set()` | Set of tool names to remove from the MCP server at startup. Disabled tools are never advertised to AI clients during tool discovery. Useful when a custom extension tool should replace a built-in Superset tool. See [Disabling built-in tools](#disabling-built-in-tools). |
| Setting | Default | Description |
| -------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MCP_SERVICE_HOST` | `"localhost"` | Host the MCP server binds to |
| `MCP_SERVICE_PORT` | `5008` | Port the MCP server binds to |
| `MCP_SERVICE_URL` | `None` | Public base URL for MCP-generated links (set this when behind a reverse proxy) |
| `MCP_DEBUG` | `False` | Enable debug logging |
| `MCP_DEV_USERNAME` | -- | Superset username for development mode (no auth) |
| `MCP_RBAC_ENABLED` | `True` | Enforce Superset's role-based access control on MCP tool calls. When `True`, each tool checks that the authenticated user has the required FAB permission before executing. Disable only for testing or trusted-network deployments. |
| `MCP_DISABLED_TOOLS` | `set()` | Set of tool names to remove from the MCP server at startup. Disabled tools are never advertised to AI clients during tool discovery. Useful when a custom extension tool should replace a built-in Superset tool. See [Disabling built-in tools](#disabling-built-in-tools). |
### Authentication
| Setting | Default | Description |
|---------|---------|-------------|
| `MCP_AUTH_ENABLED` | `False` | Enable JWT authentication |
| `MCP_JWT_ALGORITHM` | `"RS256"` | JWT signing algorithm (`RS256` or `HS256`) |
| `MCP_JWKS_URI` | `None` | JWKS endpoint URL (RS256) |
| `MCP_JWT_PUBLIC_KEY` | `None` | Static RSA public key string (RS256) |
| `MCP_JWT_SECRET` | `None` | Shared secret string (HS256) |
| `MCP_JWT_ISSUER` | `None` | Expected `iss` claim |
| `MCP_JWT_AUDIENCE` | `None` | Expected `aud` claim |
| `MCP_REQUIRED_SCOPES` | `[]` | Required JWT scopes |
| `MCP_JWT_DEBUG_ERRORS` | `False` | Log detailed JWT errors server-side (never exposed in HTTP responses per RFC 6750) |
| `MCP_AUTH_FACTORY` | `None` | Custom auth provider factory `(flask_app) -> auth_provider`. Takes precedence over built-in JWT |
| `MCP_USER_RESOLVER` | `None` | Custom function `(app, access_token) -> username` to extract a Superset username from a validated JWT token. When `None`, the default resolver checks `preferred_username`, `username`, `email`, and `sub` claims in that order. |
| Setting | Default | Description |
| ---------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MCP_AUTH_ENABLED` | `False` | Enable JWT authentication |
| `MCP_JWT_ALGORITHM` | `"RS256"` | JWT signing algorithm (`RS256` or `HS256`) |
| `MCP_JWKS_URI` | `None` | JWKS endpoint URL (RS256) |
| `MCP_JWT_PUBLIC_KEY` | `None` | Static RSA public key string (RS256) |
| `MCP_JWT_SECRET` | `None` | Shared secret string (HS256) |
| `MCP_JWT_ISSUER` | `None` | Expected `iss` claim |
| `MCP_JWT_AUDIENCE` | `None` | Expected `aud` claim |
| `MCP_REQUIRED_SCOPES` | `[]` | Required JWT scopes |
| `MCP_JWT_DEBUG_ERRORS` | `False` | Log detailed JWT errors server-side (never exposed in HTTP responses per RFC 6750) |
| `MCP_AUTH_FACTORY` | `None` | Custom auth provider factory `(flask_app) -> auth_provider`. Takes precedence over built-in JWT |
| `MCP_USER_RESOLVER` | `None` | Custom function `(app, access_token) -> username` to extract a Superset username from a validated JWT token. When `None`, the default resolver checks `preferred_username`, `username`, `email`, and `sub` claims in that order. |
### Response Size Guard
@@ -539,13 +541,13 @@ MCP_RESPONSE_SIZE_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `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) |
| Key | Default | Description |
| -------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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
@@ -571,18 +573,18 @@ MCP_CACHE_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `enabled` | `False` | Enable response caching |
| `CACHE_KEY_PREFIX` | `None` | Optional prefix for cache keys (useful for shared Redis) |
| `list_tools_ttl` | `300` | Cache TTL in seconds for `tools/list` |
| `list_resources_ttl` | `300` | Cache TTL for `resources/list` |
| `list_prompts_ttl` | `300` | Cache TTL for `prompts/list` |
| `read_resource_ttl` | `3600` | Cache TTL for `resources/read` |
| `get_prompt_ttl` | `3600` | Cache TTL for `prompts/get` |
| `call_tool_ttl` | `3600` | Cache TTL for `tools/call` |
| `max_item_size` | `1048576` | Maximum cached item size in bytes (1 MB) |
| `excluded_tools` | See above | Tools that are never cached (mutating or non-deterministic) |
| Key | Default | Description |
| -------------------- | --------- | ----------------------------------------------------------- |
| `enabled` | `False` | Enable response caching |
| `CACHE_KEY_PREFIX` | `None` | Optional prefix for cache keys (useful for shared Redis) |
| `list_tools_ttl` | `300` | Cache TTL in seconds for `tools/list` |
| `list_resources_ttl` | `300` | Cache TTL for `resources/list` |
| `list_prompts_ttl` | `300` | Cache TTL for `prompts/list` |
| `read_resource_ttl` | `3600` | Cache TTL for `resources/read` |
| `get_prompt_ttl` | `3600` | Cache TTL for `prompts/get` |
| `call_tool_ttl` | `3600` | Cache TTL for `tools/call` |
| `max_item_size` | `1048576` | Maximum cached item size in bytes (1 MB) |
| `excluded_tools` | See above | Tools that are never cached (mutating or non-deterministic) |
### Redis Store (Multi-Pod)
@@ -597,12 +599,12 @@ MCP_STORE_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `enabled` | `False` | Enable Redis-backed store |
| `CACHE_REDIS_URL` | `None` | Redis connection URL (e.g., `redis://redis-host:6379/0`) |
| `event_store_max_events` | `100` | Maximum events retained per session |
| `event_store_ttl` | `3600` | Event TTL in seconds |
| Key | Default | Description |
| ------------------------ | ------- | -------------------------------------------------------- |
| `enabled` | `False` | Enable Redis-backed store |
| `CACHE_REDIS_URL` | `None` | Redis connection URL (e.g., `redis://redis-host:6379/0`) |
| `event_store_max_events` | `100` | Maximum events retained per session |
| `event_store_ttl` | `3600` | Event TTL in seconds |
### Tool Search
@@ -625,15 +627,15 @@ MCP_TOOL_SEARCH_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `enabled` | `True` | Enable tool search. When `False`, all tools are listed upfront |
| `strategy` | `"bm25"` | Search ranking algorithm. `"bm25"` supports natural language; `"regex"` supports pattern matching |
| `max_results` | `5` | Maximum tools returned per search query |
| `always_visible` | See above | Tools that always appear in `list_tools`, regardless of search |
| `include_schemas` | `False` | When `False` (default, "summary mode"), search results omit `inputSchema` entirely and include a lightweight `parameters_hint` listing top-level parameter names. Set to `True` to include the full `inputSchema` in search results. Full schemas are always used when a tool is actually invoked via `call_tool`. |
| `compact_schemas` | `True` | Strip `$defs` / `$ref` and replace with `{"type": "object"}` in search results to reduce token cost. Only takes effect when `include_schemas=True` — ignored in summary mode. |
| `max_description_length` | `300` | Truncate tool descriptions in search results (0 = no truncation). Applies in both summary and full-schema modes. |
| Key | Default | Description |
| ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `enabled` | `True` | Enable tool search. When `False`, all tools are listed upfront |
| `strategy` | `"bm25"` | Search ranking algorithm. `"bm25"` supports natural language; `"regex"` supports pattern matching |
| `max_results` | `5` | Maximum tools returned per search query |
| `always_visible` | See above | Tools that always appear in `list_tools`, regardless of search |
| `include_schemas` | `False` | When `False` (default, "summary mode"), search results omit `inputSchema` entirely and include a lightweight `parameters_hint` listing top-level parameter names. Set to `True` to include the full `inputSchema` in search results. Full schemas are always used when a tool is actually invoked via `call_tool`. |
| `compact_schemas` | `True` | Strip `$defs` / `$ref` and replace with `{"type": "object"}` in search results to reduce token cost. Only takes effect when `include_schemas=True` — ignored in summary mode. |
| `max_description_length` | `300` | Truncate tool descriptions in search results (0 = no truncation). Applies in both summary and full-schema modes. |
:::tip
Set `enabled: False` to revert to the traditional "show all tools at once" behavior, which some clients or workflows may prefer.
@@ -670,16 +672,16 @@ The MCP server respects Superset's full role-based access control (RBAC). Every
Each tool declares one or more required FAB permissions. The table below maps tool groups to their permission requirements:
| Tool group | Required FAB permission |
|------------|------------------------|
| `list_charts`, `get_chart_info`, `get_chart_data`, `get_chart_preview`, `generate_chart`, `update_chart` | `can_read` on `Chart` (read), `can_write` on `Chart` (mutate) |
| `list_dashboards`, `get_dashboard_info`, `generate_dashboard`, `add_chart_to_existing_dashboard` | `can_read` on `Dashboard` (read), `can_write` on `Dashboard` (mutate) |
| `list_datasets`, `get_dataset_info`, `create_virtual_dataset` | `can_read` on `Dataset` (read), `can_write` on `Dataset` (mutate) |
| `list_databases`, `get_database_info` | `can_read` on `Database` |
| `execute_sql` | `can_execute_sql_query` on `SQLLab` |
| `open_sql_lab_with_context` | `can_read` on `SQLLab` |
| `save_sql_query` | `can_write` on `SavedQuery` |
| `health_check` | None (public) |
| Tool group | Required FAB permission |
| -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `list_charts`, `get_chart_info`, `get_chart_data`, `get_chart_preview`, `generate_chart`, `update_chart` | `can_read` on `Chart` (read), `can_write` on `Chart` (mutate) |
| `list_dashboards`, `get_dashboard_info`, `generate_dashboard`, `add_chart_to_existing_dashboard` | `can_read` on `Dashboard` (read), `can_write` on `Dashboard` (mutate) |
| `list_datasets`, `get_dataset_info`, `create_virtual_dataset` | `can_read` on `Dataset` (read), `can_write` on `Dataset` (mutate) |
| `list_databases`, `get_database_info` | `can_read` on `Database` |
| `execute_sql` | `can_execute_sql_query` on `SQLLab` |
| `open_sql_lab_with_context` | `can_read` on `SQLLab` |
| `save_sql_query` | `can_write` on `SavedQuery` |
| `health_check` | None (public) |
To disable RBAC checking globally (for trusted-network deployments or testing), set:
@@ -706,13 +708,13 @@ This makes MCP activity fully auditable alongside regular Superset activity. The
Every MCP request passes through a middleware stack before reaching the tool function. The default stack (assembled in `build_middleware_list()` in `server.py`) is:
| Middleware | Purpose | Default |
|------------|---------|---------|
| `StructuredContentStripperMiddleware` | Strips `structuredContent` from responses for Claude.ai bridge compatibility | Enabled |
| `LoggingMiddleware` | Logs each tool call with user, parameters, and duration | Enabled |
| `GlobalErrorHandlerMiddleware` | Catches unhandled exceptions and sanitizes sensitive data before it reaches the client | Enabled |
| `ResponseSizeGuardMiddleware` | Estimates token count, warns at 80% of limit, blocks at limit | Enabled (configurable via `MCP_RESPONSE_SIZE_CONFIG`) |
| `ResponseCachingMiddleware` | Caches read-heavy tool responses (in-memory or Redis) | Disabled (enable via `MCP_CACHE_CONFIG`) |
| Middleware | Purpose | Default |
| ------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `StructuredContentStripperMiddleware` | Strips `structuredContent` from responses for Claude.ai bridge compatibility | Enabled |
| `LoggingMiddleware` | Logs each tool call with user, parameters, and duration | Enabled |
| `GlobalErrorHandlerMiddleware` | Catches unhandled exceptions and sanitizes sensitive data before it reaches the client | Enabled |
| `ResponseSizeGuardMiddleware` | Estimates token count, warns at 80% of limit, blocks at limit | Enabled (configurable via `MCP_RESPONSE_SIZE_CONFIG`) |
| `ResponseCachingMiddleware` | Caches read-heavy tool responses (in-memory or Redis) | Disabled (enable via `MCP_CACHE_CONFIG`) |
Additional middleware classes (`RateLimitMiddleware`, `FieldPermissionsMiddleware`, `PrivateToolMiddleware`) are implemented in `superset/mcp_service/middleware.py` but are not added to the default pipeline. They are available for operators who want to layer them in via a custom startup path.

View File

@@ -8,12 +8,10 @@ version: 1
## CORS
:::note
In Superset versions prior to `5.x` you have to install to install `flask-cors` with `pip install flask-cors` to enable CORS support.
:::
The following keys in `superset_config.py` can be specified to configure CORS:
- `ENABLE_CORS`: Must be set to `True` in order to enable CORS
@@ -54,11 +52,13 @@ Restart Superset for this configuration change to take effect.
There are two approaches to making dashboards publicly accessible:
**Option 1: Dataset-based access (simpler)**
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
2. Grant the Public role access to the relevant datasets (Menu → Security → List Roles → Public)
3. All published dashboards using those datasets become visible to anonymous users
**Option 2: Dashboard-level access (selective control)**
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
2. Add the `'ENABLE_VIEWERS': True` [Feature Flag](/admin-docs/configuration/feature-flags)
3. Edit each dashboard's properties and add the "Public" role subject as a viewer
@@ -75,7 +75,7 @@ Now anybody can directly access the dashboard's URL. You can embed it in an ifra
width="600"
height="400"
seamless
frameBorder="0"
frameborder="0"
scrolling="no"
src="https://superset.my-domain.com/superset/dashboard/10/?standalone=1&height=400"
>
@@ -123,17 +123,17 @@ running a custom auth postback endpoint), you can add the endpoints to `WTF_CSRF
## SSH Tunneling
1. Turn on feature flag
- Change [`SSH_TUNNELING`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L489) to `True`
- If you want to add more security when establishing the tunnel we allow users to overwrite the `SSHTunnelManager` class [here](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L507)
- You can also set the [`SSH_TUNNEL_LOCAL_BIND_ADDRESS`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L508) this the host address where the tunnel will be accessible on your VPC
- Change [`SSH_TUNNELING`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L489) to `True`
- If you want to add more security when establishing the tunnel we allow users to overwrite the `SSHTunnelManager` class [here](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L507)
- You can also set the [`SSH_TUNNEL_LOCAL_BIND_ADDRESS`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L508) this the host address where the tunnel will be accessible on your VPC
2. Create database w/ ssh tunnel enabled
- With the feature flag enabled you should now see ssh tunnel toggle.
- Click the toggle to enable SSH tunneling and add your credentials accordingly.
- Superset allows for two different types of authentication (Basic + Private Key). These credentials should come from your service provider.
- With the feature flag enabled you should now see ssh tunnel toggle.
- Click the toggle to enable SSH tunneling and add your credentials accordingly.
- Superset allows for two different types of authentication (Basic + Private Key). These credentials should come from your service provider.
3. Verify data is flowing
- Once SSH tunneling has been enabled, go to SQL Lab and write a query to verify data is properly flowing.
- Once SSH tunneling has been enabled, go to SQL Lab and write a query to verify data is properly flowing.
## Domain Sharding

View File

@@ -90,7 +90,7 @@ In the UI you can assign a set of parameters as JSON
The parameters become available in your SQL (example: `SELECT * FROM {{ my_table }}` ) by using Jinja templating syntax.
SQL Lab template parameters are stored with the dataset as `TEMPLATE PARAMETERS`.
There is a special ``_filters`` parameter which can be used to test filters used in the jinja template.
There is a special `_filters` parameter which can be used to test filters used in the jinja template.
```json
{
@@ -111,7 +111,7 @@ WHERE action in {{ filter_values('action_type')|where_in }}
GROUP BY action
```
Note ``_filters`` is not stored with the dataset. It's only used within the SQL Lab UI.
Note `_filters` is not stored with the dataset. It's only used within the SQL Lab UI.
Besides default Jinja templating, SQL lab also supports self-defined template processor by setting
the `CUSTOM_TEMPLATE_PROCESSORS` in your superset configuration. The values in this dictionary
@@ -245,16 +245,19 @@ cache key by adding the following parameter to your Jinja code:
```
You can json-stringify the array by adding `|tojson` to your Jinja code:
```python
{{ current_user_roles()|tojson }}
```
You can use the `|where_in` filter to use your roles in a SQL statement. For example, if `current_user_roles()` returns `['admin', 'viewer']`, the following template:
```python
SELECT * FROM users WHERE role IN {{ current_user_roles()|where_in }}
```
Will be rendered as:
```sql
SELECT * FROM users WHERE role IN ('admin', 'viewer')
```
@@ -280,6 +283,7 @@ Always treat `url_param()` values as untrusted input. Escaping behaviour varies
{% if cc not in ('US', 'ES', 'FR') %}{% set cc = 'US' %}{% endif %}
WHERE country_code = '{{ cc }}'
```
:::
Here's a concrete example:
@@ -364,6 +368,7 @@ This is useful if:
AND full_name LIKE '{{ filter.get('val') | replace("'", "''") }}'
{%- endif -%}
```
:::
Here's a concrete example:
@@ -431,7 +436,7 @@ The macro takes the following parameters:
- `column`: Name of the temporal column. Leave undefined to reference the time range from a Dashboard Native Time Range
filter (when present).
- `default`: The default value to fall back to if the time filter is not present, or has the value `No filter`
- `target_type`: The target temporal type as recognized by the target database (e.g. `TIMESTAMP`, `DATE` or
- `target_type`: The target temporal type as recognized by the target database (e.g. `TIMESTAMP`, `DATE` or
`DATETIME`). If `column` is defined, the format will default to the type of the column. This is used to produce
the format of the `from_expr` and `to_expr` properties of the returned `TimeFilter` object.
- `strftime`: format using the `strftime` method of `datetime` for custom time formatting.
@@ -537,6 +542,7 @@ The parameter can be used in SQL Lab, or when fetching a metric from another dat
Superset supports [builtin filters from the Jinja2 templating package](https://jinja.palletsprojects.com/en/stable/templates/#builtin-filters). Custom filters have also been implemented:
### Where In
Parses a list into a SQL-compatible statement. This is useful with macros that return an array (for example the `filter_values` macro):
```
@@ -556,6 +562,7 @@ Dashboard filter without any value applied
### To Datetime
Loads a string as a `datetime` object. This is useful when performing date operations. For example:
```
{% set from_expr = get_time_filter("dttm", strftime="%Y-%m-%d").from_expr %}
{% set to_expr = get_time_filter("dttm", strftime="%Y-%m-%d").to_expr %}
@@ -567,5 +574,6 @@ Loads a string as a `datetime` object. This is useful when performing date opera
```
:::resources
- [Blog: Intro to Jinja Templating in Apache Superset](https://preset.io/blog/intro-jinja-templating-apache-superset/)
:::
:::

View File

@@ -4,6 +4,7 @@ hide_title: true
sidebar_position: 12
version: 1
---
# Theming Superset
:::note
@@ -34,11 +35,13 @@ You can also extend with Superset-specific tokens (documented in the default the
When `ENABLE_UI_THEME_ADMINISTRATION = True` is configured, administrators can manage system-wide themes directly from the UI:
#### Setting System Themes
- **System Default Theme**: Click the sun icon on any theme to set it as the system-wide default
- **System Dark Theme**: Click the moon icon on any theme to set it as the system dark mode theme
- **Automatic OS Detection**: When both default and dark themes are set, Superset automatically detects and applies the appropriate theme based on OS preferences
#### Managing System Themes
- System themes are indicated with special badges in the theme list
- Only administrators with write permissions can modify system theme settings
- Removing a system theme designation reverts to configuration file defaults
@@ -46,6 +49,7 @@ When `ENABLE_UI_THEME_ADMINISTRATION = True` is configured, administrators can m
### Applying Themes to Dashboards
Once created, themes can be applied to individual dashboards:
- Edit any dashboard and select your custom theme from the theme dropdown
- Each dashboard can have its own theme, allowing for branded or context-specific styling
@@ -127,6 +131,7 @@ When `ENABLE_UI_THEME_ADMINISTRATION = True`:
Superset validates theme JSON when it is saved, either through the UI or via configuration. If a theme contains invalid tokens or an unrecognized structure, Superset logs a warning and falls back to the built-in default theme rather than applying a broken configuration. This prevents a bad theme from rendering the application unusable.
The fallback order is:
1. **UI-configured system theme** (highest priority, if `ENABLE_UI_THEME_ADMINISTRATION = True`)
2. **`THEME_DEFAULT` / `THEME_DARK`** from `superset_config.py`
3. **Built-in Superset default theme** (always present as a safety net)
@@ -455,9 +460,10 @@ For programmatic theme management, Superset provides REST endpoints:
These endpoints require appropriate permissions and are subject to RBAC controls.
:::resources
- [Video: Live Demo — Theming Apache Superset](https://www.youtube.com/watch?v=XsZAsO9tC3o)
- [CSS and Theming](https://docs.preset.io/docs/css-and-theming) - Additional theming techniques and CSS customization
- [Blog: Customizing Apache Superset Dashboards with CSS](https://preset.io/blog/customizing-superset-dashboards-with-css/)
- [Blog: Customizing Dashboards with CSS — Tips and Tricks](https://preset.io/blog/customizing-apache-superset-dashboards-with-css-additional-tips-and-tricks/)
- [Blog: Customizing Chart Colors](https://preset.io/blog/customizing-chart-colors-with-superset-and-preset/)
:::
:::

View File

@@ -5,7 +5,7 @@ sidebar_position: 1
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Architecture

View File

@@ -11,8 +11,7 @@ The Apache Superset community extensively uses Docker for development, release,
and productionizing Superset. This page details our Docker builds and tag naming
schemes to help users navigate our offerings.
Images are built and pushed to the [Superset Docker Hub repository](
https://hub.docker.com/r/apache/superset) using GitHub Actions.
Images are built and pushed to the [Superset Docker Hub repository](https://hub.docker.com/r/apache/superset) using GitHub Actions.
Different sets of images are built and/or published at different times:
- **Published releases** (`release`): published using

View File

@@ -5,12 +5,13 @@ sidebar_position: 5
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Using Docker Compose
<img src={useBaseUrl("/img/docker-compose.webp" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/docker-compose.webp')} width="150" />
<br />
<br />
:::caution
Since `docker compose` is primarily designed to run a set of containers on **a single host**
@@ -29,23 +30,23 @@ way to launch a fully functioning **development environment** quickly.
Note that there are 4 major ways we support to run `docker compose`:
1. **docker-compose.yml:** for interactive development, where we mount your local folder with the
frontend/backend files that you can edit and experience the changes you
make in the app in real time
frontend/backend files that you can edit and experience the changes you
make in the app in real time
1. **docker-compose-light.yml:** a lightweight configuration with minimal services (database,
Superset app, and frontend dev server) for development. Uses in-memory caching instead of Redis
and is designed for running multiple instances simultaneously
Superset app, and frontend dev server) for development. Uses in-memory caching instead of Redis
and is designed for running multiple instances simultaneously
1. **docker-compose-non-dev.yml** where we just build a more immutable image based on the
local branch and get all the required images running. Changes in the local branch
at the time you fire this up will be reflected, but changes to the code
while `up` won't be reflected in the app
local branch and get all the required images running. Changes in the local branch
at the time you fire this up will be reflected, but changes to the code
while `up` won't be reflected in the app
1. **docker-compose-image-tag.yml** where we fetch an image from docker-hub say for the
`5.0.0` release for instance, and fire it up so you can try it. Here what's in
the local branch has no effects on what's running, we just fetch and run
pre-built images from docker-hub. For `docker compose` to work along with the
Postgres image it boots up, you'll want to point to a `-dev`-suffixed TAG, as in
`export TAG=5.0.0-dev` or `export TAG=4.1.2-dev`, with `latest-dev` being the default.
The `dev` builds include the `psycopg2-binary` required to connect
to the Postgres database launched as part of the `docker compose` builds.
`5.0.0` release for instance, and fire it up so you can try it. Here what's in
the local branch has no effects on what's running, we just fetch and run
pre-built images from docker-hub. For `docker compose` to work along with the
Postgres image it boots up, you'll want to point to a `-dev`-suffixed TAG, as in
`export TAG=5.0.0-dev` or `export TAG=4.1.2-dev`, with `latest-dev` being the default.
The `dev` builds include the `psycopg2-binary` required to connect
to the Postgres database launched as part of the `docker compose` builds.
More on these approaches after setting up the requirements for either.
@@ -92,7 +93,7 @@ like to try out Superset without making any code changes follow the steps docume
:::tip
By default, we mount the local superset-frontend folder here and run `npm install` as well
as `npm run dev` which triggers webpack to compile/bundle the frontend code. Depending
on your local setup, especially if you have less than 16GB of memory, it may be very slow to
on your local setup, especially if you have less than 16GB of memory, it may be very slow to
perform those operations. In this case, we recommend you set the env var
`BUILD_SUPERSET_FRONTEND_IN_DOCKER` to `false`, and to run this locally instead in a terminal.
Simply trigger `npm i && npm run dev`, this should be MUCH faster.
@@ -121,6 +122,7 @@ NODE_PORT=9003 docker compose -p superset-3 -f docker-compose-light.yml up
```
This configuration includes:
- PostgreSQL database (internal network only)
- Superset application server
- Frontend development server with webpack hot reloading
@@ -165,7 +167,7 @@ looking to fire up.
:::caution
All of the content belonging to a Superset instance - charts, dashboards, users, etc. - is stored in
its metadata database. In production, this database should be backed up. The default installation
its metadata database. In production, this database should be backed up. The default installation
with docker compose will store that data in a PostgreSQL database contained in a Docker
[volume](https://docs.docker.com/storage/volumes/), which is not backed up.
@@ -174,7 +176,7 @@ Again, **THE DOCKER-COMPOSE INSTALLATION IS NOT PRODUCTION-READY OUT OF THE BOX.
:::
You should see a stream of logging output from the containers being launched on your machine. Once
this output slows, you should have a running instance of Superset on your local machine! To avoid
this output slows, you should have a running instance of Superset on your local machine! To avoid
the wall of text on future runs, add the `-d` option to the end of the `docker compose up` command.
### Configuring Further
@@ -259,24 +261,24 @@ Superset (which is running in its docker container). Other databases may have sl
configurations but gist would be same and boils down to 2 steps -
1. **(Mac users may skip this step)** Configuring the local postgresql/database instance to accept
public incoming connections. By default, postgresql only allows incoming connections from
`localhost` and under Docker, unless you use `--network=host`, `localhost` will refer to different
endpoints on the host machine and in a docker container respectively. Allowing postgresql to accept
connections from the Docker involves making one-line changes to the files `postgresql.conf` and
`pg_hba.conf`; you can find helpful links tailored to your OS / PG version on the web easily for
this task. For Docker it suffices to only whitelist IPs `172.0.0.0/8` instead of `*`, but in any
case you are _warned_ that doing this in a production database _may_ have disastrous consequences as
you are opening your database to the public internet.
public incoming connections. By default, postgresql only allows incoming connections from
`localhost` and under Docker, unless you use `--network=host`, `localhost` will refer to different
endpoints on the host machine and in a docker container respectively. Allowing postgresql to accept
connections from the Docker involves making one-line changes to the files `postgresql.conf` and
`pg_hba.conf`; you can find helpful links tailored to your OS / PG version on the web easily for
this task. For Docker it suffices to only whitelist IPs `172.0.0.0/8` instead of `*`, but in any
case you are _warned_ that doing this in a production database _may_ have disastrous consequences as
you are opening your database to the public internet.
1. Instead of `localhost`, try using `host.docker.internal` (Mac users, Ubuntu) or `172.18.0.1`
(Linux users) as the hostname when attempting to connect to the database. This is a Docker internal
detail -- what is happening is that, in Mac systems, Docker Desktop creates a dns entry for the
hostname `host.docker.internal` which resolves to the correct address for the host machine, whereas
in Linux this is not the case (at least by default). If neither of these 2 hostnames work then you
may want to find the exact hostname you want to use, for that you can do `ifconfig` or
`ip addr show` and look at the IP address of `docker0` interface that must have been created by
Docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo)
`docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP
address.
(Linux users) as the hostname when attempting to connect to the database. This is a Docker internal
detail -- what is happening is that, in Mac systems, Docker Desktop creates a dns entry for the
hostname `host.docker.internal` which resolves to the correct address for the host machine, whereas
in Linux this is not the case (at least by default). If neither of these 2 hostnames work then you
may want to find the exact hostname you want to use, for that you can do `ifconfig` or
`ip addr show` and look at the IP address of `docker0` interface that must have been created by
Docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo)
`docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP
address.
## 4. To build or not to build

View File

@@ -5,7 +5,7 @@ sidebar_position: 2
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installation Methods

View File

@@ -1,16 +1,17 @@
---
title: Kubernetes
title: Kubernetes
hide_title: true
sidebar_position: 3
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installing on Kubernetes
<img src={useBaseUrl("/img/k8s.png" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/k8s.png')} width="150" />
<br />
<br />
Running Superset on Kubernetes is supported with the provided [Helm](https://helm.sh/) chart
found in the official [Superset helm repository](https://apache.github.io/superset/index.yaml).
@@ -134,7 +135,7 @@ init:
```
:::note
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
There are two independent telemetry channels:
@@ -143,11 +144,11 @@ There are two independent telemetry channels:
```yaml
extraEnv:
SCARF_ANALYTICS: "false"
SCARF_ANALYTICS: 'false'
```
This is read at runtime, so it takes effect on the pre-built images without rebuilding the frontend.
:::
:::
### Dependencies
@@ -205,7 +206,7 @@ Those can be passed as key/values either with `extraEnv` or `extraSecretEnv` if
extraEnv:
SMTP_HOST: smtp.gmail.com
SMTP_USER: user@gmail.com
SMTP_PORT: "587"
SMTP_PORT: '587'
SMTP_MAIL_FROM: user@gmail.com
extraSecretEnv:
@@ -366,7 +367,7 @@ supersetCeleryBeat:
extraEnv:
SMTP_HOST: smtp.gmail.com
SMTP_USER: user@gmail.com
SMTP_PORT: "587"
SMTP_PORT: '587'
SMTP_MAIL_FROM: user@gmail.com
extraSecretEnv:
@@ -456,6 +457,7 @@ init:
```
:::resources
- [Tutorial: Mastering Data Visualization — Installing Superset on Kubernetes with Helm Chart](https://mahira-technology.medium.com/mastering-data-visualization-installing-superset-on-kubernetes-cluster-using-helm-chart-e4ec99199e1e)
- [Tutorial: Installing Apache Superset in Kubernetes](https://aws.plainenglish.io/installing-apache-superset-in-kubernetes-1aec192ac495)
:::
:::

View File

@@ -5,12 +5,13 @@ sidebar_position: 4
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installing Superset from PyPI
<img src={useBaseUrl("/img/pypi.png" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/pypi.png')} width="150" />
<br />
<br />
This page describes how to install Superset using the `apache_superset` package [published on PyPI](https://pypi.org/project/apache_superset/).
@@ -126,6 +127,7 @@ pip install apache_superset
```
Then, define mandatory configurations, SECRET_KEY and FLASK_APP:
```bash
export SUPERSET_SECRET_KEY=YOUR-SECRET-KEY # For production use, make sure this is a strong key, for example generated using `openssl rand -base64 42`. See https://superset.apache.org/admin-docs/configuration/configuring-superset#specifying-a-secret_key
export FLASK_APP=superset

View File

@@ -55,6 +55,7 @@ For a detailed list of breaking changes and migration notes for each version, se
This file documents backwards-incompatible changes and provides guidance for migrating between
major versions, including:
- Configuration changes
- API changes
- Database migrations

View File

@@ -2,41 +2,42 @@
title: CVEs fixed by release
sidebar_position: 2
---
#### Version 6.0.0
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2026-23980 | Improper Neutralization of Special Elements used in a SQL Command | < 6.0.0 |
| CVE-2026-23982 | Improper Authorization in Dataset Creation Allows Access Control Bypass | < 6.0.0 |
| CVE-2026-23983 | Information Disclosure of sensitive user info via Tags | < 6.0.0 |
| CVE-2026-23984 | SQLLab Read-Only Bypass on PostgreSQL (DML execution) | < 6.0.0 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------------------- | -------: |
| CVE-2026-23980 | Improper Neutralization of Special Elements used in a SQL Command | < 6.0.0 |
| CVE-2026-23982 | Improper Authorization in Dataset Creation Allows Access Control Bypass | < 6.0.0 |
| CVE-2026-23983 | Information Disclosure of sensitive user info via Tags | < 6.0.0 |
| CVE-2026-23984 | SQLLab Read-Only Bypass on PostgreSQL (DML execution) | < 6.0.0 |
#### Version 5.0.0
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2025-55673 | Exposure of Sensitive Information to an Unauthorized Actor | < 5.0.0 |
| CVE-2025-55674 | Improper Neutralization of Special Elements used in an SQL Command | < 5.0.0 |
| CVE-2025-55675 | Improper Access Control leading to Information Disclosure | < 5.0.0 |
| CVE | Title | Affected |
| :------------- | :----------------------------------------------------------------- | -------: |
| CVE-2025-55673 | Exposure of Sensitive Information to an Unauthorized Actor | < 5.0.0 |
| CVE-2025-55674 | Improper Neutralization of Special Elements used in an SQL Command | < 5.0.0 |
| CVE-2025-55675 | Improper Access Control leading to Information Disclosure | < 5.0.0 |
#### Version 4.1.3
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2025-55672 | Improper Neutralization of Input During Web Page Generation | < 4.1.3 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------- | -------: |
| CVE-2025-55672 | Improper Neutralization of Input During Web Page Generation | < 4.1.3 |
#### Version 4.1.2
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2025-27696 | Improper authorization leading to resource ownership takeover | < 4.1.2 |
| CVE-2025-48912 | Improper authorization bypass on row level security via SQL Injection | < 4.1.2 |
| CVE-2026-23969 | Exposure of Sensitive Information via Incomplete ClickHouse Function Filtering | < 4.1.2 |
| CVE | Title | Affected |
| :------------- | :----------------------------------------------------------------------------- | -------: |
| CVE-2025-27696 | Improper authorization leading to resource ownership takeover | < 4.1.2 |
| CVE-2025-48912 | Improper authorization bypass on row level security via SQL Injection | < 4.1.2 |
| CVE-2026-23969 | Exposure of Sensitive Information via Incomplete ClickHouse Function Filtering | < 4.1.2 |
#### Version 4.1.0
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| :------------- | :--------------------------------------------------------------------------------- | -------: |
| CVE-2024-53947 | Improper SQL authorisation, parse for specific postgres functions | < 4.1.0 |
| CVE-2024-53948 | Error verbosity exposes metadata in analytics databases | < 4.1.0 |
| CVE-2024-53949 | Lower privilege users are able to create Role when FAB_ADD_SECURITY_API is enabled | < 4.1.0 |
@@ -44,84 +45,84 @@ sidebar_position: 2
#### Version 4.0.2
| CVE | Title | Affected |
|:---------------|:----------------------------|---------:|
| CVE-2024-39887 | Improper SQL authorization | < 4.0.1 |
| CVE | Title | Affected |
| :------------- | :------------------------- | -------: |
| CVE-2024-39887 | Improper SQL authorization | < 4.0.1 |
#### Version 3.1.3, 4.0.1
| CVE | Title | Affected |
|:---------------|:----------------------------|----------------------------:|
| CVE-2024-34693 | Server arbitrary file read | < 3.1.3, >= 4.0.0, < 4.0.1 |
| CVE | Title | Affected |
| :------------- | :------------------------- | -------------------------: |
| CVE-2024-34693 | Server arbitrary file read | < 3.1.3, >= 4.0.0, < 4.0.1 |
#### Version 3.1.2
| CVE | Title | Affected |
|:---------------|:--------------------------------------------------------|---------:|
| CVE-2024-28148 | Incorrect datasource authorization on explore REST API | < 3.1.2 |
| CVE | Title | Affected |
| :------------- | :----------------------------------------------------- | -------: |
| CVE-2024-28148 | Incorrect datasource authorization on explore REST API | < 3.1.2 |
#### Version 3.0.4, 3.1.1
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------|----------------------------:|
| CVE-2024-27315 | Improper error handling on alerts | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24773 | Improper validation of SQL statements allows for unauthorized access to data | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24772 | Improper Neutralisation of custom SQL on embedded context | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24779 | Improper data authorization when creating a new dataset | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-26016 | Improper authorization validation on dashboards and charts import | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE | Title | Affected |
| :------------- | :--------------------------------------------------------------------------- | -------------------------: |
| CVE-2024-27315 | Improper error handling on alerts | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24773 | Improper validation of SQL statements allows for unauthorized access to data | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24772 | Improper Neutralisation of custom SQL on embedded context | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24779 | Improper data authorization when creating a new dataset | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-26016 | Improper authorization validation on dashboards and charts import | < 3.0.4, >= 3.1.0, < 3.1.1 |
#### Version 3.0.3
| CVE | Title | Affected |
|:---------------|:----------------------------------------------|---------:|
| :------------- | :-------------------------------------------- | -------: |
| CVE-2023-49657 | Stored XSS in Dashboard Title and Chart Title | < 3.0.3 |
#### Version 3.0.2, 2.1.3
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------|---------------------------:|
| :------------- | :---------------------------------------------------------- | -------------------------: |
| CVE-2023-46104 | Allows for uncontrolled resource consumption via a ZIP bomb | < 2.1.3, >= 3.0.0, < 3.0.2 |
| CVE-2023-49736 | SQL Injection on where_in JINJA macro | < 2.1.3, >= 3.0.0, < 3.0.2 |
| CVE-2023-49734 | Privilege Escalation Vulnerability | < 2.1.3, >= 3.0.0, < 3.0.2 |
#### Version 3.0.0
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-42502 | Open Redirect Vulnerability | < 3.0.0 |
| CVE-2023-42505 | Sensitive information disclosure on db connection details | < 3.0.0 |
| CVE | Title | Affected |
| :------------- | :-------------------------------------------------------- | -------: |
| CVE-2023-42502 | Open Redirect Vulnerability | < 3.0.0 |
| CVE-2023-42505 | Sensitive information disclosure on db connection details | < 3.0.0 |
#### Version 2.1.3
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-42504 | Lack of rate limiting allows for possible denial of service | < 2.1.3 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------- | -------: |
| CVE-2023-42504 | Lack of rate limiting allows for possible denial of service | < 2.1.3 |
#### Version 2.1.2
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-40610 | Privilege escalation with default examples database | < 2.1.2 |
| CVE-2023-42501 | Unnecessary read permissions within the Gamma role | < 2.1.2 |
| CVE-2023-43701 | Stored XSS on API endpoint | < 2.1.2 |
| CVE | Title | Affected |
| :------------- | :-------------------------------------------------- | -------: |
| CVE-2023-40610 | Privilege escalation with default examples database | < 2.1.2 |
| CVE-2023-42501 | Unnecessary read permissions within the Gamma role | < 2.1.2 |
| CVE-2023-43701 | Stored XSS on API endpoint | < 2.1.2 |
#### Version 2.1.1
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-36387 | Improper API permission for low privilege users | < 2.1.1 |
| CVE-2023-36388 | Improper API permission for low privilege users allows for SSRF | < 2.1.1 |
| CVE-2023-27523 | Improper data permission validation on Jinja templated queries | < 2.1.1 |
| CVE-2023-27526 | Improper Authorization check on import charts | < 2.1.1 |
| CVE-2023-39264 | Stack traces enabled by default | < 2.1.1 |
| CVE-2023-39265 | Possible Unauthorized Registration of SQLite Database Connections | < 2.1.1 |
| CVE-2023-37941 | Metadata db write access can lead to remote code execution | < 2.1.1 |
| CVE-2023-32672 | SQL parser edge case bypasses data access authorization | < 2.1.1 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------------- | -------: |
| CVE-2023-36387 | Improper API permission for low privilege users | < 2.1.1 |
| CVE-2023-36388 | Improper API permission for low privilege users allows for SSRF | < 2.1.1 |
| CVE-2023-27523 | Improper data permission validation on Jinja templated queries | < 2.1.1 |
| CVE-2023-27526 | Improper Authorization check on import charts | < 2.1.1 |
| CVE-2023-39264 | Stack traces enabled by default | < 2.1.1 |
| CVE-2023-39265 | Possible Unauthorized Registration of SQLite Database Connections | < 2.1.1 |
| CVE-2023-37941 | Metadata db write access can lead to remote code execution | < 2.1.1 |
| CVE-2023-32672 | SQL parser edge case bypasses data access authorization | < 2.1.1 |
#### Version 2.1.0
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| :------------- | :---------------------------------------------------------------------- | -------: |
| CVE-2023-25504 | Possible SSRF on import datasets | < 2.1.0 |
| CVE-2023-27524 | Session validation vulnerability when using provided default SECRET_KEY | < 2.1.0 |
| CVE-2023-27525 | Incorrect default permissions for Gamma role | < 2.1.0 |
@@ -129,8 +130,8 @@ sidebar_position: 2
#### Version 2.0.1
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------|------------------: |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------- | -----------------: |
| CVE-2022-41703 | SQL injection vulnerability in adhoc clauses | < 2.0.1 or < 1.5.2 |
| CVE-2022-43717 | Cross-Site Scripting on dashboards | < 2.0.1 or < 1.5.2 |
| CVE-2022-43718 | Cross-Site Scripting vulnerability on upload forms | < 2.0.1 or < 1.5.2 |

View File

@@ -3,7 +3,7 @@ title: Securing Your Superset Installation for Production
sidebar_position: 3
---
> *This guide applies to Apache Superset version 4.0 and later and is an evolving set of best practices that administrators should adapt to their specific deployment architecture.*
> _This guide applies to Apache Superset version 4.0 and later and is an evolving set of best practices that administrators should adapt to their specific deployment architecture._
The default Apache Superset configuration is optimized for ease of use and development, not for security. For any production deployment, it is **critical** that you review and apply the following security configurations to harden your instance, protect user data, and prevent unauthorized access.
@@ -13,25 +13,25 @@ This guide provides a comprehensive checklist of essential security configuratio
Running Superset without HTTPS (TLS) is not secure. Without it, all network traffic—including user credentials, session tokens, and sensitive data—is sent in cleartext and can be easily intercepted.
* **Use a Reverse Proxy:** Your Superset instance should always be deployed behind a reverse proxy (e.g., Nginx, Traefik) or a load balancer (e.g., AWS ALB, Google Cloud Load Balancer) that is configured to handle HTTPS termination.
* **Enforce Modern TLS:** Configure your proxy to enforce TLS 1.2 or higher with strong, industry-standard cipher suites.
* **Implement HSTS:** Use the HTTP Strict Transport Security (HSTS) header to ensure browsers only connect to your Superset instance over HTTPS. This can be configured in your reverse proxy or within Superset's Talisman settings.
- **Use a Reverse Proxy:** Your Superset instance should always be deployed behind a reverse proxy (e.g., Nginx, Traefik) or a load balancer (e.g., AWS ALB, Google Cloud Load Balancer) that is configured to handle HTTPS termination.
- **Enforce Modern TLS:** Configure your proxy to enforce TLS 1.2 or higher with strong, industry-standard cipher suites.
- **Implement HSTS:** Use the HTTP Strict Transport Security (HSTS) header to ensure browsers only connect to your Superset instance over HTTPS. This can be configured in your reverse proxy or within Superset's Talisman settings.
### **`SUPERSET_SECRET_KEY` Management (CRITICAL)**
This is the most critical security setting for your Superset instance. It is used to sign all session cookies and encrypt sensitive information in the metadata database, such as database connection credentials.
* **Generate a Unique, Strong Key:** A unique key must be generated for every Superset instance. Use a cryptographically secure method to create it.
```bash
# Example using openssl to generate a strong key
openssl rand -base64 42
```
* **Store the Key Securely:** The key must be kept confidential. The recommended approach is to store it as an environment variable or in a secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault). **Do not hardcode the key in `superset_config.py` or commit it to version control.**
```python
# In superset_config.py
import os
SECRET_KEY = os.environ.get('SUPERSET_SECRET_KEY')
```
- **Generate a Unique, Strong Key:** A unique key must be generated for every Superset instance. Use a cryptographically secure method to create it.
```bash
# Example using openssl to generate a strong key
openssl rand -base64 42
```
- **Store the Key Securely:** The key must be kept confidential. The recommended approach is to store it as an environment variable or in a secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault). **Do not hardcode the key in `superset_config.py` or commit it to version control.**
```python
# In superset_config.py
import os
SECRET_KEY = os.environ.get('SUPERSET_SECRET_KEY')
```
> #### ⚠️ Warning: Your `SUPERSET_SECRET_KEY` Must Be Unique
>
@@ -75,7 +75,7 @@ SESSION_USE_SIGNER = True
#### **Configure Session Lifetime and Cookie Security Flags**
This is mandatory for *all* deployments, whether stateless or server-side.
This is mandatory for _all_ deployments, whether stateless or server-side.
```python
# superset_config.py
@@ -92,7 +92,8 @@ SESSION_COOKIE_SAMESITE = 'Lax' # Provide protection against CSRF attacks
```
> ##### Note on iFrame Embedding and `SESSION_COOKIE_SAMESITE`
>The recommended default setting `'Lax'` provides good CSRF protection for most use cases. However, if you need to embed Superset dashboards into other applications using an iFrame, you will need to change this setting to `'None'`.
>
> The recommended default setting `'Lax'` provides good CSRF protection for most use cases. However, if you need to embed Superset dashboards into other applications using an iFrame, you will need to change this setting to `'None'`.
SESSION_COOKIE_SAMESITE = 'None'
@@ -102,9 +103,9 @@ Setting SameSite to 'None' requires that SESSION_COOKIE_SECURE is also set to Tr
While Superset's built-in database authentication is convenient, for production it's highly recommended to integrate with an enterprise-grade identity provider (IdP).
* **Use an Enterprise IdP:** Configure authentication via OAuth or LDAP to leverage your organization's existing identity management system. This provides benefits like Single Sign-On (SSO), Multi-Factor Authentication (MFA), and centralized user provisioning/deprovisioning.
* **Principle of Least Privilege:** Assign users to the most restrictive roles necessary for their jobs. Avoid over-provisioning users with Admin or Alpha roles, and ensure row-level security is applied where appropriate.
* **Admin Accounts:** Delete or disable the default admin user after a new administrative account has been configured.
- **Use an Enterprise IdP:** Configure authentication via OAuth or LDAP to leverage your organization's existing identity management system. This provides benefits like Single Sign-On (SSO), Multi-Factor Authentication (MFA), and centralized user provisioning/deprovisioning.
- **Principle of Least Privilege:** Assign users to the most restrictive roles necessary for their jobs. Avoid over-provisioning users with Admin or Alpha roles, and ensure row-level security is applied where appropriate.
- **Admin Accounts:** Delete or disable the default admin user after a new administrative account has been configured.
### **Content Security Policy (CSP) and Other Headers**
@@ -122,48 +123,48 @@ Here's the documentation section how how to set up Talisman: https://superset.ap
>
> It is essential to understand that **Apache Superset is a data visualization and exploration platform, not a database firewall or a comprehensive security solution for your data warehouse.** While Superset provides features to help manage data access, the ultimate responsibility for securing your underlying databases lies with your database administrators (DBAs) and security teams. This includes managing network access, user privileges, and fine-grained permissions directly within the database. The configurations below are an important secondary layer of security but should not be your only line of defense.
* **Use a Dedicated Database User:** The database connection configured in Superset should use a dedicated, limited-privilege database user. This user should only have the minimum required permissions (e.g., `SELECT` on specific schemas) for the data sources it needs to query. It should **not** have `INSERT`, `UPDATE`, `DELETE`, or administrative privileges.
* **Restrict Dangerous SQL Functions:** To mitigate potential SQL injection risks, configure the `DISALLOWED_SQL_FUNCTIONS` list in your `superset_config.py`. Be aware that this is a defense-in-depth measure, not a substitute for proper database permissions.
- **Use a Dedicated Database User:** The database connection configured in Superset should use a dedicated, limited-privilege database user. This user should only have the minimum required permissions (e.g., `SELECT` on specific schemas) for the data sources it needs to query. It should **not** have `INSERT`, `UPDATE`, `DELETE`, or administrative privileges.
- **Restrict Dangerous SQL Functions:** To mitigate potential SQL injection risks, configure the `DISALLOWED_SQL_FUNCTIONS` list in your `superset_config.py`. Be aware that this is a defense-in-depth measure, not a substitute for proper database permissions.
### **Additional Security Layers**
* **Web Application Firewall (WAF):** Deploying Superset behind a WAF (e.g., Cloudflare, AWS WAF) is strongly recommended. A WAF with a standard ruleset (like the OWASP Core Rule Set) provides a critical layer of defense against common attacks like SQL Injection, XSS, and remote code execution.
- **Web Application Firewall (WAF):** Deploying Superset behind a WAF (e.g., Cloudflare, AWS WAF) is strongly recommended. A WAF with a standard ruleset (like the OWASP Core Rule Set) provides a critical layer of defense against common attacks like SQL Injection, XSS, and remote code execution.
### **Monitoring and Logging**
* **Configure Structured Logging:** Set up a robust logging configuration to capture important security events.
* **Centralize Logs:** Ship logs from all Superset components (frontend, worker, etc.) to a centralized SIEM (Security Information and Event Management) system for analysis and alerting.
* **Monitor Key Events:** Create alerts for suspicious activities, including:
* Multiple failed login attempts for a single user or from a single IP address.
* Changes to user roles or permissions.
* Creation or deletion of high-privilege users.
* Attempts to use disallowed SQL functions.
- **Configure Structured Logging:** Set up a robust logging configuration to capture important security events.
- **Centralize Logs:** Ship logs from all Superset components (frontend, worker, etc.) to a centralized SIEM (Security Information and Event Management) system for analysis and alerting.
- **Monitor Key Events:** Create alerts for suspicious activities, including:
- Multiple failed login attempts for a single user or from a single IP address.
- Changes to user roles or permissions.
- Creation or deletion of high-privilege users.
- Attempts to use disallowed SQL functions.
-----
---
### **Appendix A: Production Deployment Checklist**
#### **Initial Setup:**
- [ ] HTTPS/TLS is configured and enforced via a reverse proxy.
- [ ] A unique, strong `SUPERSET_SECRET_KEY` is generated and secured in an environment variable or secrets vault.
- [ ] Server-side session management is configured (e.g., Redis).
- [ ] `PERMANENT_SESSION_LIFETIME` is set to a short duration (e.g., 8 hours).
- [ ] All session cookie security flags (`Secure`, `HttpOnly`, `SameSite`) are enabled.
- [ ] `DEBUG` mode is set to `False`.
- [ ] Talisman is explicitly enabled and configured with a strict Content Security Policy.
- [ ] Database connections use dedicated, limited-privilege accounts.
- [ ] Authentication is integrated with an enterprise identity provider (OAuth/LDAP).
- [ ] A Web Application Firewall (WAF) is deployed in front of Superset.
- [ ] Logging is configured and logs are shipped to a central monitoring system.
- [ ] HTTPS/TLS is configured and enforced via a reverse proxy.
- [ ] A unique, strong `SUPERSET_SECRET_KEY` is generated and secured in an environment variable or secrets vault.
- [ ] Server-side session management is configured (e.g., Redis).
- [ ] `PERMANENT_SESSION_LIFETIME` is set to a short duration (e.g., 8 hours).
- [ ] All session cookie security flags (`Secure`, `HttpOnly`, `SameSite`) are enabled.
- [ ] `DEBUG` mode is set to `False`.
- [ ] Talisman is explicitly enabled and configured with a strict Content Security Policy.
- [ ] Database connections use dedicated, limited-privilege accounts.
- [ ] Authentication is integrated with an enterprise identity provider (OAuth/LDAP).
- [ ] A Web Application Firewall (WAF) is deployed in front of Superset.
- [ ] Logging is configured and logs are shipped to a central monitoring system.
#### **Ongoing Maintenance:**
- [ ] Regularly update to the latest major or minor versions of Superset. Those versions receive up-to-date security patches.
- [ ] Rotate the `SUPERSET_SECRET_KEY` periodically (e.g., quarterly) and after any potential security incident.
- [ ] Rotate the other security-critical secrets (guest-token and async-query JWT secrets, SMTP and database credentials) on the cadence in Appendix C, and after any potential security incident.
- [ ] Conduct quarterly access reviews for all users.
- [ ] Assuming logging and monitoring is in place, review security monitoring alerts weekly.
- [ ] Regularly update to the latest major or minor versions of Superset. Those versions receive up-to-date security patches.
- [ ] Rotate the `SUPERSET_SECRET_KEY` periodically (e.g., quarterly) and after any potential security incident.
- [ ] Rotate the other security-critical secrets (guest-token and async-query JWT secrets, SMTP and database credentials) on the cadence in Appendix C, and after any potential security incident.
- [ ] Conduct quarterly access reviews for all users.
- [ ] Assuming logging and monitoring is in place, review security monitoring alerts weekly.
### **Appendix B: `SECRET_KEY` Rotation and Compromise Response**
@@ -178,13 +179,13 @@ https://superset.apache.org/admin-docs/configuration/configuring-superset/#rotat
`SUPERSET_SECRET_KEY` is not the only security-critical secret in a Superset deployment. Maintain an inventory of all such secrets, store each in a secrets manager (not in `superset_config.py` or version control), assign a responsible maintainer, and rotate them on a defined cadence as well as after any suspected compromise.
| Secret | Purpose | Risk if leaked | Suggested rotation |
|---|---|---|---|
| `SUPERSET_SECRET_KEY` | Signs session cookies; key material for encrypting stored DB credentials (Fernet/AES) | Forged sessions (auth bypass / privilege escalation); decryption of exfiltrated metadata-DB secrets | Quarterly + post-incident |
| `GUEST_TOKEN_JWT_SECRET` | Signs embedded-dashboard guest tokens | Forged guest tokens → unauthorized dashboard/data access | Quarterly + post-incident |
| `GLOBAL_ASYNC_QUERIES_JWT_SECRET` | Signs the async-query channel JWT | Forged async-query tokens | Quarterly + post-incident |
| SMTP password | Outbound email for alerts & reports | Email relay abuse / spoofing | Per organizational policy + post-incident |
| Database connection passwords | Access to analytical databases and the metadata DB | Direct database access | Per organizational policy + post-incident |
| Secret | Purpose | Risk if leaked | Suggested rotation |
| --------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `SUPERSET_SECRET_KEY` | Signs session cookies; key material for encrypting stored DB credentials (Fernet/AES) | Forged sessions (auth bypass / privilege escalation); decryption of exfiltrated metadata-DB secrets | Quarterly + post-incident |
| `GUEST_TOKEN_JWT_SECRET` | Signs embedded-dashboard guest tokens | Forged guest tokens → unauthorized dashboard/data access | Quarterly + post-incident |
| `GLOBAL_ASYNC_QUERIES_JWT_SECRET` | Signs the async-query channel JWT | Forged async-query tokens | Quarterly + post-incident |
| SMTP password | Outbound email for alerts & reports | Email relay abuse / spoofing | Per organizational policy + post-incident |
| Database connection passwords | Access to analytical databases and the metadata DB | Direct database access | Per organizational policy + post-incident |
Notes:
@@ -193,6 +194,7 @@ Notes:
- Keep the register under change control so new secrets introduced by future features are added to the rotation schedule.
:::resources
- [Blog: Running Apache Superset on the Open Internet](https://preset.io/blog/running-apache-superset-on-the-open-internet-a-report-from-the-fireline/)
- [Blog: How Security Vulnerabilities are Reported & Handled in Apache Superset](https://preset.io/blog/how-security-vulnerabilities-are-reported-and-handled-in-apache-superset/)
:::
:::

View File

@@ -24,13 +24,13 @@ A table with the permissions for these roles can be found at [/RESOURCES/STANDAR
Admins have all possible rights, including granting or revoking rights from other
users and altering other peoples slices and dashboards.
>#### Threat Model and Privilege Boundaries: The Admin Role
> #### Threat Model and Privilege Boundaries: The Admin Role
>
>Apache Superset is built with a granular permission model where users assigned the Admin role are considered fully trusted. Admins possess complete control over the application's configuration, UI rendering, and access controls.
> Apache Superset is built with a granular permission model where users assigned the Admin role are considered fully trusted. Admins possess complete control over the application's configuration, UI rendering, and access controls.
>
>Consequently, actions performed by an Admin that alter the application's behavior or presentation—such as injecting custom CSS, modifying Jinja templates, or altering security flags—are intended administrative capabilities by design.
> Consequently, actions performed by an Admin that alter the application's behavior or presentation—such as injecting custom CSS, modifying Jinja templates, or altering security flags—are intended administrative capabilities by design.
>
>In accordance with MITRE CNA Rule 4.1, a vulnerability must represent a violation of an explicit security policy. Because the Admin role is defined as a trusted operational boundary, actions executed with Admin privileges do not cross a security perimeter. Therefore, exploit vectors that strictly require Admin access are not classified as security vulnerabilities and are ineligible for CVE assignment.
> In accordance with MITRE CNA Rule 4.1, a vulnerability must represent a violation of an explicit security policy. Because the Admin role is defined as a trusted operational boundary, actions executed with Admin privileges do not cross a security perimeter. Therefore, exploit vectors that strictly require Admin access are not classified as security vulnerabilities and are ineligible for CVE assignment.
### Alpha
@@ -54,10 +54,10 @@ to all databases by default, both **Alpha** and **Gamma** users need to be given
Beyond the base `sql_lab` role, two additional SQL Lab permissions must be explicitly granted for users who need these capabilities:
| Permission | Feature |
|------------|---------|
| `can_estimate_query_cost` on `SQLLab` | Estimate query cost before running |
| `can_format_sql` on `SQLLab` | Format SQL using the database's dialect |
| Permission | Feature |
| ------------------------------------- | --------------------------------------- |
| `can_estimate_query_cost` on `SQLLab` | Estimate query cost before running |
| `can_format_sql` on `SQLLab` | Format SQL using the database's dialect |
Grant these in **Security → List Roles** by adding the permissions to the relevant role.
@@ -73,6 +73,7 @@ users who need to view dashboards. It provides minimal read-only access for:
- Viewing annotations on charts
The Public role explicitly excludes:
- Any write permissions on dashboards, charts, or datasets
- SQL Lab access
- Share functionality
@@ -236,6 +237,7 @@ viewers returns the resource to the dataset-based fallback. Explicit Viewers are
going forward; the implicit fallback may be deprecated and removed in a later major version.
**Important considerations:**
- Viewer access uses normal dataset checks unless `VIEWER_PROMISCUOUS_MODE` is enabled
- With `VIEWER_PROMISCUOUS_MODE`, dashboard viewer access can bypass dataset-level checks for
charts and datasets in that dashboard
@@ -243,6 +245,7 @@ going forward; the implicit fallback may be deprecated and removed in a later ma
- The dashboard must still be published to be visible
This feature is particularly useful for:
- Making specific dashboards public while keeping others private
- Granting access to dashboards without exposing the underlying datasets for other uses
- Creating dashboard-specific access patterns that don't align with dataset permissions
@@ -305,10 +308,11 @@ However, it is crucial to understand the following:
**Database Security is Paramount**: The ultimate responsibility for securing database access, controlling permissions, and preventing unauthorized function execution lies with the database administrators (DBAs) and security teams managing the underlying database instance.
**Recommended Database Practices**: We strongly recommend implementing security best practices at the database level, including:
* **Least Privilege**: Connecting Superset using dedicated database user accounts with the minimum permissions required for Superset's operation (typically read-only access to necessary schemas/tables).
* **Database Roles & Permissions**: Utilizing database-native roles and permissions to restrict access to sensitive functions, system variables (like `@@hostname`), schemas, or tables.
* **Network Security**: Employing network-level controls like database firewalls or proxies to restrict connections.
* **Auditing**: Enabling database-level auditing to monitor executed queries and access patterns.
- **Least Privilege**: Connecting Superset using dedicated database user accounts with the minimum permissions required for Superset's operation (typically read-only access to necessary schemas/tables).
- **Database Roles & Permissions**: Utilizing database-native roles and permissions to restrict access to sensitive functions, system variables (like `@@hostname`), schemas, or tables.
- **Network Security**: Employing network-level controls like database firewalls or proxies to restrict connections.
- **Auditing**: Enabling database-level auditing to monitor executed queries and access patterns.
By combining Superset's configurable safeguards with strong database-level security practices, you can achieve a more robust and layered security posture.
@@ -464,11 +468,11 @@ rules are:
For example, if a dataset has three filters:
| Filter | Clause | Group Key |
|--------|--------|-----------|
| F1 | `department = 'Finance'` | `department` |
| F2 | `department = 'Marketing'` | `department` |
| F3 | `region = 'Europe'` | `region` |
| Filter | Clause | Group Key |
| ------ | -------------------------- | ------------ |
| F1 | `department = 'Finance'` | `department` |
| F2 | `department = 'Marketing'` | `department` |
| F3 | `region = 'Europe'` | `region` |
The resulting WHERE clause would be:
@@ -552,7 +556,7 @@ GET /api/v1/rowlevelsecurity/<id>
```
The response includes the filter's `name`, `filter_type` (Regular or Base), `clause`,
`group_key`, assigned `tables` (with id, schema, and table\_name), and assigned `subjects`.
`group_key`, assigned `tables` (with id, schema, and table_name), and assigned `subjects`.
:::tip Auditing RLS for virtual datasets
To find all RLS rules that could affect a particular virtual dataset, query the list
@@ -598,13 +602,13 @@ This reduces the risk for replay attacks and session hijacking.
Superset uses [Flask-Session](https://flask-session.readthedocs.io/en/latest/) to manage server side sessions.
To enable this extension you have to set:
``` python
```python
SESSION_SERVER_SIDE = True
```
Flask-Session offers multiple backend session interfaces for Flask, here's an example for Redis:
``` python
```python
from redis import Redis
SESSION_TYPE = "redis"
@@ -633,8 +637,8 @@ It's extremely important to correctly configure a Content Security Policy when d
prevent many types of attacks. Superset provides two variables in `config.py` for deploying a CSP:
- `TALISMAN_ENABLED` defaults to `True`; set this to `False` in order to disable CSP
- `TALISMAN_CONFIG` holds the actual the policy definition (*see example below*) as well as any
other arguments to be passed to Talisman.
- `TALISMAN_CONFIG` holds the actual the policy definition (_see example below_) as well as any
other arguments to be passed to Talisman.
When running in production mode, Superset will check at startup for the presence
of a CSP. If one is not found, it will issue a warning with the security risks. For environments
@@ -650,12 +654,12 @@ this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`.
```
- Only scripts marked with a [nonce](https://content-security-policy.com/nonce/) can be loaded and executed.
Nonce is a random string automatically generated by Talisman on each page load.
You can get current nonce value by calling jinja macro `csp_nonce()`.
Nonce is a random string automatically generated by Talisman on each page load.
You can get current nonce value by calling jinja macro `csp_nonce()`.
```html
<script nonce="{{ csp_nonce() }}">
/* my script */
/* my script */
</script>
```
@@ -673,7 +677,7 @@ You can get current nonce value by calling jinja macro `csp_nonce()`.
```
- Cartodiagram charts request map data (image and json) from external resources that can be edited by users,
and therefore either require a list of allowed domains to request from or a wildcard (`'*'`) for `img-src` and `connect-src`.
and therefore either require a list of allowed domains to request from or a wildcard (`'*'`) for `img-src` and `connect-src`.
- Other CSP directives default to `'self'` to limit content to the same origin as the Superset server.
@@ -684,12 +688,12 @@ In order to adjust provided CSP configuration to your needs, follow the instruct
Setting `TALISMAN_ENABLED = True` will invoke Talisman's protection with its default arguments,
of which `content_security_policy` is only one. Those can be found in the
[Talisman documentation](https://pypi.org/project/flask-talisman/) under *Options*.
[Talisman documentation](https://pypi.org/project/flask-talisman/) under _Options_.
These generally improve security, but administrators should be aware of their existence.
In particular, the option of `force_https = True` (`False` by default) may break Superset's Alerts & Reports
if workers are configured to access charts via a `WEBDRIVER_BASEURL` beginning
with `http://`. As long as a Superset deployment enforces https upstream, e.g.,
with `http://`. As long as a Superset deployment enforces https upstream, e.g.,
through a load balancer or application gateway, it should be acceptable to keep this
option disabled. Otherwise, you may want to enable `force_https` like this:

View File

@@ -9,8 +9,8 @@ version: 2
Users can configure automated alerts and reports to send dashboards or charts to an email recipient or Slack channel.
- *Alerts* are sent when a SQL condition is reached
- *Reports* are sent on a schedule
- _Alerts_ are sent when a SQL condition is reached
- _Reports_ are sent on a schedule
Alerts and reports are disabled by default. To turn them on, you'll need to change configuration settings and install a suitable headless browser in your environment.
@@ -26,16 +26,17 @@ Alerts and reports are disabled by default. To turn them on, you'll need to chan
- emails: `SMTP_*` settings
- Slack messages: `SLACK_API_TOKEN`
- Users can customize the email subject by including date code placeholders, which will automatically be replaced with the corresponding UTC date when the email is sent. To enable this functionality, activate the `"DATE_FORMAT_IN_EMAIL_SUBJECT"` [feature flag](/admin-docs/configuration/configuring-superset#feature-flags). This enables date formatting in email subjects, preventing all reporting emails from being grouped into the same thread (optional for the reporting feature).
- Use date codes from [strftime.org](https://strftime.org/) to create the email subject.
- If no date code is provided, the original string will be used as the email subject.
- Use date codes from [strftime.org](https://strftime.org/) to create the email subject.
- If no date code is provided, the original string will be used as the email subject.
##### Disable dry-run mode
Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `docker/pythonpath_dev/superset_config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py).
Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `docker/pythonpath_dev/superset_config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py).
#### In your `Dockerfile`
You'll need to extend the Superset image to include a headless browser. Your options include:
- Use Playwright with Chrome: this is the recommended approach as of version 4.1.x or greater. A working example of a Dockerfile that installs these tools is provided under "Building your own production Docker image" on the [Docker Builds](/admin-docs/installation/docker-builds#building-your-own-production-docker-image) page. Read the code comments there as you'll also need to change a feature flag in your config.
- Use Firefox: you'll need to install geckodriver and Firefox.
- Use Chrome without Playwright: you'll need to install Chrome and set the value of `WEBDRIVER_TYPE` to `"chrome"` in your `superset_config.py`.
@@ -189,7 +190,7 @@ You need to replace default values with your custom Redis, Slack and/or SMTP con
Superset uses Celery beat and Celery worker(s) to send alerts and reports.
- The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report.
- The worker will process the tasks that need to be performed when an alert or report is fired.
- The worker will process the tasks that need to be performed when an alert or report is fired.
In the `CeleryConfig`, only the `beat_schedule` is relevant to this feature, the rest of the `CeleryConfig` can be changed for your needs.
@@ -296,7 +297,7 @@ Please refer to `ExecutorType` in the codebase for other executor types.
It's also possible to specify a minimum interval between each report's execution through the config file:
``` python
```python
# Set a minimum interval threshold between executions (for each Alert/Report)
# Value should be an integer
ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=10).total_seconds())
@@ -305,7 +306,7 @@ REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=5).total_seconds())
Alternatively, you can assign a function to `ALERT_MINIMUM_INTERVAL` and/or `REPORT_MINIMUM_INTERVAL`. This is useful to dynamically retrieve a value as needed:
``` python
```python
def alert_dynamic_minimal_interval(**kwargs) -> int:
"""
Define logic here to retrieve the value dynamically
@@ -318,7 +319,7 @@ ALERT_MINIMUM_INTERVAL = alert_dynamic_minimal_interval
For security, Superset rewrites external links in alert/report email HTML so
they go through a warning page before the user is navigated to the external
site. Internal links (matching your configured base URL) are not affected.
site. Internal links (matching your configured base URL) are not affected.
```python
# Disable external link redirection entirely (default: True)
@@ -330,17 +331,17 @@ to determine which hosts are internal.
## Troubleshooting
There are many reasons that reports might not be working. Try these steps to check for specific issues.
There are many reasons that reports might not be working. Try these steps to check for specific issues.
### Confirm feature flag is enabled and you have sufficient permissions
If you don't see "Alerts & Reports" under the *Manage* section of the Settings dropdown in the Superset UI, you need to enable the `ALERT_REPORTS` feature flag (see above). Enable another feature flag and check to see that it took effect, to verify that your config file is getting loaded.
If you don't see "Alerts & Reports" under the _Manage_ section of the Settings dropdown in the Superset UI, you need to enable the `ALERT_REPORTS` feature flag (see above). Enable another feature flag and check to see that it took effect, to verify that your config file is getting loaded.
Log in as an admin user to ensure you have adequate permissions.
### Check the logs of your Celery worker
This is the best source of information about the problem. In a docker compose deployment, you can do this with a command like `docker logs superset_worker --since 1h`.
This is the best source of information about the problem. In a docker compose deployment, you can do this with a command like `docker logs superset_worker --since 1h`.
### Check web browser and webdriver installation
@@ -352,7 +353,7 @@ If you are handling the installation of the headless browser on your own, do you
One symptom of an invalid connection to an email server is receiving an error of `[Errno 110] Connection timed out` in your logs when the report tries to send.
Confirm via testing that your outbound email configuration is correct. Here is the simplest test, for an un-authenticated email SMTP email service running on port 25. If you are sending over SSL, for instance, study how [Superset's codebase sends emails](https://github.com/apache/superset/blob/master/superset/utils/core.py#L818) and then test with those commands and arguments.
Confirm via testing that your outbound email configuration is correct. Here is the simplest test, for an un-authenticated email SMTP email service running on port 25. If you are sending over SSL, for instance, study how [Superset's codebase sends emails](https://github.com/apache/superset/blob/master/superset/utils/core.py#L818) and then test with those commands and arguments.
Start Python in your worker environment, replace all example values, and run:
@@ -378,16 +379,16 @@ This should send an email.
Possible fixes:
- Some cloud hosts disable outgoing unauthenticated SMTP email to prevent spam. For instance, [Azure blocks port 25 by default on some machines](https://learn.microsoft.com/en-us/azure/virtual-network/troubleshoot-outbound-smtp-connectivity). Enable that port or use another sending method.
- Some cloud hosts disable outgoing unauthenticated SMTP email to prevent spam. For instance, [Azure blocks port 25 by default on some machines](https://learn.microsoft.com/en-us/azure/virtual-network/troubleshoot-outbound-smtp-connectivity). Enable that port or use another sending method.
- Use another set of SMTP credentials that you verify works in this setup.
### Browse to your report from the worker
The worker may be unable to reach the report. It will use the value of `WEBDRIVER_BASEURL` to browse to the report. If that route is invalid, or presents an authentication challenge that the worker can't pass, the report screenshot will fail.
The worker may be unable to reach the report. It will use the value of `WEBDRIVER_BASEURL` to browse to the report. If that route is invalid, or presents an authentication challenge that the worker can't pass, the report screenshot will fail.
Check this by attempting to `curl` the URL of a report that you see in the error logs of your worker. For instance, from the worker environment, run `curl http://superset_app:8088/superset/dashboard/1/`. You may get different responses depending on whether the dashboard exists - for example, you may need to change the `1` in that URL. If there's a URL in your logs from a failed report screenshot, that's a good place to start. The goal is to determine a valid value for `WEBDRIVER_BASEURL` and determine if an issue like HTTPS or authentication is redirecting your worker.
In a deployment with authentication measures enabled like HTTPS and Single Sign-On, it may make sense to have the worker navigate directly to the Superset application running in the same location, avoiding the need to sign in. For instance, you could use `WEBDRIVER_BASEURL="http://superset_app:8088"` for a docker compose deployment, and set `"force_https": False,` in your `TALISMAN_CONFIG`.
In a deployment with authentication measures enabled like HTTPS and Single Sign-On, it may make sense to have the worker navigate directly to the Superset application running in the same location, avoiding the need to sign in. For instance, you could use `WEBDRIVER_BASEURL="http://superset_app:8088"` for a docker compose deployment, and set `"force_https": False,` in your `TALISMAN_CONFIG`.
### Duplicate report deliveries
@@ -495,6 +496,7 @@ schedule the queries that have `schedule_info` in their JSON metadata. For sched
Airflow, additional fields can be easily added to the configuration file above.
:::resources
- [Tutorial: Automated Alerts and Reporting via Slack/Email in Superset](https://dev.to/ngtduc693/apache-superset-topic-5-automated-alerts-and-reporting-via-slackemail-in-superset-2gbe)
- [Blog: Integrating Slack alerts and Apache Superset for better data observability](https://medium.com/affinityanswers-tech/integrating-slack-alerts-and-apache-superset-for-better-data-observability-fd2f9a12c350)
:::
:::

View File

@@ -104,5 +104,6 @@ celery --app=superset.tasks.celery_app:app flower
```
:::resources
- [Blog: How to Set Up Global Async Queries (GAQ) in Apache Superset](https://medium.com/@ngigilevis/how-to-set-up-global-async-queries-gaq-in-apache-superset-a-complete-guide-9d2f4a047559)
:::
:::

View File

@@ -1,26 +1,28 @@
{/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
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
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/}
---
title: AWS IAM Authentication
sidebar_label: AWS IAM Authentication
sidebar_position: 15
---
# AWS IAM Authentication for AWS Databases
@@ -31,7 +33,7 @@ Cross-account IAM role assumption via STS `AssumeRole` is supported, allowing a
## Prerequisites
- Enable the `AWS_DATABASE_IAM_AUTH` feature flag in `superset_config.py`. IAM authentication is gated behind this flag; if it is disabled, connections using `aws_iam` fail with *"AWS IAM database authentication is not enabled."*
- Enable the `AWS_DATABASE_IAM_AUTH` feature flag in `superset_config.py`. IAM authentication is gated behind this flag; if it is disabled, connections using `aws_iam` fail with _"AWS IAM database authentication is not enabled."_
```python
FEATURE_FLAGS = {
"AWS_DATABASE_IAM_AUTH": True,
@@ -66,14 +68,14 @@ IAM authentication is configured via the **encrypted_extra** field of the databa
}
```
| Field | Required | Description |
|-------|----------|-------------|
| `enabled` | Yes | Set to `true` to activate IAM auth |
| `role_arn` | No | ARN of the cross-account IAM role to assume via STS. Omit for same-account auth |
| `external_id` | No | External ID for the STS `AssumeRole` call, if required by the target role's trust policy |
| `region` | Yes | AWS region of the database cluster |
| `db_username` | Yes | The database username associated with the IAM identity |
| `session_duration` | No | STS session duration in seconds (default: `3600`) |
| Field | Required | Description |
| ------------------ | -------- | ---------------------------------------------------------------------------------------- |
| `enabled` | Yes | Set to `true` to activate IAM auth |
| `role_arn` | No | ARN of the cross-account IAM role to assume via STS. Omit for same-account auth |
| `external_id` | No | External ID for the STS `AssumeRole` call, if required by the target role's trust policy |
| `region` | Yes | AWS region of the database cluster |
| `db_username` | Yes | The database username associated with the IAM identity |
| `session_duration` | No | STS session duration in seconds (default: `3600`) |
### Redshift (Serverless)

View File

@@ -271,6 +271,7 @@ While database-backed operations work reliably, the Redis backend is recommended
deployments where low latency and reduced database load are important.
:::resources
- [Blog: The Data Engineer's Guide to Lightning-Fast Superset Dashboards](https://preset.io/blog/the-data-engineers-guide-to-lightning-fast-apache-superset-dashboards/)
- [Blog: Accelerating Dashboards with Materialized Views](https://preset.io/blog/accelerating-apache-superset-dashboards-with-materialized-views/)
:::
:::

View File

@@ -225,7 +225,7 @@ RequestHeader set X-Forwarded-Proto "https"
## Configuring the application root
*Please be advised that this feature is in BETA.*
_Please be advised that this feature is in BETA._
Superset supports running the application under a non-root path. The root path
prefix can be specified in one of three ways:
@@ -312,10 +312,13 @@ AUTH_USER_REGISTRATION_ROLE = "Public"
```
In case you want to assign the `Admin` role on new user registration, it can be assigned as follows:
```python
AUTH_USER_REGISTRATION_ROLE = "Admin"
```
If you encounter the [issue](https://github.com/apache/superset/issues/13243) of not being able to list users from the Superset main page settings, although a newly registered user has an `Admin` role, please re-run `superset init` to sync the required permissions. Below is the command to re-run `superset init` using docker compose.
```
docker-compose exec superset superset init
```
@@ -505,5 +508,6 @@ CELERY_BEAT_SCHEDULE = {
Adjust `retention_period_days` to control how long query rows are kept. Companion opt-in tasks (`prune_logs`, `prune_tasks`) exist for pruning the logs and tasks tables; see the commented-out examples in `superset/config.py`. Without enabling these tasks, the metadata database will grow unbounded over time.
:::resources
- [Blog: Feature Flags in Apache Superset](https://preset.io/blog/feature-flags-in-apache-superset-and-preset/)
:::
:::

View File

@@ -22,10 +22,10 @@ The current list of countries can be found in the src
The Country Maps visualization already ships with the maps for the following countries:
<ul style={{columns: 3}}>
{countriesData.countries.map((country, index) => (
<li key={index}>{country}</li>
))}
<ul style={{ columns: 3 }}>
{countriesData.countries.map((country, index) => (
<li key={index}>{country}</li>
))}
</ul>
## Adding a New Country

View File

@@ -7,7 +7,7 @@ version: 1
import featureFlags from '../_versioned_data/static/feature-flags.json';
export const FlagTable = ({flags}) => (
export const FlagTable = ({ flags }) => (
<table>
<thead>
<tr>
@@ -17,14 +17,21 @@ export const FlagTable = ({flags}) => (
</tr>
</thead>
<tbody>
{flags.map((flag) => (
{flags.map(flag => (
<tr key={flag.name}>
<td><code>{flag.name}</code></td>
<td><code>{flag.default ? 'True' : 'False'}</code></td>
<td>
<code>{flag.name}</code>
</td>
<td>
<code>{flag.default ? 'True' : 'False'}</code>
</td>
<td>
{flag.description}
{flag.docs && (
<> (<a href={flag.docs}>docs</a>)</>
<>
{' '}
(<a href={flag.docs}>docs</a>)
</>
)}
</td>
</tr>
@@ -50,12 +57,12 @@ FEATURE_FLAGS = {
Feature flags progress through lifecycle stages:
| Stage | Description |
|-------|-------------|
| Stage | Description |
| --------------- | ------------------------------------------------------------------------------ |
| **Development** | Experimental features under active development. May be incomplete or unstable. |
| **Testing** | Feature complete but undergoing testing. Usable but may contain bugs. |
| **Stable** | Production-ready features. Safe for all deployments. |
| **Deprecated** | Features scheduled for removal. Migrate away from these. |
| **Testing** | Feature complete but undergoing testing. Usable but may contain bugs. |
| **Stable** | Production-ready features. Safe for all deployments. |
| **Deprecated** | Features scheduled for removal. Migrate away from these. |
---

View File

@@ -148,10 +148,10 @@ datasets by saving the following YAML to file and then running the **import_data
```yaml
databases:
- database_name: main
tables:
- table_name: random_time_series
columns:
- column_name: ds
verbose_name: datetime
- database_name: main
tables:
- table_name: random_time_series
columns:
- column_name: ds
verbose_name: datetime
```

View File

@@ -18,7 +18,9 @@ DECKGL_BASE_MAP = [
['tile://https://your_personal_url/{z}/{x}/{y}.png', 'MyTile']
]
```
Openstreetmap tiles url can be added without prefix.
```python
DECKGL_BASE_MAP = [
['https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', 'OpenStreetMap']
@@ -26,6 +28,7 @@ DECKGL_BASE_MAP = [
```
Default values are:
```python
DECKGL_BASE_MAP = [
['https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'Streets (OSM)'],
@@ -46,6 +49,7 @@ Setting `DECKGL_BASE_MAP` overwrite default values
:::
After defining your map tiles, set them in these variables:
- `CORS_OPTIONS`
- `connect-src` of `TALISMAN_CONFIG` and `TALISMAN_CONFIG_DEV` variables.

View File

@@ -55,11 +55,11 @@ The MCP server runs as a separate process alongside Superset:
superset mcp run --host 127.0.0.1 --port 5008
```
| Flag | Default | Description |
|------|---------|-------------|
| `--host` | `127.0.0.1` | Host to bind to |
| `--port` | `5008` | Port to bind to |
| `--debug` | off | Enable debug logging |
| Flag | Default | Description |
| --------- | ----------- | -------------------- |
| `--host` | `127.0.0.1` | Host to bind to |
| `--port` | `5008` | Port to bind to |
| `--debug` | off | Enable debug logging |
The endpoint is available at `http://<host>:<port>/mcp`.
@@ -193,22 +193,24 @@ MCP_JWT_AUDIENCE = "your-audience"
:::warning
Store `MCP_JWT_SECRET` securely. Never commit it to version control. Use environment variables:
```python
import os
MCP_JWT_SECRET = os.environ.get("MCP_JWT_SECRET")
```
:::
#### JWT claims
The MCP server validates these standard claims:
| Claim | Config Key | Description |
|-------|-----------|-------------|
| `exp` | -- | Expiration time (always validated) |
| `iss` | `MCP_JWT_ISSUER` | Token issuer (optional but recommended) |
| `aud` | `MCP_JWT_AUDIENCE` | Token audience (optional but recommended) |
| `sub` | -- | Subject -- primary claim used to resolve the Superset user |
| Claim | Config Key | Description |
| ----- | ------------------ | ---------------------------------------------------------- |
| `exp` | -- | Expiration time (always validated) |
| `iss` | `MCP_JWT_ISSUER` | Token issuer (optional but recommended) |
| `aud` | `MCP_JWT_AUDIENCE` | Token audience (optional but recommended) |
| `sub` | -- | Subject -- primary claim used to resolve the Superset user |
#### User resolution
@@ -435,7 +437,7 @@ services:
superset:
image: apache/superset:latest
ports:
- "8088:8088"
- '8088:8088'
volumes:
- ./superset_config.py:/app/superset_config.py
environment:
@@ -443,9 +445,9 @@ services:
mcp:
image: apache/superset:latest
command: ["superset", "mcp", "run", "--host", "0.0.0.0", "--port", "5008"]
command: ['superset', 'mcp', 'run', '--host', '0.0.0.0', '--port', '5008']
ports:
- "5008:5008"
- '5008:5008'
volumes:
- ./superset_config.py:/app/superset_config.py
environment:
@@ -494,30 +496,30 @@ All MCP settings go in `superset_config.py`. Defaults are defined in `superset/m
### Core
| Setting | Default | Description |
|---------|---------|-------------|
| `MCP_SERVICE_HOST` | `"localhost"` | Host the MCP server binds to |
| `MCP_SERVICE_PORT` | `5008` | Port the MCP server binds to |
| `MCP_SERVICE_URL` | `None` | Public base URL for MCP-generated links (set this when behind a reverse proxy) |
| `MCP_DEBUG` | `False` | Enable debug logging |
| `MCP_DEV_USERNAME` | -- | Superset username for development mode (no auth) |
| `MCP_RBAC_ENABLED` | `True` | Enforce Superset's role-based access control on MCP tool calls. When `True`, each tool checks that the authenticated user has the required FAB permission before executing. Disable only for testing or trusted-network deployments. |
| Setting | Default | Description |
| ------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `MCP_SERVICE_HOST` | `"localhost"` | Host the MCP server binds to |
| `MCP_SERVICE_PORT` | `5008` | Port the MCP server binds to |
| `MCP_SERVICE_URL` | `None` | Public base URL for MCP-generated links (set this when behind a reverse proxy) |
| `MCP_DEBUG` | `False` | Enable debug logging |
| `MCP_DEV_USERNAME` | -- | Superset username for development mode (no auth) |
| `MCP_RBAC_ENABLED` | `True` | Enforce Superset's role-based access control on MCP tool calls. When `True`, each tool checks that the authenticated user has the required FAB permission before executing. Disable only for testing or trusted-network deployments. |
### Authentication
| Setting | Default | Description |
|---------|---------|-------------|
| `MCP_AUTH_ENABLED` | `False` | Enable JWT authentication |
| `MCP_JWT_ALGORITHM` | `"RS256"` | JWT signing algorithm (`RS256` or `HS256`) |
| `MCP_JWKS_URI` | `None` | JWKS endpoint URL (RS256) |
| `MCP_JWT_PUBLIC_KEY` | `None` | Static RSA public key string (RS256) |
| `MCP_JWT_SECRET` | `None` | Shared secret string (HS256) |
| `MCP_JWT_ISSUER` | `None` | Expected `iss` claim |
| `MCP_JWT_AUDIENCE` | `None` | Expected `aud` claim |
| `MCP_REQUIRED_SCOPES` | `[]` | Required JWT scopes |
| `MCP_JWT_DEBUG_ERRORS` | `False` | Log detailed JWT errors server-side (never exposed in HTTP responses per RFC 6750) |
| `MCP_AUTH_FACTORY` | `None` | Custom auth provider factory `(flask_app) -> auth_provider`. Takes precedence over built-in JWT |
| `MCP_USER_RESOLVER` | `None` | Custom function `(app, access_token) -> username` to extract a Superset username from a validated JWT token. When `None`, the default resolver checks `preferred_username`, `username`, `email`, and `sub` claims in that order. |
| Setting | Default | Description |
| ---------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MCP_AUTH_ENABLED` | `False` | Enable JWT authentication |
| `MCP_JWT_ALGORITHM` | `"RS256"` | JWT signing algorithm (`RS256` or `HS256`) |
| `MCP_JWKS_URI` | `None` | JWKS endpoint URL (RS256) |
| `MCP_JWT_PUBLIC_KEY` | `None` | Static RSA public key string (RS256) |
| `MCP_JWT_SECRET` | `None` | Shared secret string (HS256) |
| `MCP_JWT_ISSUER` | `None` | Expected `iss` claim |
| `MCP_JWT_AUDIENCE` | `None` | Expected `aud` claim |
| `MCP_REQUIRED_SCOPES` | `[]` | Required JWT scopes |
| `MCP_JWT_DEBUG_ERRORS` | `False` | Log detailed JWT errors server-side (never exposed in HTTP responses per RFC 6750) |
| `MCP_AUTH_FACTORY` | `None` | Custom auth provider factory `(flask_app) -> auth_provider`. Takes precedence over built-in JWT |
| `MCP_USER_RESOLVER` | `None` | Custom function `(app, access_token) -> username` to extract a Superset username from a validated JWT token. When `None`, the default resolver checks `preferred_username`, `username`, `email`, and `sub` claims in that order. |
### Response Size Guard
@@ -537,12 +539,12 @@ MCP_RESPONSE_SIZE_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `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 |
| `excluded_tools` | See above | Tools exempt from size checking (e.g., tools that return URLs, not data) |
| Key | Default | Description |
| -------------------- | --------- | ------------------------------------------------------------------------ |
| `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 |
| `excluded_tools` | See above | Tools exempt from size checking (e.g., tools that return URLs, not data) |
### Caching
@@ -568,18 +570,18 @@ MCP_CACHE_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `enabled` | `False` | Enable response caching |
| `CACHE_KEY_PREFIX` | `None` | Optional prefix for cache keys (useful for shared Redis) |
| `list_tools_ttl` | `300` | Cache TTL in seconds for `tools/list` |
| `list_resources_ttl` | `300` | Cache TTL for `resources/list` |
| `list_prompts_ttl` | `300` | Cache TTL for `prompts/list` |
| `read_resource_ttl` | `3600` | Cache TTL for `resources/read` |
| `get_prompt_ttl` | `3600` | Cache TTL for `prompts/get` |
| `call_tool_ttl` | `3600` | Cache TTL for `tools/call` |
| `max_item_size` | `1048576` | Maximum cached item size in bytes (1 MB) |
| `excluded_tools` | See above | Tools that are never cached (mutating or non-deterministic) |
| Key | Default | Description |
| -------------------- | --------- | ----------------------------------------------------------- |
| `enabled` | `False` | Enable response caching |
| `CACHE_KEY_PREFIX` | `None` | Optional prefix for cache keys (useful for shared Redis) |
| `list_tools_ttl` | `300` | Cache TTL in seconds for `tools/list` |
| `list_resources_ttl` | `300` | Cache TTL for `resources/list` |
| `list_prompts_ttl` | `300` | Cache TTL for `prompts/list` |
| `read_resource_ttl` | `3600` | Cache TTL for `resources/read` |
| `get_prompt_ttl` | `3600` | Cache TTL for `prompts/get` |
| `call_tool_ttl` | `3600` | Cache TTL for `tools/call` |
| `max_item_size` | `1048576` | Maximum cached item size in bytes (1 MB) |
| `excluded_tools` | See above | Tools that are never cached (mutating or non-deterministic) |
### Redis Store (Multi-Pod)
@@ -594,12 +596,12 @@ MCP_STORE_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `enabled` | `False` | Enable Redis-backed store |
| `CACHE_REDIS_URL` | `None` | Redis connection URL (e.g., `redis://redis-host:6379/0`) |
| `event_store_max_events` | `100` | Maximum events retained per session |
| `event_store_ttl` | `3600` | Event TTL in seconds |
| Key | Default | Description |
| ------------------------ | ------- | -------------------------------------------------------- |
| `enabled` | `False` | Enable Redis-backed store |
| `CACHE_REDIS_URL` | `None` | Redis connection URL (e.g., `redis://redis-host:6379/0`) |
| `event_store_max_events` | `100` | Maximum events retained per session |
| `event_store_ttl` | `3600` | Event TTL in seconds |
### Tool Search
@@ -622,15 +624,15 @@ MCP_TOOL_SEARCH_CONFIG = {
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `enabled` | `True` | Enable tool search. When `False`, all tools are listed upfront |
| `strategy` | `"bm25"` | Search ranking algorithm. `"bm25"` supports natural language; `"regex"` supports pattern matching |
| `max_results` | `5` | Maximum tools returned per search query |
| `always_visible` | See above | Tools that always appear in `list_tools`, regardless of search |
| `include_schemas` | `False` | When `False` (default, "summary mode"), search results omit `inputSchema` entirely and include a lightweight `parameters_hint` listing top-level parameter names. Set to `True` to include the full `inputSchema` in search results. Full schemas are always used when a tool is actually invoked via `call_tool`. |
| `compact_schemas` | `True` | Strip `$defs` / `$ref` and replace with `{"type": "object"}` in search results to reduce token cost. Only takes effect when `include_schemas=True` — ignored in summary mode. |
| `max_description_length` | `300` | Truncate tool descriptions in search results (0 = no truncation). Applies in both summary and full-schema modes. |
| Key | Default | Description |
| ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `enabled` | `True` | Enable tool search. When `False`, all tools are listed upfront |
| `strategy` | `"bm25"` | Search ranking algorithm. `"bm25"` supports natural language; `"regex"` supports pattern matching |
| `max_results` | `5` | Maximum tools returned per search query |
| `always_visible` | See above | Tools that always appear in `list_tools`, regardless of search |
| `include_schemas` | `False` | When `False` (default, "summary mode"), search results omit `inputSchema` entirely and include a lightweight `parameters_hint` listing top-level parameter names. Set to `True` to include the full `inputSchema` in search results. Full schemas are always used when a tool is actually invoked via `call_tool`. |
| `compact_schemas` | `True` | Strip `$defs` / `$ref` and replace with `{"type": "object"}` in search results to reduce token cost. Only takes effect when `include_schemas=True` — ignored in summary mode. |
| `max_description_length` | `300` | Truncate tool descriptions in search results (0 = no truncation). Applies in both summary and full-schema modes. |
:::tip
Set `enabled: False` to revert to the traditional "show all tools at once" behavior, which some clients or workflows may prefer.
@@ -667,16 +669,16 @@ The MCP server respects Superset's full role-based access control (RBAC). Every
Each tool declares one or more required FAB permissions. The table below maps tool groups to their permission requirements:
| Tool group | Required FAB permission |
|------------|------------------------|
| `list_charts`, `get_chart_info`, `get_chart_data`, `get_chart_preview`, `generate_chart`, `update_chart` | `can_read` on `Chart` (read), `can_write` on `Chart` (mutate) |
| `list_dashboards`, `get_dashboard_info`, `generate_dashboard`, `add_chart_to_existing_dashboard` | `can_read` on `Dashboard` (read), `can_write` on `Dashboard` (mutate) |
| `list_datasets`, `get_dataset_info`, `create_virtual_dataset` | `can_read` on `Dataset` (read), `can_write` on `Dataset` (mutate) |
| `list_databases`, `get_database_info` | `can_read` on `Database` |
| `execute_sql` | `can_execute_sql_query` on `SQLLab` |
| `open_sql_lab_with_context` | `can_read` on `SQLLab` |
| `save_sql_query` | `can_write` on `SavedQuery` |
| `health_check` | None (public) |
| Tool group | Required FAB permission |
| -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `list_charts`, `get_chart_info`, `get_chart_data`, `get_chart_preview`, `generate_chart`, `update_chart` | `can_read` on `Chart` (read), `can_write` on `Chart` (mutate) |
| `list_dashboards`, `get_dashboard_info`, `generate_dashboard`, `add_chart_to_existing_dashboard` | `can_read` on `Dashboard` (read), `can_write` on `Dashboard` (mutate) |
| `list_datasets`, `get_dataset_info`, `create_virtual_dataset` | `can_read` on `Dataset` (read), `can_write` on `Dataset` (mutate) |
| `list_databases`, `get_database_info` | `can_read` on `Database` |
| `execute_sql` | `can_execute_sql_query` on `SQLLab` |
| `open_sql_lab_with_context` | `can_read` on `SQLLab` |
| `save_sql_query` | `can_write` on `SavedQuery` |
| `health_check` | None (public) |
To disable RBAC checking globally (for trusted-network deployments or testing), set:
@@ -703,13 +705,13 @@ This makes MCP activity fully auditable alongside regular Superset activity. The
Every MCP request passes through a middleware stack before reaching the tool function. The default stack (assembled in `build_middleware_list()` in `server.py`) is:
| Middleware | Purpose | Default |
|------------|---------|---------|
| `StructuredContentStripperMiddleware` | Strips `structuredContent` from responses for Claude.ai bridge compatibility | Enabled |
| `LoggingMiddleware` | Logs each tool call with user, parameters, and duration | Enabled |
| `GlobalErrorHandlerMiddleware` | Catches unhandled exceptions and sanitizes sensitive data before it reaches the client | Enabled |
| `ResponseSizeGuardMiddleware` | Estimates token count, warns at 80% of limit, blocks at limit | Enabled (configurable via `MCP_RESPONSE_SIZE_CONFIG`) |
| `ResponseCachingMiddleware` | Caches read-heavy tool responses (in-memory or Redis) | Disabled (enable via `MCP_CACHE_CONFIG`) |
| Middleware | Purpose | Default |
| ------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `StructuredContentStripperMiddleware` | Strips `structuredContent` from responses for Claude.ai bridge compatibility | Enabled |
| `LoggingMiddleware` | Logs each tool call with user, parameters, and duration | Enabled |
| `GlobalErrorHandlerMiddleware` | Catches unhandled exceptions and sanitizes sensitive data before it reaches the client | Enabled |
| `ResponseSizeGuardMiddleware` | Estimates token count, warns at 80% of limit, blocks at limit | Enabled (configurable via `MCP_RESPONSE_SIZE_CONFIG`) |
| `ResponseCachingMiddleware` | Caches read-heavy tool responses (in-memory or Redis) | Disabled (enable via `MCP_CACHE_CONFIG`) |
Additional middleware classes (`RateLimitMiddleware`, `FieldPermissionsMiddleware`, `PrivateToolMiddleware`) are implemented in `superset/mcp_service/middleware.py` but are not added to the default pipeline. They are available for operators who want to layer them in via a custom startup path.

View File

@@ -8,12 +8,10 @@ version: 1
## CORS
:::note
In Superset versions prior to `5.x` you have to install to install `flask-cors` with `pip install flask-cors` to enable CORS support.
:::
The following keys in `superset_config.py` can be specified to configure CORS:
- `ENABLE_CORS`: Must be set to `True` in order to enable CORS
@@ -54,11 +52,13 @@ Restart Superset for this configuration change to take effect.
There are two approaches to making dashboards publicly accessible:
**Option 1: Dataset-based access (simpler)**
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
2. Grant the Public role access to the relevant datasets (Menu → Security → List Roles → Public)
3. All published dashboards using those datasets become visible to anonymous users
**Option 2: Dashboard-level access (selective control)**
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
2. Add the `'DASHBOARD_RBAC': True` [Feature Flag](/admin-docs/configuration/feature-flags)
3. Edit each dashboard's properties and add the "Public" role
@@ -75,7 +75,7 @@ Now anybody can directly access the dashboard's URL. You can embed it in an ifra
width="600"
height="400"
seamless
frameBorder="0"
frameborder="0"
scrolling="no"
src="https://superset.my-domain.com/superset/dashboard/10/?standalone=1&height=400"
>
@@ -123,17 +123,17 @@ running a custom auth postback endpoint), you can add the endpoints to `WTF_CSRF
## SSH Tunneling
1. Turn on feature flag
- Change [`SSH_TUNNELING`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L489) to `True`
- If you want to add more security when establishing the tunnel we allow users to overwrite the `SSHTunnelManager` class [here](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L507)
- You can also set the [`SSH_TUNNEL_LOCAL_BIND_ADDRESS`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L508) this the host address where the tunnel will be accessible on your VPC
- Change [`SSH_TUNNELING`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L489) to `True`
- If you want to add more security when establishing the tunnel we allow users to overwrite the `SSHTunnelManager` class [here](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L507)
- You can also set the [`SSH_TUNNEL_LOCAL_BIND_ADDRESS`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L508) this the host address where the tunnel will be accessible on your VPC
2. Create database w/ ssh tunnel enabled
- With the feature flag enabled you should now see ssh tunnel toggle.
- Click the toggle to enable SSH tunneling and add your credentials accordingly.
- Superset allows for two different types of authentication (Basic + Private Key). These credentials should come from your service provider.
- With the feature flag enabled you should now see ssh tunnel toggle.
- Click the toggle to enable SSH tunneling and add your credentials accordingly.
- Superset allows for two different types of authentication (Basic + Private Key). These credentials should come from your service provider.
3. Verify data is flowing
- Once SSH tunneling has been enabled, go to SQL Lab and write a query to verify data is properly flowing.
- Once SSH tunneling has been enabled, go to SQL Lab and write a query to verify data is properly flowing.
## Domain Sharding

View File

@@ -106,6 +106,7 @@ WHERE dttm_col > '{{ from_dttm | default("2024-01-01", true) }}'
**Option 2: Use SQL Lab Parameters**
Set parameters in the SQL Lab UI (Parameters menu):
```json
{
"from_dttm": "2024-01-01",
@@ -151,7 +152,7 @@ In the UI you can assign a set of parameters as JSON
The parameters become available in your SQL (example: `SELECT * FROM {{ my_table }}` ) by using Jinja templating syntax.
SQL Lab template parameters are stored with the dataset as `TEMPLATE PARAMETERS`.
There is a special ``_filters`` parameter which can be used to test filters used in the jinja template.
There is a special `_filters` parameter which can be used to test filters used in the jinja template.
```json
{
@@ -172,7 +173,7 @@ WHERE action in {{ filter_values('action_type')|where_in }}
GROUP BY action
```
Note ``_filters`` is not stored with the dataset. It's only used within the SQL Lab UI.
Note `_filters` is not stored with the dataset. It's only used within the SQL Lab UI.
Besides default Jinja templating, SQL lab also supports self-defined template processor by setting
the `CUSTOM_TEMPLATE_PROCESSORS` in your superset configuration. The values in this dictionary
@@ -306,16 +307,19 @@ cache key by adding the following parameter to your Jinja code:
```
You can json-stringify the array by adding `|tojson` to your Jinja code:
```python
{{ current_user_roles()|tojson }}
```
You can use the `|where_in` filter to use your roles in a SQL statement. For example, if `current_user_roles()` returns `['admin', 'viewer']`, the following template:
```python
SELECT * FROM users WHERE role IN {{ current_user_roles()|where_in }}
```
Will be rendered as:
```sql
SELECT * FROM users WHERE role IN ('admin', 'viewer')
```
@@ -341,6 +345,7 @@ Always treat `url_param()` values as untrusted input. Escaping behaviour varies
{% if cc not in ('US', 'ES', 'FR') %}{% set cc = 'US' %}{% endif %}
WHERE country_code = '{{ cc }}'
```
:::
Here's a concrete example:
@@ -425,6 +430,7 @@ This is useful if:
AND full_name LIKE '{{ filter.get('val') | replace("'", "''") }}'
{%- endif -%}
```
:::
Here's a concrete example:
@@ -489,7 +495,7 @@ The macro takes the following parameters:
- `column`: Name of the temporal column. Leave undefined to reference the time range from a Dashboard Native Time Range
filter (when present).
- `default`: The default value to fall back to if the time filter is not present, or has the value `No filter`
- `target_type`: The target temporal type as recognized by the target database (e.g. `TIMESTAMP`, `DATE` or
- `target_type`: The target temporal type as recognized by the target database (e.g. `TIMESTAMP`, `DATE` or
`DATETIME`). If `column` is defined, the format will default to the type of the column. This is used to produce
the format of the `from_expr` and `to_expr` properties of the returned `TimeFilter` object.
- `strftime`: format using the `strftime` method of `datetime` for custom time formatting.
@@ -595,6 +601,7 @@ The parameter can be used in SQL Lab, or when fetching a metric from another dat
Superset supports [builtin filters from the Jinja2 templating package](https://jinja.palletsprojects.com/en/stable/templates/#builtin-filters). Custom filters have also been implemented:
### Where In
Parses a list into a SQL-compatible statement. This is useful with macros that return an array (for example the `filter_values` macro):
```
@@ -614,6 +621,7 @@ Dashboard filter without any value applied
### To Datetime
Loads a string as a `datetime` object. This is useful when performing date operations. For example:
```
{% set from_expr = get_time_filter("dttm", strftime="%Y-%m-%d").from_expr %}
{% set to_expr = get_time_filter("dttm", strftime="%Y-%m-%d").to_expr %}
@@ -625,5 +633,6 @@ Loads a string as a `datetime` object. This is useful when performing date opera
```
:::resources
- [Blog: Intro to Jinja Templating in Apache Superset](https://preset.io/blog/intro-jinja-templating-apache-superset/)
:::
:::

View File

@@ -4,6 +4,7 @@ hide_title: true
sidebar_position: 12
version: 1
---
# Theming Superset
:::note
@@ -34,11 +35,13 @@ You can also extend with Superset-specific tokens (documented in the default the
When `ENABLE_UI_THEME_ADMINISTRATION = True` is configured, administrators can manage system-wide themes directly from the UI:
#### Setting System Themes
- **System Default Theme**: Click the sun icon on any theme to set it as the system-wide default
- **System Dark Theme**: Click the moon icon on any theme to set it as the system dark mode theme
- **Automatic OS Detection**: When both default and dark themes are set, Superset automatically detects and applies the appropriate theme based on OS preferences
#### Managing System Themes
- System themes are indicated with special badges in the theme list
- Only administrators with write permissions can modify system theme settings
- Removing a system theme designation reverts to configuration file defaults
@@ -46,6 +49,7 @@ When `ENABLE_UI_THEME_ADMINISTRATION = True` is configured, administrators can m
### Applying Themes to Dashboards
Once created, themes can be applied to individual dashboards:
- Edit any dashboard and select your custom theme from the theme dropdown
- Each dashboard can have its own theme, allowing for branded or context-specific styling
@@ -127,6 +131,7 @@ When `ENABLE_UI_THEME_ADMINISTRATION = True`:
Superset validates theme JSON when it is saved, either through the UI or via configuration. If a theme contains invalid tokens or an unrecognized structure, Superset logs a warning and falls back to the built-in default theme rather than applying a broken configuration. This prevents a bad theme from rendering the application unusable.
The fallback order is:
1. **UI-configured system theme** (highest priority, if `ENABLE_UI_THEME_ADMINISTRATION = True`)
2. **`THEME_DEFAULT` / `THEME_DARK`** from `superset_config.py`
3. **Built-in Superset default theme** (always present as a safety net)
@@ -455,9 +460,10 @@ For programmatic theme management, Superset provides REST endpoints:
These endpoints require appropriate permissions and are subject to RBAC controls.
:::resources
- [Video: Live Demo — Theming Apache Superset](https://www.youtube.com/watch?v=XsZAsO9tC3o)
- [CSS and Theming](https://docs.preset.io/docs/css-and-theming) - Additional theming techniques and CSS customization
- [Blog: Customizing Apache Superset Dashboards with CSS](https://preset.io/blog/customizing-superset-dashboards-with-css/)
- [Blog: Customizing Dashboards with CSS — Tips and Tricks](https://preset.io/blog/customizing-apache-superset-dashboards-with-css-additional-tips-and-tricks/)
- [Blog: Customizing Chart Colors](https://preset.io/blog/customizing-chart-colors-with-superset-and-preset/)
:::
:::

View File

@@ -5,7 +5,7 @@ sidebar_position: 1
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Architecture

View File

@@ -11,8 +11,7 @@ The Apache Superset community extensively uses Docker for development, release,
and productionizing Superset. This page details our Docker builds and tag naming
schemes to help users navigate our offerings.
Images are built and pushed to the [Superset Docker Hub repository](
https://hub.docker.com/r/apache/superset) using GitHub Actions.
Images are built and pushed to the [Superset Docker Hub repository](https://hub.docker.com/r/apache/superset) using GitHub Actions.
Different sets of images are built and/or published at different times:
- **Published releases** (`release`): published using

View File

@@ -5,12 +5,13 @@ sidebar_position: 5
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Using Docker Compose
<img src={useBaseUrl("/img/docker-compose.webp" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/docker-compose.webp')} width="150" />
<br />
<br />
:::caution
Since `docker compose` is primarily designed to run a set of containers on **a single host**
@@ -29,23 +30,23 @@ way to launch a fully functioning **development environment** quickly.
Note that there are 4 major ways we support to run `docker compose`:
1. **docker-compose.yml:** for interactive development, where we mount your local folder with the
frontend/backend files that you can edit and experience the changes you
make in the app in real time
frontend/backend files that you can edit and experience the changes you
make in the app in real time
1. **docker-compose-light.yml:** a lightweight configuration with minimal services (database,
Superset app, and frontend dev server) for development. Uses in-memory caching instead of Redis
and is designed for running multiple instances simultaneously
Superset app, and frontend dev server) for development. Uses in-memory caching instead of Redis
and is designed for running multiple instances simultaneously
1. **docker-compose-non-dev.yml** where we just build a more immutable image based on the
local branch and get all the required images running. Changes in the local branch
at the time you fire this up will be reflected, but changes to the code
while `up` won't be reflected in the app
local branch and get all the required images running. Changes in the local branch
at the time you fire this up will be reflected, but changes to the code
while `up` won't be reflected in the app
1. **docker-compose-image-tag.yml** where we fetch an image from docker-hub say for the
`5.0.0` release for instance, and fire it up so you can try it. Here what's in
the local branch has no effects on what's running, we just fetch and run
pre-built images from docker-hub. For `docker compose` to work along with the
Postgres image it boots up, you'll want to point to a `-dev`-suffixed TAG, as in
`export TAG=5.0.0-dev` or `export TAG=4.1.2-dev`, with `latest-dev` being the default.
The `dev` builds include the `psycopg2-binary` required to connect
to the Postgres database launched as part of the `docker compose` builds.
`5.0.0` release for instance, and fire it up so you can try it. Here what's in
the local branch has no effects on what's running, we just fetch and run
pre-built images from docker-hub. For `docker compose` to work along with the
Postgres image it boots up, you'll want to point to a `-dev`-suffixed TAG, as in
`export TAG=5.0.0-dev` or `export TAG=4.1.2-dev`, with `latest-dev` being the default.
The `dev` builds include the `psycopg2-binary` required to connect
to the Postgres database launched as part of the `docker compose` builds.
More on these approaches after setting up the requirements for either.
@@ -92,7 +93,7 @@ like to try out Superset without making any code changes follow the steps docume
:::tip
By default, we mount the local superset-frontend folder here and run `npm install` as well
as `npm run dev` which triggers webpack to compile/bundle the frontend code. Depending
on your local setup, especially if you have less than 16GB of memory, it may be very slow to
on your local setup, especially if you have less than 16GB of memory, it may be very slow to
perform those operations. In this case, we recommend you set the env var
`BUILD_SUPERSET_FRONTEND_IN_DOCKER` to `false`, and to run this locally instead in a terminal.
Simply trigger `npm i && npm run dev`, this should be MUCH faster.
@@ -121,6 +122,7 @@ NODE_PORT=9003 docker compose -p superset-3 -f docker-compose-light.yml up
```
This configuration includes:
- PostgreSQL database (internal network only)
- Superset application server
- Frontend development server with webpack hot reloading
@@ -165,7 +167,7 @@ looking to fire up.
:::caution
All of the content belonging to a Superset instance - charts, dashboards, users, etc. - is stored in
its metadata database. In production, this database should be backed up. The default installation
its metadata database. In production, this database should be backed up. The default installation
with docker compose will store that data in a PostgreSQL database contained in a Docker
[volume](https://docs.docker.com/storage/volumes/), which is not backed up.
@@ -174,7 +176,7 @@ Again, **THE DOCKER-COMPOSE INSTALLATION IS NOT PRODUCTION-READY OUT OF THE BOX.
:::
You should see a stream of logging output from the containers being launched on your machine. Once
this output slows, you should have a running instance of Superset on your local machine! To avoid
this output slows, you should have a running instance of Superset on your local machine! To avoid
the wall of text on future runs, add the `-d` option to the end of the `docker compose up` command.
### Configuring Further
@@ -258,24 +260,24 @@ Superset (which is running in its docker container). Other databases may have sl
configurations but gist would be same and boils down to 2 steps -
1. **(Mac users may skip this step)** Configuring the local postgresql/database instance to accept
public incoming connections. By default, postgresql only allows incoming connections from
`localhost` and under Docker, unless you use `--network=host`, `localhost` will refer to different
endpoints on the host machine and in a docker container respectively. Allowing postgresql to accept
connections from the Docker involves making one-line changes to the files `postgresql.conf` and
`pg_hba.conf`; you can find helpful links tailored to your OS / PG version on the web easily for
this task. For Docker it suffices to only whitelist IPs `172.0.0.0/8` instead of `*`, but in any
case you are _warned_ that doing this in a production database _may_ have disastrous consequences as
you are opening your database to the public internet.
public incoming connections. By default, postgresql only allows incoming connections from
`localhost` and under Docker, unless you use `--network=host`, `localhost` will refer to different
endpoints on the host machine and in a docker container respectively. Allowing postgresql to accept
connections from the Docker involves making one-line changes to the files `postgresql.conf` and
`pg_hba.conf`; you can find helpful links tailored to your OS / PG version on the web easily for
this task. For Docker it suffices to only whitelist IPs `172.0.0.0/8` instead of `*`, but in any
case you are _warned_ that doing this in a production database _may_ have disastrous consequences as
you are opening your database to the public internet.
1. Instead of `localhost`, try using `host.docker.internal` (Mac users, Ubuntu) or `172.18.0.1`
(Linux users) as the hostname when attempting to connect to the database. This is a Docker internal
detail -- what is happening is that, in Mac systems, Docker Desktop creates a dns entry for the
hostname `host.docker.internal` which resolves to the correct address for the host machine, whereas
in Linux this is not the case (at least by default). If neither of these 2 hostnames work then you
may want to find the exact hostname you want to use, for that you can do `ifconfig` or
`ip addr show` and look at the IP address of `docker0` interface that must have been created by
Docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo)
`docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP
address.
(Linux users) as the hostname when attempting to connect to the database. This is a Docker internal
detail -- what is happening is that, in Mac systems, Docker Desktop creates a dns entry for the
hostname `host.docker.internal` which resolves to the correct address for the host machine, whereas
in Linux this is not the case (at least by default). If neither of these 2 hostnames work then you
may want to find the exact hostname you want to use, for that you can do `ifconfig` or
`ip addr show` and look at the IP address of `docker0` interface that must have been created by
Docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo)
`docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP
address.
## 4. To build or not to build

View File

@@ -5,7 +5,7 @@ sidebar_position: 2
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installation Methods

View File

@@ -1,16 +1,17 @@
---
title: Kubernetes
title: Kubernetes
hide_title: true
sidebar_position: 3
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installing on Kubernetes
<img src={useBaseUrl("/img/k8s.png" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/k8s.png')} width="150" />
<br />
<br />
Running Superset on Kubernetes is supported with the provided [Helm](https://helm.sh/) chart
found in the official [Superset helm repository](https://apache.github.io/superset/index.yaml).
@@ -134,7 +135,7 @@ init:
```
:::note
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
To opt-out of this data collection in your Helm-based installation, edit the `repository:` line in your `helm/superset/values.yaml` file, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub.
:::
@@ -195,7 +196,7 @@ Those can be passed as key/values either with `extraEnv` or `extraSecretEnv` if
extraEnv:
SMTP_HOST: smtp.gmail.com
SMTP_USER: user@gmail.com
SMTP_PORT: "587"
SMTP_PORT: '587'
SMTP_MAIL_FROM: user@gmail.com
extraSecretEnv:
@@ -356,7 +357,7 @@ supersetCeleryBeat:
extraEnv:
SMTP_HOST: smtp.gmail.com
SMTP_USER: user@gmail.com
SMTP_PORT: "587"
SMTP_PORT: '587'
SMTP_MAIL_FROM: user@gmail.com
extraSecretEnv:
@@ -446,6 +447,7 @@ init:
```
:::resources
- [Tutorial: Mastering Data Visualization — Installing Superset on Kubernetes with Helm Chart](https://mahira-technology.medium.com/mastering-data-visualization-installing-superset-on-kubernetes-cluster-using-helm-chart-e4ec99199e1e)
- [Tutorial: Installing Apache Superset in Kubernetes](https://aws.plainenglish.io/installing-apache-superset-in-kubernetes-1aec192ac495)
:::
:::

View File

@@ -5,12 +5,13 @@ sidebar_position: 4
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installing Superset from PyPI
<img src={useBaseUrl("/img/pypi.png" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/pypi.png')} width="150" />
<br />
<br />
This page describes how to install Superset using the `apache_superset` package [published on PyPI](https://pypi.org/project/apache_superset/).
@@ -23,6 +24,7 @@ level dependencies.
**Debian and Ubuntu**
Ubuntu **24.04** uses python 3.12 per default, which currently is not supported by Superset. You need to add a second python installation of 3.11 and install the required additional dependencies.
```bash
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
@@ -133,6 +135,7 @@ pip install apache_superset
```
Then, define mandatory configurations, SECRET_KEY and FLASK_APP:
```bash
export SUPERSET_SECRET_KEY=YOUR-SECRET-KEY # For production use, make sure this is a strong key, for example generated using `openssl rand -base64 42`. See https://superset.apache.org/admin-docs/configuration/configuring-superset#specifying-a-secret_key
export FLASK_APP=superset

View File

@@ -55,6 +55,7 @@ For a detailed list of breaking changes and migration notes for each version, se
This file documents backwards-incompatible changes and provides guidance for migrating between
major versions, including:
- Configuration changes
- API changes
- Database migrations

View File

@@ -2,41 +2,42 @@
title: CVEs fixed by release
sidebar_position: 2
---
#### Version 6.0.0
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2026-23980 | Improper Neutralization of Special Elements used in a SQL Command | < 6.0.0 |
| CVE-2026-23982 | Improper Authorization in Dataset Creation Allows Access Control Bypass | < 6.0.0 |
| CVE-2026-23983 | Information Disclosure of sensitive user info via Tags | < 6.0.0 |
| CVE-2026-23984 | SQLLab Read-Only Bypass on PostgreSQL (DML execution) | < 6.0.0 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------------------- | -------: |
| CVE-2026-23980 | Improper Neutralization of Special Elements used in a SQL Command | < 6.0.0 |
| CVE-2026-23982 | Improper Authorization in Dataset Creation Allows Access Control Bypass | < 6.0.0 |
| CVE-2026-23983 | Information Disclosure of sensitive user info via Tags | < 6.0.0 |
| CVE-2026-23984 | SQLLab Read-Only Bypass on PostgreSQL (DML execution) | < 6.0.0 |
#### Version 5.0.0
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2025-55673 | Exposure of Sensitive Information to an Unauthorized Actor | < 5.0.0 |
| CVE-2025-55674 | Improper Neutralization of Special Elements used in an SQL Command | < 5.0.0 |
| CVE-2025-55675 | Improper Access Control leading to Information Disclosure | < 5.0.0 |
| CVE | Title | Affected |
| :------------- | :----------------------------------------------------------------- | -------: |
| CVE-2025-55673 | Exposure of Sensitive Information to an Unauthorized Actor | < 5.0.0 |
| CVE-2025-55674 | Improper Neutralization of Special Elements used in an SQL Command | < 5.0.0 |
| CVE-2025-55675 | Improper Access Control leading to Information Disclosure | < 5.0.0 |
#### Version 4.1.3
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2025-55672 | Improper Neutralization of Input During Web Page Generation | < 4.1.3 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------- | -------: |
| CVE-2025-55672 | Improper Neutralization of Input During Web Page Generation | < 4.1.3 |
#### Version 4.1.2
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| CVE-2025-27696 | Improper authorization leading to resource ownership takeover | < 4.1.2 |
| CVE-2025-48912 | Improper authorization bypass on row level security via SQL Injection | < 4.1.2 |
| CVE-2026-23969 | Exposure of Sensitive Information via Incomplete ClickHouse Function Filtering | < 4.1.2 |
| CVE | Title | Affected |
| :------------- | :----------------------------------------------------------------------------- | -------: |
| CVE-2025-27696 | Improper authorization leading to resource ownership takeover | < 4.1.2 |
| CVE-2025-48912 | Improper authorization bypass on row level security via SQL Injection | < 4.1.2 |
| CVE-2026-23969 | Exposure of Sensitive Information via Incomplete ClickHouse Function Filtering | < 4.1.2 |
#### Version 4.1.0
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------------|---------:|
| :------------- | :--------------------------------------------------------------------------------- | -------: |
| CVE-2024-53947 | Improper SQL authorisation, parse for specific postgres functions | < 4.1.0 |
| CVE-2024-53948 | Error verbosity exposes metadata in analytics databases | < 4.1.0 |
| CVE-2024-53949 | Lower privilege users are able to create Role when FAB_ADD_SECURITY_API is enabled | < 4.1.0 |
@@ -44,84 +45,84 @@ sidebar_position: 2
#### Version 4.0.2
| CVE | Title | Affected |
|:---------------|:----------------------------|---------:|
| CVE-2024-39887 | Improper SQL authorization | < 4.0.1 |
| CVE | Title | Affected |
| :------------- | :------------------------- | -------: |
| CVE-2024-39887 | Improper SQL authorization | < 4.0.1 |
#### Version 3.1.3, 4.0.1
| CVE | Title | Affected |
|:---------------|:----------------------------|----------------------------:|
| CVE-2024-34693 | Server arbitrary file read | < 3.1.3, >= 4.0.0, < 4.0.1 |
| CVE | Title | Affected |
| :------------- | :------------------------- | -------------------------: |
| CVE-2024-34693 | Server arbitrary file read | < 3.1.3, >= 4.0.0, < 4.0.1 |
#### Version 3.1.2
| CVE | Title | Affected |
|:---------------|:--------------------------------------------------------|---------:|
| CVE-2024-28148 | Incorrect datasource authorization on explore REST API | < 3.1.2 |
| CVE | Title | Affected |
| :------------- | :----------------------------------------------------- | -------: |
| CVE-2024-28148 | Incorrect datasource authorization on explore REST API | < 3.1.2 |
#### Version 3.0.4, 3.1.1
| CVE | Title | Affected |
|:---------------|:-----------------------------------------------------------------------------|----------------------------:|
| CVE-2024-27315 | Improper error handling on alerts | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24773 | Improper validation of SQL statements allows for unauthorized access to data | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24772 | Improper Neutralisation of custom SQL on embedded context | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24779 | Improper data authorization when creating a new dataset | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-26016 | Improper authorization validation on dashboards and charts import | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE | Title | Affected |
| :------------- | :--------------------------------------------------------------------------- | -------------------------: |
| CVE-2024-27315 | Improper error handling on alerts | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24773 | Improper validation of SQL statements allows for unauthorized access to data | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24772 | Improper Neutralisation of custom SQL on embedded context | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-24779 | Improper data authorization when creating a new dataset | < 3.0.4, >= 3.1.0, < 3.1.1 |
| CVE-2024-26016 | Improper authorization validation on dashboards and charts import | < 3.0.4, >= 3.1.0, < 3.1.1 |
#### Version 3.0.3
| CVE | Title | Affected |
|:---------------|:----------------------------------------------|---------:|
| :------------- | :-------------------------------------------- | -------: |
| CVE-2023-49657 | Stored XSS in Dashboard Title and Chart Title | < 3.0.3 |
#### Version 3.0.2, 2.1.3
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------|---------------------------:|
| :------------- | :---------------------------------------------------------- | -------------------------: |
| CVE-2023-46104 | Allows for uncontrolled resource consumption via a ZIP bomb | < 2.1.3, >= 3.0.0, < 3.0.2 |
| CVE-2023-49736 | SQL Injection on where_in JINJA macro | < 2.1.3, >= 3.0.0, < 3.0.2 |
| CVE-2023-49734 | Privilege Escalation Vulnerability | < 2.1.3, >= 3.0.0, < 3.0.2 |
#### Version 3.0.0
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-42502 | Open Redirect Vulnerability | < 3.0.0 |
| CVE-2023-42505 | Sensitive information disclosure on db connection details | < 3.0.0 |
| CVE | Title | Affected |
| :------------- | :-------------------------------------------------------- | -------: |
| CVE-2023-42502 | Open Redirect Vulnerability | < 3.0.0 |
| CVE-2023-42505 | Sensitive information disclosure on db connection details | < 3.0.0 |
#### Version 2.1.3
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-42504 | Lack of rate limiting allows for possible denial of service | < 2.1.3 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------- | -------: |
| CVE-2023-42504 | Lack of rate limiting allows for possible denial of service | < 2.1.3 |
#### Version 2.1.2
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-40610 | Privilege escalation with default examples database | < 2.1.2 |
| CVE-2023-42501 | Unnecessary read permissions within the Gamma role | < 2.1.2 |
| CVE-2023-43701 | Stored XSS on API endpoint | < 2.1.2 |
| CVE | Title | Affected |
| :------------- | :-------------------------------------------------- | -------: |
| CVE-2023-40610 | Privilege escalation with default examples database | < 2.1.2 |
| CVE-2023-42501 | Unnecessary read permissions within the Gamma role | < 2.1.2 |
| CVE-2023-43701 | Stored XSS on API endpoint | < 2.1.2 |
#### Version 2.1.1
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| CVE-2023-36387 | Improper API permission for low privilege users | < 2.1.1 |
| CVE-2023-36388 | Improper API permission for low privilege users allows for SSRF | < 2.1.1 |
| CVE-2023-27523 | Improper data permission validation on Jinja templated queries | < 2.1.1 |
| CVE-2023-27526 | Improper Authorization check on import charts | < 2.1.1 |
| CVE-2023-39264 | Stack traces enabled by default | < 2.1.1 |
| CVE-2023-39265 | Possible Unauthorized Registration of SQLite Database Connections | < 2.1.1 |
| CVE-2023-37941 | Metadata db write access can lead to remote code execution | < 2.1.1 |
| CVE-2023-32672 | SQL parser edge case bypasses data access authorization | < 2.1.1 |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------------- | -------: |
| CVE-2023-36387 | Improper API permission for low privilege users | < 2.1.1 |
| CVE-2023-36388 | Improper API permission for low privilege users allows for SSRF | < 2.1.1 |
| CVE-2023-27523 | Improper data permission validation on Jinja templated queries | < 2.1.1 |
| CVE-2023-27526 | Improper Authorization check on import charts | < 2.1.1 |
| CVE-2023-39264 | Stack traces enabled by default | < 2.1.1 |
| CVE-2023-39265 | Possible Unauthorized Registration of SQLite Database Connections | < 2.1.1 |
| CVE-2023-37941 | Metadata db write access can lead to remote code execution | < 2.1.1 |
| CVE-2023-32672 | SQL parser edge case bypasses data access authorization | < 2.1.1 |
#### Version 2.1.0
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------------------|---------:|
| :------------- | :---------------------------------------------------------------------- | -------: |
| CVE-2023-25504 | Possible SSRF on import datasets | < 2.1.0 |
| CVE-2023-27524 | Session validation vulnerability when using provided default SECRET_KEY | < 2.1.0 |
| CVE-2023-27525 | Incorrect default permissions for Gamma role | < 2.1.0 |
@@ -129,8 +130,8 @@ sidebar_position: 2
#### Version 2.0.1
| CVE | Title | Affected |
|:---------------|:------------------------------------------------------------|------------------: |
| CVE | Title | Affected |
| :------------- | :---------------------------------------------------------- | -----------------: |
| CVE-2022-41703 | SQL injection vulnerability in adhoc clauses | < 2.0.1 or < 1.5.2 |
| CVE-2022-43717 | Cross-Site Scripting on dashboards | < 2.0.1 or < 1.5.2 |
| CVE-2022-43718 | Cross-Site Scripting vulnerability on upload forms | < 2.0.1 or < 1.5.2 |

View File

@@ -3,7 +3,7 @@ title: Securing Your Superset Installation for Production
sidebar_position: 3
---
> *This guide applies to Apache Superset version 4.0 and later and is an evolving set of best practices that administrators should adapt to their specific deployment architecture.*
> _This guide applies to Apache Superset version 4.0 and later and is an evolving set of best practices that administrators should adapt to their specific deployment architecture._
The default Apache Superset configuration is optimized for ease of use and development, not for security. For any production deployment, it is **critical** that you review and apply the following security configurations to harden your instance, protect user data, and prevent unauthorized access.
@@ -13,25 +13,25 @@ This guide provides a comprehensive checklist of essential security configuratio
Running Superset without HTTPS (TLS) is not secure. Without it, all network traffic—including user credentials, session tokens, and sensitive data—is sent in cleartext and can be easily intercepted.
* **Use a Reverse Proxy:** Your Superset instance should always be deployed behind a reverse proxy (e.g., Nginx, Traefik) or a load balancer (e.g., AWS ALB, Google Cloud Load Balancer) that is configured to handle HTTPS termination.
* **Enforce Modern TLS:** Configure your proxy to enforce TLS 1.2 or higher with strong, industry-standard cipher suites.
* **Implement HSTS:** Use the HTTP Strict Transport Security (HSTS) header to ensure browsers only connect to your Superset instance over HTTPS. This can be configured in your reverse proxy or within Superset's Talisman settings.
- **Use a Reverse Proxy:** Your Superset instance should always be deployed behind a reverse proxy (e.g., Nginx, Traefik) or a load balancer (e.g., AWS ALB, Google Cloud Load Balancer) that is configured to handle HTTPS termination.
- **Enforce Modern TLS:** Configure your proxy to enforce TLS 1.2 or higher with strong, industry-standard cipher suites.
- **Implement HSTS:** Use the HTTP Strict Transport Security (HSTS) header to ensure browsers only connect to your Superset instance over HTTPS. This can be configured in your reverse proxy or within Superset's Talisman settings.
### **`SUPERSET_SECRET_KEY` Management (CRITICAL)**
This is the most critical security setting for your Superset instance. It is used to sign all session cookies and encrypt sensitive information in the metadata database, such as database connection credentials.
* **Generate a Unique, Strong Key:** A unique key must be generated for every Superset instance. Use a cryptographically secure method to create it.
```bash
# Example using openssl to generate a strong key
openssl rand -base64 42
```
* **Store the Key Securely:** The key must be kept confidential. The recommended approach is to store it as an environment variable or in a secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault). **Do not hardcode the key in `superset_config.py` or commit it to version control.**
```python
# In superset_config.py
import os
SECRET_KEY = os.environ.get('SUPERSET_SECRET_KEY')
```
- **Generate a Unique, Strong Key:** A unique key must be generated for every Superset instance. Use a cryptographically secure method to create it.
```bash
# Example using openssl to generate a strong key
openssl rand -base64 42
```
- **Store the Key Securely:** The key must be kept confidential. The recommended approach is to store it as an environment variable or in a secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault). **Do not hardcode the key in `superset_config.py` or commit it to version control.**
```python
# In superset_config.py
import os
SECRET_KEY = os.environ.get('SUPERSET_SECRET_KEY')
```
> #### ⚠️ Warning: Your `SUPERSET_SECRET_KEY` Must Be Unique
>
@@ -75,7 +75,7 @@ SESSION_USE_SIGNER = True
#### **Configure Session Lifetime and Cookie Security Flags**
This is mandatory for *all* deployments, whether stateless or server-side.
This is mandatory for _all_ deployments, whether stateless or server-side.
```python
# superset_config.py
@@ -92,7 +92,8 @@ SESSION_COOKIE_SAMESITE = 'Lax' # Provide protection against CSRF attacks
```
> ##### Note on iFrame Embedding and `SESSION_COOKIE_SAMESITE`
>The recommended default setting `'Lax'` provides good CSRF protection for most use cases. However, if you need to embed Superset dashboards into other applications using an iFrame, you will need to change this setting to `'None'`.
>
> The recommended default setting `'Lax'` provides good CSRF protection for most use cases. However, if you need to embed Superset dashboards into other applications using an iFrame, you will need to change this setting to `'None'`.
SESSION_COOKIE_SAMESITE = 'None'
@@ -102,9 +103,9 @@ Setting SameSite to 'None' requires that SESSION_COOKIE_SECURE is also set to Tr
While Superset's built-in database authentication is convenient, for production it's highly recommended to integrate with an enterprise-grade identity provider (IdP).
* **Use an Enterprise IdP:** Configure authentication via OAuth or LDAP to leverage your organization's existing identity management system. This provides benefits like Single Sign-On (SSO), Multi-Factor Authentication (MFA), and centralized user provisioning/deprovisioning.
* **Principle of Least Privilege:** Assign users to the most restrictive roles necessary for their jobs. Avoid over-provisioning users with Admin or Alpha roles, and ensure row-level security is applied where appropriate.
* **Admin Accounts:** Delete or disable the default admin user after a new administrative account has been configured.
- **Use an Enterprise IdP:** Configure authentication via OAuth or LDAP to leverage your organization's existing identity management system. This provides benefits like Single Sign-On (SSO), Multi-Factor Authentication (MFA), and centralized user provisioning/deprovisioning.
- **Principle of Least Privilege:** Assign users to the most restrictive roles necessary for their jobs. Avoid over-provisioning users with Admin or Alpha roles, and ensure row-level security is applied where appropriate.
- **Admin Accounts:** Delete or disable the default admin user after a new administrative account has been configured.
### **Content Security Policy (CSP) and Other Headers**
@@ -122,47 +123,47 @@ Here's the documentation section how how to set up Talisman: https://superset.ap
>
> It is essential to understand that **Apache Superset is a data visualization and exploration platform, not a database firewall or a comprehensive security solution for your data warehouse.** While Superset provides features to help manage data access, the ultimate responsibility for securing your underlying databases lies with your database administrators (DBAs) and security teams. This includes managing network access, user privileges, and fine-grained permissions directly within the database. The configurations below are an important secondary layer of security but should not be your only line of defense.
* **Use a Dedicated Database User:** The database connection configured in Superset should use a dedicated, limited-privilege database user. This user should only have the minimum required permissions (e.g., `SELECT` on specific schemas) for the data sources it needs to query. It should **not** have `INSERT`, `UPDATE`, `DELETE`, or administrative privileges.
* **Restrict Dangerous SQL Functions:** To mitigate potential SQL injection risks, configure the `DISALLOWED_SQL_FUNCTIONS` list in your `superset_config.py`. Be aware that this is a defense-in-depth measure, not a substitute for proper database permissions.
- **Use a Dedicated Database User:** The database connection configured in Superset should use a dedicated, limited-privilege database user. This user should only have the minimum required permissions (e.g., `SELECT` on specific schemas) for the data sources it needs to query. It should **not** have `INSERT`, `UPDATE`, `DELETE`, or administrative privileges.
- **Restrict Dangerous SQL Functions:** To mitigate potential SQL injection risks, configure the `DISALLOWED_SQL_FUNCTIONS` list in your `superset_config.py`. Be aware that this is a defense-in-depth measure, not a substitute for proper database permissions.
### **Additional Security Layers**
* **Web Application Firewall (WAF):** Deploying Superset behind a WAF (e.g., Cloudflare, AWS WAF) is strongly recommended. A WAF with a standard ruleset (like the OWASP Core Rule Set) provides a critical layer of defense against common attacks like SQL Injection, XSS, and remote code execution.
- **Web Application Firewall (WAF):** Deploying Superset behind a WAF (e.g., Cloudflare, AWS WAF) is strongly recommended. A WAF with a standard ruleset (like the OWASP Core Rule Set) provides a critical layer of defense against common attacks like SQL Injection, XSS, and remote code execution.
### **Monitoring and Logging**
* **Configure Structured Logging:** Set up a robust logging configuration to capture important security events.
* **Centralize Logs:** Ship logs from all Superset components (frontend, worker, etc.) to a centralized SIEM (Security Information and Event Management) system for analysis and alerting.
* **Monitor Key Events:** Create alerts for suspicious activities, including:
* Multiple failed login attempts for a single user or from a single IP address.
* Changes to user roles or permissions.
* Creation or deletion of high-privilege users.
* Attempts to use disallowed SQL functions.
- **Configure Structured Logging:** Set up a robust logging configuration to capture important security events.
- **Centralize Logs:** Ship logs from all Superset components (frontend, worker, etc.) to a centralized SIEM (Security Information and Event Management) system for analysis and alerting.
- **Monitor Key Events:** Create alerts for suspicious activities, including:
- Multiple failed login attempts for a single user or from a single IP address.
- Changes to user roles or permissions.
- Creation or deletion of high-privilege users.
- Attempts to use disallowed SQL functions.
-----
---
### **Appendix A: Production Deployment Checklist**
#### **Initial Setup:**
- [ ] HTTPS/TLS is configured and enforced via a reverse proxy.
- [ ] A unique, strong `SUPERSET_SECRET_KEY` is generated and secured in an environment variable or secrets vault.
- [ ] Server-side session management is configured (e.g., Redis).
- [ ] `PERMANENT_SESSION_LIFETIME` is set to a short duration (e.g., 8 hours).
- [ ] All session cookie security flags (`Secure`, `HttpOnly`, `SameSite`) are enabled.
- [ ] `DEBUG` mode is set to `False`.
- [ ] Talisman is explicitly enabled and configured with a strict Content Security Policy.
- [ ] Database connections use dedicated, limited-privilege accounts.
- [ ] Authentication is integrated with an enterprise identity provider (OAuth/LDAP).
- [ ] A Web Application Firewall (WAF) is deployed in front of Superset.
- [ ] Logging is configured and logs are shipped to a central monitoring system.
- [ ] HTTPS/TLS is configured and enforced via a reverse proxy.
- [ ] A unique, strong `SUPERSET_SECRET_KEY` is generated and secured in an environment variable or secrets vault.
- [ ] Server-side session management is configured (e.g., Redis).
- [ ] `PERMANENT_SESSION_LIFETIME` is set to a short duration (e.g., 8 hours).
- [ ] All session cookie security flags (`Secure`, `HttpOnly`, `SameSite`) are enabled.
- [ ] `DEBUG` mode is set to `False`.
- [ ] Talisman is explicitly enabled and configured with a strict Content Security Policy.
- [ ] Database connections use dedicated, limited-privilege accounts.
- [ ] Authentication is integrated with an enterprise identity provider (OAuth/LDAP).
- [ ] A Web Application Firewall (WAF) is deployed in front of Superset.
- [ ] Logging is configured and logs are shipped to a central monitoring system.
#### **Ongoing Maintenance:**
- [ ] Regularly update to the latest major or minor versions of Superset. Those versions receive up-to-date security patches.
- [ ] Rotate the `SUPERSET_SECRET_KEY` periodically (e.g., quarterly) and after any potential security incident.
- [ ] Conduct quarterly access reviews for all users.
- [ ] Assuming logging and monitoring is in place, review security monitoring alerts weekly.
- [ ] Regularly update to the latest major or minor versions of Superset. Those versions receive up-to-date security patches.
- [ ] Rotate the `SUPERSET_SECRET_KEY` periodically (e.g., quarterly) and after any potential security incident.
- [ ] Conduct quarterly access reviews for all users.
- [ ] Assuming logging and monitoring is in place, review security monitoring alerts weekly.
### **Appendix B: `SECRET_KEY` Rotation and Compromise Response**
@@ -174,6 +175,7 @@ The procedure for safely rotating the SECRET_KEY must be followed precisely to a
https://superset.apache.org/admin-docs/configuration/configuring-superset/#rotating-to-a-newer-secret_key
:::resources
- [Blog: Running Apache Superset on the Open Internet](https://preset.io/blog/running-apache-superset-on-the-open-internet-a-report-from-the-fireline/)
- [Blog: How Security Vulnerabilities are Reported & Handled in Apache Superset](https://preset.io/blog/how-security-vulnerabilities-are-reported-and-handled-in-apache-superset/)
:::
:::

View File

@@ -24,13 +24,13 @@ A table with the permissions for these roles can be found at [/RESOURCES/STANDAR
Admins have all possible rights, including granting or revoking rights from other
users and altering other peoples slices and dashboards.
>#### Threat Model and Privilege Boundaries: The Admin Role
> #### Threat Model and Privilege Boundaries: The Admin Role
>
>Apache Superset is built with a granular permission model where users assigned the Admin role are considered fully trusted. Admins possess complete control over the application's configuration, UI rendering, and access controls.
> Apache Superset is built with a granular permission model where users assigned the Admin role are considered fully trusted. Admins possess complete control over the application's configuration, UI rendering, and access controls.
>
>Consequently, actions performed by an Admin that alter the application's behavior or presentation—such as injecting custom CSS, modifying Jinja templates, or altering security flags—are intended administrative capabilities by design.
> Consequently, actions performed by an Admin that alter the application's behavior or presentation—such as injecting custom CSS, modifying Jinja templates, or altering security flags—are intended administrative capabilities by design.
>
>In accordance with MITRE CNA Rule 4.1, a vulnerability must represent a violation of an explicit security policy. Because the Admin role is defined as a trusted operational boundary, actions executed with Admin privileges do not cross a security perimeter. Therefore, exploit vectors that strictly require Admin access are not classified as security vulnerabilities and are ineligible for CVE assignment.
> In accordance with MITRE CNA Rule 4.1, a vulnerability must represent a violation of an explicit security policy. Because the Admin role is defined as a trusted operational boundary, actions executed with Admin privileges do not cross a security perimeter. Therefore, exploit vectors that strictly require Admin access are not classified as security vulnerabilities and are ineligible for CVE assignment.
### Alpha
@@ -54,10 +54,10 @@ to all databases by default, both **Alpha** and **Gamma** users need to be given
Beyond the base `sql_lab` role, two additional SQL Lab permissions must be explicitly granted for users who need these capabilities:
| Permission | Feature |
|------------|---------|
| `can_estimate_query_cost` on `SQLLab` | Estimate query cost before running |
| `can_format_sql` on `SQLLab` | Format SQL using the database's dialect |
| Permission | Feature |
| ------------------------------------- | --------------------------------------- |
| `can_estimate_query_cost` on `SQLLab` | Estimate query cost before running |
| `can_format_sql` on `SQLLab` | Format SQL using the database's dialect |
Grant these in **Security → List Roles** by adding the permissions to the relevant role.
@@ -73,6 +73,7 @@ users who need to view dashboards. It provides minimal read-only access for:
- Viewing annotations on charts
The Public role explicitly excludes:
- Any write permissions on dashboards, charts, or datasets
- SQL Lab access
- Share functionality
@@ -161,12 +162,14 @@ With this enabled, you can assign specific roles to each dashboard in its proper
will only see dashboards where their role is explicitly added.
**Important considerations:**
- Dashboard access **bypasses** dataset-level checks—granting a role access to a dashboard
implicitly grants read access to all charts and datasets in that dashboard
- Dashboards without any assigned roles fall back to dataset-based access
- The dashboard must still be published to be visible
This feature is particularly useful for:
- Making specific dashboards public while keeping others private
- Granting access to dashboards without exposing the underlying datasets for other uses
- Creating dashboard-specific access patterns that don't align with dataset ownership
@@ -184,10 +187,11 @@ However, it is crucial to understand the following:
**Database Security is Paramount**: The ultimate responsibility for securing database access, controlling permissions, and preventing unauthorized function execution lies with the database administrators (DBAs) and security teams managing the underlying database instance.
**Recommended Database Practices**: We strongly recommend implementing security best practices at the database level, including:
* **Least Privilege**: Connecting Superset using dedicated database user accounts with the minimum permissions required for Superset's operation (typically read-only access to necessary schemas/tables).
* **Database Roles & Permissions**: Utilizing database-native roles and permissions to restrict access to sensitive functions, system variables (like `@@hostname`), schemas, or tables.
* **Network Security**: Employing network-level controls like database firewalls or proxies to restrict connections.
* **Auditing**: Enabling database-level auditing to monitor executed queries and access patterns.
- **Least Privilege**: Connecting Superset using dedicated database user accounts with the minimum permissions required for Superset's operation (typically read-only access to necessary schemas/tables).
- **Database Roles & Permissions**: Utilizing database-native roles and permissions to restrict access to sensitive functions, system variables (like `@@hostname`), schemas, or tables.
- **Network Security**: Employing network-level controls like database firewalls or proxies to restrict connections.
- **Auditing**: Enabling database-level auditing to monitor executed queries and access patterns.
By combining Superset's configurable safeguards with strong database-level security practices, you can achieve a more robust and layered security posture.
@@ -341,11 +345,11 @@ rules are:
For example, if a dataset has three filters:
| Filter | Clause | Group Key |
|--------|--------|-----------|
| F1 | `department = 'Finance'` | `department` |
| F2 | `department = 'Marketing'` | `department` |
| F3 | `region = 'Europe'` | `region` |
| Filter | Clause | Group Key |
| ------ | -------------------------- | ------------ |
| F1 | `department = 'Finance'` | `department` |
| F2 | `department = 'Marketing'` | `department` |
| F3 | `region = 'Europe'` | `region` |
The resulting WHERE clause would be:
@@ -429,7 +433,7 @@ GET /api/v1/rowlevelsecurity/<id>
```
The response includes the filter's `name`, `filter_type` (Regular or Base), `clause`,
`group_key`, assigned `tables` (with id, schema, and table\_name), and assigned `roles`
`group_key`, assigned `tables` (with id, schema, and table_name), and assigned `roles`
(with id and name).
:::tip Auditing RLS for virtual datasets
@@ -476,13 +480,13 @@ This reduces the risk for replay attacks and session hijacking.
Superset uses [Flask-Session](https://flask-session.readthedocs.io/en/latest/) to manage server side sessions.
To enable this extension you have to set:
``` python
```python
SESSION_SERVER_SIDE = True
```
Flask-Session offers multiple backend session interfaces for Flask, here's an example for Redis:
``` python
```python
from redis import Redis
SESSION_TYPE = "redis"
@@ -511,8 +515,8 @@ It's extremely important to correctly configure a Content Security Policy when d
prevent many types of attacks. Superset provides two variables in `config.py` for deploying a CSP:
- `TALISMAN_ENABLED` defaults to `True`; set this to `False` in order to disable CSP
- `TALISMAN_CONFIG` holds the actual the policy definition (*see example below*) as well as any
other arguments to be passed to Talisman.
- `TALISMAN_CONFIG` holds the actual the policy definition (_see example below_) as well as any
other arguments to be passed to Talisman.
When running in production mode, Superset will check at startup for the presence
of a CSP. If one is not found, it will issue a warning with the security risks. For environments
@@ -528,12 +532,12 @@ this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`.
```
- Only scripts marked with a [nonce](https://content-security-policy.com/nonce/) can be loaded and executed.
Nonce is a random string automatically generated by Talisman on each page load.
You can get current nonce value by calling jinja macro `csp_nonce()`.
Nonce is a random string automatically generated by Talisman on each page load.
You can get current nonce value by calling jinja macro `csp_nonce()`.
```html
<script nonce="{{ csp_nonce() }}">
/* my script */
/* my script */
</script>
```
@@ -551,7 +555,7 @@ You can get current nonce value by calling jinja macro `csp_nonce()`.
```
- Cartodiagram charts request map data (image and json) from external resources that can be edited by users,
and therefore either require a list of allowed domains to request from or a wildcard (`'*'`) for `img-src` and `connect-src`.
and therefore either require a list of allowed domains to request from or a wildcard (`'*'`) for `img-src` and `connect-src`.
- Other CSP directives default to `'self'` to limit content to the same origin as the Superset server.
@@ -562,12 +566,12 @@ In order to adjust provided CSP configuration to your needs, follow the instruct
Setting `TALISMAN_ENABLED = True` will invoke Talisman's protection with its default arguments,
of which `content_security_policy` is only one. Those can be found in the
[Talisman documentation](https://pypi.org/project/flask-talisman/) under *Options*.
[Talisman documentation](https://pypi.org/project/flask-talisman/) under _Options_.
These generally improve security, but administrators should be aware of their existence.
In particular, the option of `force_https = True` (`False` by default) may break Superset's Alerts & Reports
if workers are configured to access charts via a `WEBDRIVER_BASEURL` beginning
with `http://`. As long as a Superset deployment enforces https upstream, e.g.,
with `http://`. As long as a Superset deployment enforces https upstream, e.g.,
through a load balancer or application gateway, it should be acceptable to keep this
option disabled. Otherwise, you may want to enable `force_https` like this:

View File

@@ -1,3 +1 @@
[
"6.1.0"
]
["6.1.0"]

View File

@@ -16,7 +16,9 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Bar Chart
sidebar_position: 1
---
@@ -27,18 +29,18 @@ The Bar Chart component is used to visualize categorical data with rectangular b
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `data` | `array` | `[]` | Array of data objects to visualize |
| `width` | `number` | `800` | Width of the chart in pixels |
| `height` | `number` | `600` | Height of the chart in pixels |
| `xField` | `string` | - | Field name for x-axis values |
| `yField` | `string` | - | Field name for y-axis values |
| `colorField` | `string` | - | Field name for color encoding |
| `colorScheme` | `string` | `'supersetColors'` | Color scheme to use |
| `showLegend` | `boolean` | `true` | Whether to show the legend |
| `showGrid` | `boolean` | `true` | Whether to show grid lines |
| `labelPosition` | `string` | `'top'` | Position of bar labels: 'top', 'middle', 'bottom' |
| Prop | Type | Default | Description |
| --------------- | --------- | ------------------ | ------------------------------------------------- |
| `data` | `array` | `[]` | Array of data objects to visualize |
| `width` | `number` | `800` | Width of the chart in pixels |
| `height` | `number` | `600` | Height of the chart in pixels |
| `xField` | `string` | - | Field name for x-axis values |
| `yField` | `string` | - | Field name for y-axis values |
| `colorField` | `string` | - | Field name for color encoding |
| `colorScheme` | `string` | `'supersetColors'` | Color scheme to use |
| `showLegend` | `boolean` | `true` | Whether to show the legend |
| `showGrid` | `boolean` | `true` | Whether to show grid lines |
| `labelPosition` | `string` | `'top'` | Position of bar labels: 'top', 'middle', 'bottom' |
## Examples

View File

@@ -16,7 +16,9 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Component Library
sidebar_position: 1
---

View File

@@ -16,7 +16,9 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Grid
sidebar_position: 1
---
@@ -27,29 +29,29 @@ The Grid component provides a flexible layout system for arranging content in ro
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `gutter` | `number` or `[number, number]` | `0` | Grid spacing between items, can be a single number or [horizontal, vertical] |
| `columns` | `number` | `12` | Number of columns in the grid |
| `justify` | `string` | `'start'` | Horizontal alignment: 'start', 'center', 'end', 'space-between', 'space-around' |
| `align` | `string` | `'top'` | Vertical alignment: 'top', 'middle', 'bottom' |
| `wrap` | `boolean` | `true` | Whether to wrap items when they overflow |
| Prop | Type | Default | Description |
| --------- | ------------------------------ | --------- | ------------------------------------------------------------------------------- |
| `gutter` | `number` or `[number, number]` | `0` | Grid spacing between items, can be a single number or [horizontal, vertical] |
| `columns` | `number` | `12` | Number of columns in the grid |
| `justify` | `string` | `'start'` | Horizontal alignment: 'start', 'center', 'end', 'space-between', 'space-around' |
| `align` | `string` | `'top'` | Vertical alignment: 'top', 'middle', 'bottom' |
| `wrap` | `boolean` | `true` | Whether to wrap items when they overflow |
### Row Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `gutter` | `number` or `[number, number]` | `0` | Spacing between items in the row |
| `justify` | `string` | `'start'` | Horizontal alignment for this row |
| `align` | `string` | `'top'` | Vertical alignment for this row |
| Prop | Type | Default | Description |
| --------- | ------------------------------ | --------- | --------------------------------- |
| `gutter` | `number` or `[number, number]` | `0` | Spacing between items in the row |
| `justify` | `string` | `'start'` | Horizontal alignment for this row |
| `align` | `string` | `'top'` | Vertical alignment for this row |
### Col Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `span` | `number` | - | Number of columns the grid item spans |
| `offset` | `number` | `0` | Number of columns the grid item is offset |
| `xs`, `sm`, `md`, `lg`, `xl` | `number` or `object` | - | Responsive props for different screen sizes |
| Prop | Type | Default | Description |
| ---------------------------- | -------------------- | ------- | ------------------------------------------- |
| `span` | `number` | - | Number of columns the grid item spans |
| `offset` | `number` | `0` | Number of columns the grid item is offset |
| `xs`, `sm`, `md`, `lg`, `xl` | `number` or `object` | - | Responsive props for different screen sizes |
## Examples

View File

@@ -16,9 +16,10 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Test
---
## title: Test
import { StoryExample } from '../src/components/StorybookWrapper';
@@ -28,7 +29,9 @@ This is a test using our custom StorybookWrapper component.
<StoryExample
component={() => (
<div style={{ padding: '10px', background: '#f0f0f0', borderRadius: '4px' }}>
<div
style={{ padding: '10px', background: '#f0f0f0', borderRadius: '4px' }}
>
This is a simple example component
</div>
)}

View File

@@ -16,12 +16,18 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Button Component
sidebar_position: 1
---
import { StoryExample, StoryWithControls } from '../../src/components/StorybookWrapper';
title: Button Component
sidebar_position: 1
---
import {
StoryExample,
StoryWithControls,
} from '../../src/components/StorybookWrapper';
import { Button } from '../../../superset-frontend/packages/superset-ui-core/src/components/Button';
# Button Component
@@ -31,6 +37,7 @@ The Button component is a fundamental UI element used throughout Superset for us
## Basic Usage
The default button with primary styling:
<StoryExample
component={() => (
<Button buttonStyle="primary" onClick={() => console.log('Clicked!')}>
@@ -56,47 +63,57 @@ The default button with primary styling:
buttonStyle: 'primary',
buttonSize: 'default',
label: 'Click Me',
disabled: false
disabled: false,
}}
controls={[
{
name: 'buttonStyle',
label: 'Button Style',
type: 'select',
options: ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'default', 'link', 'dashed']
options: [
'primary',
'secondary',
'tertiary',
'success',
'warning',
'danger',
'default',
'link',
'dashed',
],
},
{
name: 'buttonSize',
label: 'Button Size',
type: 'select',
options: ['default', 'small', 'xsmall']
options: ['default', 'small', 'xsmall'],
},
{
name: 'label',
label: 'Button Text',
type: 'text'
type: 'text',
},
{
name: 'disabled',
label: 'Disabled',
type: 'boolean'
}
type: 'boolean',
},
]}
/>
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `buttonStyle` | `'primary' \| 'secondary' \| 'tertiary' \| 'success' \| 'warning' \| 'danger' \| 'default' \| 'link' \| 'dashed'` | `'default'` | Button style |
| `buttonSize` | `'default' \| 'small' \| 'xsmall'` | `'default'` | Button size |
| `disabled` | `boolean` | `false` | Whether the button is disabled |
| `cta` | `boolean` | `false` | Whether the button is a call-to-action button |
| `tooltip` | `ReactNode` | - | Tooltip content |
| `placement` | `TooltipProps['placement']` | - | Tooltip placement |
| `onClick` | `function` | - | Callback when button is clicked |
| `href` | `string` | - | Turns button into an anchor link |
| `target` | `string` | - | Target attribute for anchor links |
| Prop | Type | Default | Description |
| ------------- | ----------------------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------- |
| `buttonStyle` | `'primary' \| 'secondary' \| 'tertiary' \| 'success' \| 'warning' \| 'danger' \| 'default' \| 'link' \| 'dashed'` | `'default'` | Button style |
| `buttonSize` | `'default' \| 'small' \| 'xsmall'` | `'default'` | Button size |
| `disabled` | `boolean` | `false` | Whether the button is disabled |
| `cta` | `boolean` | `false` | Whether the button is a call-to-action button |
| `tooltip` | `ReactNode` | - | Tooltip content |
| `placement` | `TooltipProps['placement']` | - | Tooltip placement |
| `onClick` | `function` | - | Callback when button is clicked |
| `href` | `string` | - | Turns button into an anchor link |
| `target` | `string` | - | Target attribute for anchor links |
## Usage
@@ -105,10 +122,7 @@ import Button from 'src/components/Button';
function MyComponent() {
return (
<Button
buttonStyle="primary"
onClick={() => console.log('Button clicked')}
>
<Button buttonStyle="primary" onClick={() => console.log('Button clicked')}>
Click Me
</Button>
);

View File

@@ -16,7 +16,9 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Bar Chart
sidebar_position: 1
---
@@ -27,18 +29,18 @@ The Bar Chart component is used to visualize categorical data with rectangular b
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `data` | `array` | `[]` | Array of data objects to visualize |
| `width` | `number` | `800` | Width of the chart in pixels |
| `height` | `number` | `600` | Height of the chart in pixels |
| `xField` | `string` | - | Field name for x-axis values |
| `yField` | `string` | - | Field name for y-axis values |
| `colorField` | `string` | - | Field name for color encoding |
| `colorScheme` | `string` | `'supersetColors'` | Color scheme to use |
| `showLegend` | `boolean` | `true` | Whether to show the legend |
| `showGrid` | `boolean` | `true` | Whether to show grid lines |
| `labelPosition` | `string` | `'top'` | Position of bar labels: 'top', 'middle', 'bottom' |
| Prop | Type | Default | Description |
| --------------- | --------- | ------------------ | ------------------------------------------------- |
| `data` | `array` | `[]` | Array of data objects to visualize |
| `width` | `number` | `800` | Width of the chart in pixels |
| `height` | `number` | `600` | Height of the chart in pixels |
| `xField` | `string` | - | Field name for x-axis values |
| `yField` | `string` | - | Field name for y-axis values |
| `colorField` | `string` | - | Field name for color encoding |
| `colorScheme` | `string` | `'supersetColors'` | Color scheme to use |
| `showLegend` | `boolean` | `true` | Whether to show the legend |
| `showGrid` | `boolean` | `true` | Whether to show grid lines |
| `labelPosition` | `string` | `'top'` | Position of bar labels: 'top', 'middle', 'bottom' |
## Examples

View File

@@ -16,7 +16,9 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Component Library
sidebar_position: 1
---

View File

@@ -16,7 +16,9 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Grid
sidebar_position: 1
---
@@ -27,29 +29,29 @@ The Grid component provides a flexible layout system for arranging content in ro
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `gutter` | `number` or `[number, number]` | `0` | Grid spacing between items, can be a single number or [horizontal, vertical] |
| `columns` | `number` | `12` | Number of columns in the grid |
| `justify` | `string` | `'start'` | Horizontal alignment: 'start', 'center', 'end', 'space-between', 'space-around' |
| `align` | `string` | `'top'` | Vertical alignment: 'top', 'middle', 'bottom' |
| `wrap` | `boolean` | `true` | Whether to wrap items when they overflow |
| Prop | Type | Default | Description |
| --------- | ------------------------------ | --------- | ------------------------------------------------------------------------------- |
| `gutter` | `number` or `[number, number]` | `0` | Grid spacing between items, can be a single number or [horizontal, vertical] |
| `columns` | `number` | `12` | Number of columns in the grid |
| `justify` | `string` | `'start'` | Horizontal alignment: 'start', 'center', 'end', 'space-between', 'space-around' |
| `align` | `string` | `'top'` | Vertical alignment: 'top', 'middle', 'bottom' |
| `wrap` | `boolean` | `true` | Whether to wrap items when they overflow |
### Row Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `gutter` | `number` or `[number, number]` | `0` | Spacing between items in the row |
| `justify` | `string` | `'start'` | Horizontal alignment for this row |
| `align` | `string` | `'top'` | Vertical alignment for this row |
| Prop | Type | Default | Description |
| --------- | ------------------------------ | --------- | --------------------------------- |
| `gutter` | `number` or `[number, number]` | `0` | Spacing between items in the row |
| `justify` | `string` | `'start'` | Horizontal alignment for this row |
| `align` | `string` | `'top'` | Vertical alignment for this row |
### Col Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `span` | `number` | - | Number of columns the grid item spans |
| `offset` | `number` | `0` | Number of columns the grid item is offset |
| `xs`, `sm`, `md`, `lg`, `xl` | `number` or `object` | - | Responsive props for different screen sizes |
| Prop | Type | Default | Description |
| ---------------------------- | -------------------- | ------- | ------------------------------------------- |
| `span` | `number` | - | Number of columns the grid item spans |
| `offset` | `number` | `0` | Number of columns the grid item is offset |
| `xs`, `sm`, `md`, `lg`, `xl` | `number` or `object` | - | Responsive props for different screen sizes |
## Examples

View File

@@ -16,9 +16,10 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Test
---
## title: Test
import { StoryExample } from '../../src/components/StorybookWrapper';
@@ -28,7 +29,9 @@ This is a test using our custom StorybookWrapper component.
<StoryExample
component={() => (
<div style={{ padding: '10px', background: '#f0f0f0', borderRadius: '4px' }}>
<div
style={{ padding: '10px', background: '#f0f0f0', borderRadius: '4px' }}
>
This is a simple example component
</div>
)}

View File

@@ -16,12 +16,18 @@
specific language governing permissions and limitations
under the License.
-->
---
title: Button Component
sidebar_position: 1
---
import { StoryExample, StoryWithControls } from '../../../src/components/StorybookWrapper';
title: Button Component
sidebar_position: 1
---
import {
StoryExample,
StoryWithControls,
} from '../../../src/components/StorybookWrapper';
import { Button } from '../../../../superset-frontend/packages/superset-ui-core/src/components/Button';
# Button Component
@@ -31,6 +37,7 @@ The Button component is a fundamental UI element used throughout Superset for us
## Basic Usage
The default button with primary styling:
<StoryExample
component={() => (
<Button buttonStyle="primary" onClick={() => console.log('Clicked!')}>
@@ -56,47 +63,57 @@ The default button with primary styling:
buttonStyle: 'primary',
buttonSize: 'default',
label: 'Click Me',
disabled: false
disabled: false,
}}
controls={[
{
name: 'buttonStyle',
label: 'Button Style',
type: 'select',
options: ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'default', 'link', 'dashed']
options: [
'primary',
'secondary',
'tertiary',
'success',
'warning',
'danger',
'default',
'link',
'dashed',
],
},
{
name: 'buttonSize',
label: 'Button Size',
type: 'select',
options: ['default', 'small', 'xsmall']
options: ['default', 'small', 'xsmall'],
},
{
name: 'label',
label: 'Button Text',
type: 'text'
type: 'text',
},
{
name: 'disabled',
label: 'Disabled',
type: 'boolean'
}
type: 'boolean',
},
]}
/>
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `buttonStyle` | `'primary' \| 'secondary' \| 'tertiary' \| 'success' \| 'warning' \| 'danger' \| 'default' \| 'link' \| 'dashed'` | `'default'` | Button style |
| `buttonSize` | `'default' \| 'small' \| 'xsmall'` | `'default'` | Button size |
| `disabled` | `boolean` | `false` | Whether the button is disabled |
| `cta` | `boolean` | `false` | Whether the button is a call-to-action button |
| `tooltip` | `ReactNode` | - | Tooltip content |
| `placement` | `TooltipProps['placement']` | - | Tooltip placement |
| `onClick` | `function` | - | Callback when button is clicked |
| `href` | `string` | - | Turns button into an anchor link |
| `target` | `string` | - | Target attribute for anchor links |
| Prop | Type | Default | Description |
| ------------- | ----------------------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------- |
| `buttonStyle` | `'primary' \| 'secondary' \| 'tertiary' \| 'success' \| 'warning' \| 'danger' \| 'default' \| 'link' \| 'dashed'` | `'default'` | Button style |
| `buttonSize` | `'default' \| 'small' \| 'xsmall'` | `'default'` | Button size |
| `disabled` | `boolean` | `false` | Whether the button is disabled |
| `cta` | `boolean` | `false` | Whether the button is a call-to-action button |
| `tooltip` | `ReactNode` | - | Tooltip content |
| `placement` | `TooltipProps['placement']` | - | Tooltip placement |
| `onClick` | `function` | - | Callback when button is clicked |
| `href` | `string` | - | Turns button into an anchor link |
| `target` | `string` | - | Target attribute for anchor links |
## Usage
@@ -105,10 +122,7 @@ import Button from 'src/components/Button';
function MyComponent() {
return (
<Button
buttonStyle="primary"
onClick={() => console.log('Button clicked')}
>
<Button buttonStyle="primary" onClick={() => console.log('Button clicked')}>
Click Me
</Button>
);

View File

@@ -1,3 +1 @@
[
"6.1.0"
]
["6.1.0"]

View File

@@ -35,6 +35,7 @@ Code review is a critical part of maintaining code quality and sharing knowledge
### Preparing for Review
#### Before Requesting Review
- [ ] Self-review your changes
- [ ] Ensure CI checks pass
- [ ] Add comprehensive tests
@@ -43,6 +44,7 @@ Code review is a critical part of maintaining code quality and sharing knowledge
- [ ] Add screenshots for UI changes
#### Self-Review Checklist
```bash
# View your changes
git diff upstream/master
@@ -59,18 +61,23 @@ git diff upstream/master
### Requesting Review
#### Auto-Assignment
GitHub will automatically request reviews based on CODEOWNERS file.
#### Manual Assignment
For specific expertise, request additional reviewers:
- Frontend changes: Tag frontend experts
- Backend changes: Tag backend experts
- Security changes: Tag security team
- Database changes: Tag database experts
#### Review Request Message
```markdown
@reviewer This PR implements [feature]. Could you please review:
1. The approach taken in [file]
2. Performance implications of [change]
3. Security considerations for [feature]
@@ -81,23 +88,29 @@ Thanks!
### Responding to Feedback
#### Best Practices
- **Be receptive**: Reviews improve code quality
- **Ask questions**: Clarify if feedback is unclear
- **Explain decisions**: Share context for your choices
- **Update promptly**: Address feedback in timely manner
#### Comment Responses
```markdown
# Acknowledging
"Good catch! Fixed in [commit hash]"
# Explaining
"I chose this approach because [reason]. Would you prefer [alternative]?"
# Questioning
"Could you elaborate on [concern]? I'm not sure I understand the issue."
# Disagreeing respectfully
"I see your point, but I think [current approach] because [reason]. What do you think?"
```
@@ -106,6 +119,7 @@ Thanks!
### Review Responsibilities
#### What to Review
1. **Correctness**: Does the code do what it claims?
2. **Design**: Is the approach appropriate?
3. **Clarity**: Is the code readable and maintainable?
@@ -117,12 +131,14 @@ Thanks!
### Review Checklist
#### Functionality
- [ ] Feature works as described
- [ ] Edge cases are handled
- [ ] Error handling is appropriate
- [ ] Backwards compatibility maintained
#### Code Quality
- [ ] Follows project conventions
- [ ] No code duplication
- [ ] Clear variable/function names
@@ -130,6 +146,7 @@ Thanks!
- [ ] SOLID principles followed
#### Testing
- [ ] Unit tests for business logic
- [ ] Integration tests for APIs
- [ ] E2E tests for critical paths
@@ -137,6 +154,7 @@ Thanks!
- [ ] Good test coverage
#### Security
- [ ] Input validation
- [ ] SQL injection prevention
- [ ] XSS prevention
@@ -145,6 +163,7 @@ Thanks!
- [ ] No sensitive data in logs
#### Performance
- [ ] Database queries optimized
- [ ] No N+1 queries
- [ ] Appropriate caching
@@ -176,11 +195,13 @@ re-renders when dependencies haven't changed."
#### Comment Types
**Use GitHub's comment types:**
- **Comment**: General feedback or questions
- **Approve**: Changes look good
- **Request Changes**: Must be addressed before merge
**Prefix conventions:**
- `nit:` Minor issue (non-blocking)
- `suggestion:` Recommended improvement
- `question:` Seeking clarification
@@ -206,12 +227,15 @@ praise: Excellent test coverage! 👍
### Timeline
#### Expected Response Times
- **Initial review**: Within 2-3 business days
- **Follow-up review**: Within 1-2 business days
- **Critical fixes**: ASAP (tag in Slack)
#### Escalation
If no response after 3 days:
1. Ping reviewer in PR comments
2. Ask in #development Slack channel
3. Tag @apache/superset-committers
@@ -219,11 +243,13 @@ If no response after 3 days:
### Approval Requirements
#### Minimum Requirements
- **1 approval** from a committer for minor changes
- **2 approvals** for significant features
- **3 approvals** for breaking changes
#### Special Cases
- **Security changes**: Require security team review
- **API changes**: Require API team review
- **Database migrations**: Require database expert review
@@ -232,16 +258,19 @@ If no response after 3 days:
### Merge Process
#### Who Can Merge
- Committers with write access
- After all requirements met
- CI checks must pass
#### Merge Methods
- **Squash and merge**: Default for feature PRs
- **Rebase and merge**: For clean history
- **Create merge commit**: Rarely used
#### Merge Checklist
- [ ] All CI checks green
- [ ] Required approvals obtained
- [ ] No unresolved conversations
@@ -251,6 +280,7 @@ If no response after 3 days:
## Review Etiquette
### Do's
- ✅ Be kind and constructive
- ✅ Acknowledge time and effort
- ✅ Provide specific examples
@@ -260,6 +290,7 @@ If no response after 3 days:
- ✅ Focus on the code, not the person
### Don'ts
- ❌ Use harsh or dismissive language
- ❌ Bikeshed on minor preferences
- ❌ Review when tired or frustrated
@@ -270,6 +301,7 @@ If no response after 3 days:
## Becoming a Reviewer
### Path to Reviewer
1. **Contribute regularly**: Submit quality PRs
2. **Participate in discussions**: Share knowledge
3. **Review others' code**: Start with comments
@@ -277,6 +309,7 @@ If no response after 3 days:
5. **Get nominated**: By existing committers
### Reviewer Expectations
- Review PRs in your area of expertise
- Respond within reasonable time
- Mentor new contributors
@@ -288,6 +321,7 @@ If no response after 3 days:
### Reviewing Large PRs
#### Strategy
1. **Request splitting**: Ask to break into smaller PRs
2. **Review in phases**:
- Architecture/approach first
@@ -298,6 +332,7 @@ If no response after 3 days:
### Cross-Team Reviews
#### When Needed
- Changes affecting multiple teams
- Shared components/libraries
- API contract changes
@@ -306,6 +341,7 @@ If no response after 3 days:
### Performance Reviews
#### Tools
```python
# Backend performance
import cProfile
@@ -327,11 +363,13 @@ stats.sort_stats('cumulative').print_stats(10)
## Resources
### Internal
- [Coding Guidelines](../guidelines/design-guidelines.md)
- [Testing Guide](../testing/overview.md)
- [Extension Architecture](../extensions/architecture.md)
### External
- [Google's Code Review Guide](https://google.github.io/eng-practices/review/)
- [Best Practices for Code Review](https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/)
- [The Art of Readable Code](https://www.oreilly.com/library/view/the-art-of/9781449318482/)

View File

@@ -150,6 +150,7 @@ make up
```
This automatically:
- Generates a unique project name from your directory name
- Finds available ports (incrementing from 8088, 9000, etc. if already in use)
- Displays the assigned URLs before starting
@@ -158,16 +159,16 @@ Each clone gets isolated containers and volumes, so you can run them side-by-sid
Available commands (run from repo root):
| Command | Description |
|---------|-------------|
| `make up` | Start services (foreground) |
| `make up-detached` | Start services (background) |
| `make down` | Stop all services |
| `make ps` | Show running containers |
| `make logs` | Follow container logs |
| `make ports` | Show assigned URLs and ports |
| `make open` | Open browser to dev server |
| `make nuke` | Stop, remove volumes & local images |
| Command | Description |
| ------------------ | ----------------------------------- |
| `make up` | Start services (foreground) |
| `make up-detached` | Start services (background) |
| `make down` | Stop all services |
| `make ps` | Show running containers |
| `make logs` | Follow container logs |
| `make ports` | Show assigned URLs and ports |
| `make open` | Open browser to dev server |
| `make nuke` | Stop, remove volumes & local images |
From a subdirectory, use: `make -C $(git rev-parse --show-toplevel) up`
@@ -178,6 +179,7 @@ Always use these commands instead of plain `docker compose down`, which won't kn
## GitHub Codespaces (Cloud Development)
GitHub Codespaces provides a complete, pre-configured development environment in the cloud. This is ideal for:
- Quick contributions without local setup
- Consistent development environments across team members
- Working from devices that can't run Docker locally
@@ -324,17 +326,21 @@ You can also run the pre-commit checks manually in various ways:
## Working with LLMs
### Environment Setup
Ensure Docker Compose is running before starting LLM sessions:
```bash
docker compose up
```
Validate your environment:
```bash
curl -f http://localhost:8088/health && echo "✅ Superset ready"
```
### LLM Session Best Practices
- Always validate environment setup first using the health checks above
- Use focused validation commands: `pre-commit run` (not `--all-files`)
- **Read [LLMS.md](https://github.com/apache/superset/blob/master/LLMS.md) first** - Contains comprehensive development guidelines, coding standards, and critical refactor information
@@ -346,6 +352,7 @@ curl -f http://localhost:8088/health && echo "✅ Superset ready"
- Follow the TypeScript migration guidelines and avoid deprecated patterns listed in LLMS.md
### Key Development Commands
```bash
# Frontend development
cd superset-frontend
@@ -646,7 +653,7 @@ If you want to use the same flag in the client code, also add it to the FeatureF
```typescript
export enum FeatureFlag {
SCOPED_FILTER = "SCOPED_FILTER",
SCOPED_FILTER = 'SCOPED_FILTER',
}
```
@@ -815,6 +822,7 @@ If Jest tests hang with "Jest did not exit one second after the test run has com
**To verify if still needed**: Remove the MessageChannel mocking lines and run `npm test -- --shard=4/8`. If tests hang, the workaround is still required.
**Future removal conditions**: This workaround can be removed when:
- rc-overflow updates to properly clean up MessagePorts in test environments
- Jest updates to handle MessageChannel/MessagePort cleanup better
- Ant Design switches away from rc-overflow
@@ -959,9 +967,9 @@ VSCode will not stop on breakpoints right away. We've attached to PID 6 however
To debug Flask running in POD inside a kubernetes cluster, you'll need to make sure the pod runs as root and is granted the SYS_TRACE capability.These settings should not be used in production environments.
```yaml
securityContext:
capabilities:
add: ["SYS_PTRACE"]
securityContext:
capabilities:
add: ['SYS_PTRACE']
```
See [set capabilities for a container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container) for more details.

View File

@@ -130,8 +130,8 @@ Triaging goals
First, add **Category labels (a.k.a. hash labels)**. Every issue/PR must have one hash label (except spam entry). Labels that begin with `#` defines issue/PR type:
| Label | for Issue | for PR |
| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Label | for Issue | for PR |
| --------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `#bug` | Bug report | Bug fix |
| `#code-quality` | Describe problem with code, architecture or productivity | Refactor, tests, tooling |
| `#feature` | New feature request | New feature implementation |
@@ -175,12 +175,14 @@ Should you decide that reverting is desirable, it is the responsibility of the C
- **Put the revert through code review:** The revert must be approved by another committer.
**Revert liberally to keep `master` stable**:
- Build failures
- Test failures
- Critical bugs in production
- Security vulnerabilities
**How to revert**:
1. Use GitHub's revert button when possible
2. Create a PR with clear explanation
3. Tag the original author
@@ -211,11 +213,13 @@ Sentence case: "A dog takes a walk in Paris"
- It's the easiest form to distinguish between common and proper nouns
**Good examples:**
- "Select a database"
- "Create new chart"
- "View all dashboards"
**Bad examples:**
- "Select a Database"
- "Create New Chart"
- "View All Dashboards"
@@ -240,6 +244,7 @@ Often a product page will have the same title as the objects it contains. In thi
- Create custom queries in SQL Lab then create dashboards
When writing about UI elements:
- Use **bold** for clickable elements: "Click **Save**"
- Use quotes for text fields: 'Enter "My Dashboard" in the name field'
- Be specific about element types: button, link, dropdown, etc.
@@ -247,6 +252,7 @@ When writing about UI elements:
#### **Exceptions to sentence case
Only use title case for:
- Product names (Apache Superset)
- Proper nouns
- Acronyms (SQL, API, CSV)
@@ -258,10 +264,12 @@ Only use title case for:
### Python
We use:
- **[Ruff](https://docs.astral.sh/ruff/)** for linting and formatting
- **[Mypy](http://mypy-lang.org/)** for type checking
Python code should:
- Follow PEP 8
- Use type hints for all new code
- Use descriptive variable names
@@ -336,6 +344,7 @@ def process_data(
```
Use `mypy` to check types:
```bash
mypy superset
```
@@ -343,8 +352,9 @@ mypy superset
### TypeScript
We use:
- **ESLint** for linting
- **Prettier** for formatting
- **Oxfmt** for formatting
- **TypeScript** strict mode
TypeScript is fully supported and is the recommended language for writing all new frontend
@@ -353,6 +363,7 @@ appreciated, but not required. Examples of migrating functions/components to Typ
found in [#9162](https://github.com/apache/superset/pull/9162) and [#9180](https://github.com/apache/superset/pull/9180).
TypeScript code should:
- Avoid `any` types - use proper TypeScript types
- Use functional components with hooks for React
- Include JSDoc comments for complex functions
@@ -360,6 +371,7 @@ TypeScript code should:
- Handle errors appropriately
Example:
```typescript
interface User {
id: number;
@@ -411,5 +423,6 @@ Bad: "Fixed stuff"
## Questions?
If you have questions about these guidelines, ask in:
- [Slack #development](https://apache-superset.slack.com)
- [GitHub Discussions](https://github.com/apache/superset/discussions)

View File

@@ -68,11 +68,13 @@ Visualization plugins allow you to add custom chart types to Superset. They are
### Creating a simple Hello World viz plugin
1. **Install the Superset Yeoman generator**:
```bash
npm install -g @superset-ui/generator-superset
```
2. **Create a new plugin**:
```bash
mkdir superset-plugin-chart-hello-world
cd superset-plugin-chart-hello-world
@@ -80,19 +82,22 @@ yo @superset-ui/superset
```
3. **Follow the prompts**:
- Package name: `superset-plugin-chart-hello-world`
- Chart type: Choose your preferred type
- Include storybook: Yes (recommended for development)
4. **Develop your plugin**:
The generator creates a complete plugin structure with TypeScript, React components, and build configuration.
The generator creates a complete plugin structure with TypeScript, React components, and build configuration.
5. **Test your plugin locally**:
```bash
npm run dev
```
6. **Link to your local Superset**:
```bash
npm link
# In your Superset frontend directory:
@@ -100,7 +105,7 @@ npm link superset-plugin-chart-hello-world
```
7. **Import and register in Superset**:
Edit `superset-frontend/src/visualizations/presets/MainPreset.ts` to include your plugin.
Edit `superset-frontend/src/visualizations/presets/MainPreset.ts` to include your plugin.
## Testing
@@ -121,7 +126,7 @@ pytest --cov=superset
# Run only unit tests
pytest tests/unit_tests
# Run only integration tests
# Run only integration tests
pytest tests/integration_tests
```
@@ -234,6 +239,7 @@ For debugging the Flask backend:
#### Using VS Code
1. Add to `.vscode/launch.json`:
```json
{
"version": "0.2.0",
@@ -261,9 +267,9 @@ For debugging the Flask backend:
To debug Flask running in a POD inside a kubernetes cluster, you'll need to make sure the pod runs as root and is granted the `SYS_PTRACE` capability. These settings should not be used in production environments.
```yaml
securityContext:
capabilities:
add: ["SYS_PTRACE"]
securityContext:
capabilities:
add: ['SYS_PTRACE']
```
See [set capabilities for a container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container) for more details.
@@ -349,7 +355,7 @@ uses Claude AI to generate draft translations for any missing entries. All
AI-generated strings are marked `#, fuzzy` and tagged with an attribution
comment so that human reviewers know they need to be checked.
Note that `#, fuzzy` marks a translation as *needing review*, not as *withheld*:
Note that `#, fuzzy` marks a translation as _needing review_, not as _withheld_:
both the frontend and backend builds serve fuzzy entries (see [Applying
translations](#applying-translations) above), so an AI-generated string is shown
in the UI as soon as it is built and deployed. Reviewers should verify each
@@ -395,6 +401,7 @@ python scripts/translations/backfill_po.py --lang fr --limit 20 --dry-run
```
Output shows each string, its translation, and a context tag:
- No tag — 3+ reference languages available (high confidence)
- `[ctx:N]` — only N other languages have this string (lower confidence)
- `[ctx:0]` — no other language has this string yet; English alone used
@@ -407,15 +414,15 @@ python scripts/translations/backfill_po.py --lang fr
Options:
| Flag | Default | Description |
|------|---------|-------------|
| `--lang LANG` | required | ISO language code (`fr`, `de`, `ja`, …) |
| `--batch-size N` | 50 | Strings per Claude request |
| `--limit N` | unlimited | Stop after N entries |
| `--min-context N` | 0 | Skip entries with fewer than N reference translations |
| `--model MODEL` | `claude-sonnet-4-6` | Claude model to use |
| `--dry-run` | off | Print without writing |
| `--no-fuzzy` | off | Don't mark entries as fuzzy |
| Flag | Default | Description |
| ----------------- | ------------------- | ----------------------------------------------------- |
| `--lang LANG` | required | ISO language code (`fr`, `de`, `ja`, …) |
| `--batch-size N` | 50 | Strings per Claude request |
| `--limit N` | unlimited | Stop after N entries |
| `--min-context N` | 0 | Skip entries with fewer than N reference translations |
| `--model MODEL` | `claude-sonnet-4-6` | Claude model to use |
| `--dry-run` | off | Print without writing |
| `--no-fuzzy` | off | Don't mark entries as fuzzy |
Use `--min-context 2` to skip strings that have fewer than 2 reference
translations in other languages. Those strings are more likely to be ambiguous
@@ -488,8 +495,8 @@ npm run check:custom-rules
# Run tsc (typescript) checks
npm run type
# Format with Prettier
npm run prettier
# Format with Oxfmt
npm run format
```
#### Architecture
@@ -519,6 +526,7 @@ The linting system consists of two components:
**"Plugin 'basic-custom-plugin' not found" Error**
Ensure you're using the explicit config:
```bash
npx oxlint --config oxlint.json
```
@@ -526,6 +534,7 @@ npx oxlint --config oxlint.json
**Custom Rules Not Running**
Verify the AST parsing dependencies are installed:
```bash
npm ls @babel/parser @babel/traverse glob
```
@@ -544,6 +553,7 @@ For every PR, an ephemeral environment is automatically deployed for testing.
Access pattern: `https://pr-{PR_NUMBER}.superset.apache.org`
Features:
- Automatically deployed on PR creation/update
- Includes sample data
- Destroyed when PR is closed
@@ -573,6 +583,7 @@ docker compose up
**Frontend**: Webpack dev server provides hot module replacement automatically.
**Backend**: Use Flask debug mode:
```bash
FLASK_ENV=development superset run -p 8088 --with-threads --reload
```
@@ -580,12 +591,14 @@ FLASK_ENV=development superset run -p 8088 --with-threads --reload
### Performance Profiling
For Python profiling:
```python
# In superset_config.py
PROFILING = True
```
For React profiling:
- Use React DevTools Profiler
- Enable performance marks in Chrome DevTools
@@ -683,6 +696,7 @@ To do this, you'll need to:
```
Note that:
- for changes that affect the worker logic, you'll have to restart the `celery worker` process for the changes to be reflected.
- The message queue used is a `sqlite` database using the `SQLAlchemy` experimental broker. Ok for testing, but not recommended in production
- In some cases, you may want to create a context that is more aligned to your production environment, and use the similar broker as well as results backend configuration

View File

@@ -31,6 +31,7 @@ Learn how to effectively report bugs and request features for Apache Superset.
### Pre-Issue Checklist
1. **Search Existing Issues**
```
Search: https://github.com/apache/superset/issues
- Use keywords from your error message
@@ -44,6 +45,7 @@ Learn how to effectively report bugs and request features for Apache Superset.
- [Configuration Guide](https://superset.apache.org/docs/configuration/configuring-superset)
3. **Verify Version**
```bash
# Check Superset version
superset version
@@ -63,24 +65,30 @@ Learn how to effectively report bugs and request features for Apache Superset.
```markdown
### Bug Description
A clear and concise description of the bug.
### How to Reproduce
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
### Expected Behavior
What you expected to happen.
### Actual Behavior
What actually happened. Include error messages.
### Screenshots/Videos
If applicable, add screenshots or recordings.
### Environment
- Superset version: [e.g., 3.0.0]
- Python version: [e.g., 3.11.7]
- Node version: [e.g., 18.17.0]
@@ -89,6 +97,7 @@ If applicable, add screenshots or recordings.
- OS: [e.g., Ubuntu 22.04]
### Additional Context
- Using Docker: Yes/No
- Configuration overrides:
- Feature flags enabled:
@@ -98,12 +107,15 @@ If applicable, add screenshots or recordings.
### What Makes a Good Bug Report
#### ✅ Good Example
```markdown
### Bug Description
When filtering a dashboard with a date range filter, charts using
SQL Lab datasets don't update, while charts using regular datasets do.
### How to Reproduce
1. Create a dashboard with 2 charts:
- Chart A: Uses a SQL Lab virtual dataset
- Chart B: Uses a regular table dataset
@@ -112,18 +124,22 @@ SQL Lab datasets don't update, while charts using regular datasets do.
4. Chart B updates, Chart A shows no change
### Expected Behavior
Both charts should filter to show last 30 days of data.
### Actual Behavior
Only Chart B updates. Chart A still shows all data.
No error messages in browser console or server logs.
### Screenshots
[Dashboard before filter]: attachment1.png
[Dashboard after filter]: attachment2.png
[Network tab showing requests]: attachment3.png
### Environment
- Superset version: 3.0.0
- Python version: 3.11.16
- Database: PostgreSQL 14.9
@@ -132,6 +148,7 @@ No error messages in browser console or server logs.
```
#### ❌ Poor Example
```markdown
Dashboard filters don't work. Please fix.
```
@@ -139,6 +156,7 @@ Dashboard filters don't work. Please fix.
### Required Information
#### Error Messages
```python
# Include full error traceback
Traceback (most recent call last):
@@ -148,6 +166,7 @@ SupersetException: Detailed error message
```
#### Logs
```bash
# Backend logs
docker logs superset_app 2>&1 | tail -100
@@ -157,6 +176,7 @@ tail -f ~/.superset/superset.log
```
#### Browser Console
```javascript
// Include JavaScript errors
// Chrome: F12 → Console tab
@@ -165,6 +185,7 @@ tail -f ~/.superset/superset.log
```
#### Configuration
```python
# Relevant config from superset_config.py
FEATURE_FLAGS = {
@@ -179,18 +200,23 @@ FEATURE_FLAGS = {
```markdown
### Is your feature request related to a problem?
A clear description of the problem you're trying to solve.
### Describe the solution you'd like
A clear description of what you want to happen.
### Describe alternatives you've considered
Other solutions or features you've considered.
### Additional context
Any other context, mockups, or examples.
### Are you willing to contribute?
- [ ] Yes, I can implement this feature
- [ ] Yes, I can help test
- [ ] No, but I can provide feedback
@@ -199,6 +225,7 @@ Any other context, mockups, or examples.
### Good Feature Requests Include
1. **Clear Use Case**
```markdown
As a [type of user], I want [feature] so that [benefit].
@@ -224,6 +251,7 @@ Any other context, mockups, or examples.
**DO NOT** create public issues for security vulnerabilities!
Instead:
1. Email: security@apache.org
2. Subject: `[Superset] Security Vulnerability`
3. Include:
@@ -238,9 +266,11 @@ Instead:
Send to: security@apache.org
### Vulnerability Description
[Describe the security issue]
### Type
- [ ] SQL Injection
- [ ] XSS
- [ ] CSRF
@@ -249,27 +279,33 @@ Send to: security@apache.org
- [ ] Other: [specify]
### Affected Versions
[List affected versions]
### Steps to Reproduce
[Detailed steps - be specific]
### Impact
[What can an attacker do?]
### Suggested Fix
[If you have suggestions]
```
## Issue Labels
### Priority Labels
- `P0`: Critical - System unusable
- `P1`: High - Major feature broken
- `P2`: Medium - Important but workaround exists
- `P3`: Low - Nice to have
### Type Labels
- `bug`: Something isn't working
- `feature`: New feature request
- `enhancement`: Improvement to existing feature
@@ -277,6 +313,7 @@ Send to: security@apache.org
- `question`: Question about usage
### Component Labels
- `dashboard`: Dashboard functionality
- `sqllab`: SQL Lab
- `explore`: Chart builder
@@ -285,6 +322,7 @@ Send to: security@apache.org
- `security`: Security related
### Status Labels
- `needs-triage`: Awaiting review
- `confirmed`: Bug confirmed
- `in-progress`: Being worked on
@@ -294,25 +332,30 @@ Send to: security@apache.org
## Issue Lifecycle
### 1. Creation
- User creates issue with template
- Auto-labeled as `needs-triage`
### 2. Triage
- Maintainer reviews within 7 days
- Labels applied (priority, type, component)
- Questions asked if needed
### 3. Confirmation
- Bug reproduced or feature discussed
- Label changed to `confirmed`
- Assigned to milestone if applicable
### 4. Development
- Contributor claims issue
- Label changed to `in-progress`
- PR linked to issue
### 5. Resolution
- PR merged
- Issue auto-closed
- Or manually closed with explanation
@@ -322,6 +365,7 @@ Send to: security@apache.org
### If No Response
After 7 days without response:
```markdown
@apache/superset-committers This issue hasn't been triaged yet.
Could someone please take a look?
@@ -343,6 +387,7 @@ Here's additional debugging information: [details]
## Tips for Success
### Do's
- ✅ Search before creating
- ✅ Use templates
- ✅ Provide complete information
@@ -352,6 +397,7 @@ Here's additional debugging information: [details]
- ✅ One issue per report
### Don'ts
- ❌ "+1" or "me too" comments (use reactions)
- ❌ Multiple issues in one report
- ❌ Vague descriptions
@@ -410,6 +456,7 @@ with app.app_context():
### Issue Not a Bug?
Consider:
- **Feature Request**: Use feature request template
- **Question**: Use GitHub Discussions
- **Configuration Help**: Ask in Slack

View File

@@ -146,7 +146,7 @@ Security team members must:
- Have an [ICLA](https://www.apache.org/licenses/contributor-agreements.html) signed with Apache Software Foundation.
- Not reveal information about pending and unfixed security issues to anyone (including their employers) unless specifically authorised by the security team members, e.g., if the security team agrees that diagnosing and solving an issue requires the involvement of external experts.
A release manager, the contributor overseeing the release of a specific version of Apache Superset, is by default a member of the security team. However, they are not expected to be active in assessing, discussing, and fixing security issues.
A release manager, the contributor overseeing the release of a specific version of Apache Superset, is by default a member of the security team. However, they are not expected to be active in assessing, discussing, and fixing security issues.
Security team members should also follow these general expectations:

View File

@@ -61,6 +61,7 @@ Update all dependencies to use `importlib.metadata` instead of `pkg_resources`:
#### Migration Example
**Old (deprecated):**
```python
import pkg_resources
@@ -69,6 +70,7 @@ entry_points = pkg_resources.iter_entry_points("group_name")
```
**New (recommended):**
```python
from importlib.metadata import version, entry_points
@@ -79,11 +81,13 @@ eps = entry_points(group="group_name")
## Action Items
### For Superset Maintainers
1. The Superset codebase already uses `importlib.metadata`
2. Monitor third-party dependencies for updates
3. Update setuptools pin once the ecosystem is ready
### For Extension Developers
1. **Update your packages** to use `importlib.metadata` instead of `pkg_resources`
2. **Test with setuptools >= 81.0.0** once all packages are migrated

View File

@@ -29,6 +29,7 @@ Understand Apache Superset's release process, versioning strategy, and how to pa
## Release Cadence
### Schedule
- **Major releases (X.0.0)**: Annually (approximately)
- **Minor releases (X.Y.0)**: Quarterly
- **Patch releases (X.Y.Z)**: As needed for critical fixes
@@ -46,6 +47,7 @@ MAJOR.MINOR.PATCH
```
### Examples
- `3.0.0`: Major release with breaking changes
- `3.1.0`: Minor release with new features
- `3.1.1`: Patch release with bug fixes
@@ -55,12 +57,14 @@ MAJOR.MINOR.PATCH
### Major Releases (X.0.0)
#### Includes
- Breaking API changes
- Deprecated feature removals
- Major architectural changes
- Database migration requirements
#### Process
- 2-3 month preparation period
- Multiple release candidates (RC)
- Extensive testing period
@@ -69,12 +73,14 @@ MAJOR.MINOR.PATCH
### Minor Releases (X.Y.0)
#### Includes
- New features
- Performance improvements
- Non-breaking API additions
- Minor UI/UX updates
#### Process
- 1 month preparation
- 1-2 release candidates
- Standard testing period
@@ -82,12 +88,14 @@ MAJOR.MINOR.PATCH
### Patch Releases (X.Y.Z)
#### Includes
- Bug fixes
- Security patches
- Documentation fixes
- Dependency updates (security)
#### Process
- Fast track for critical issues
- May skip RC for urgent security fixes
- Minimal testing requirements
@@ -97,6 +105,7 @@ MAJOR.MINOR.PATCH
### 1. Pre-Release Preparation
#### Feature Freeze
```bash
# Create release branch
git checkout -b release-X.Y
@@ -108,40 +117,49 @@ VERSION = "X.Y.0rc1"
```
#### Update Documentation
- CHANGELOG.md
- UPDATING.md (for breaking changes)
- Documentation version
#### Release Notes Template
```markdown
# Apache Superset X.Y.0
## 🎉 Highlights
- Major feature 1
- Major feature 2
## 🚀 New Features
- Feature 1 (#PR)
- Feature 2 (#PR)
## 🐛 Bug Fixes
- Fix 1 (#PR)
- Fix 2 (#PR)
## ⚠️ Breaking Changes
- Breaking change 1
- Migration required for X
## 📝 Documentation
- Doc update 1 (#PR)
## 🙏 Thank You
Thanks to all contributors!
```
### 2. Create Release Candidate
#### Build RC
```bash
# Tag release candidate
git tag -a vX.Y.Zrc1 -m "Apache Superset X.Y.Z RC1"
@@ -158,6 +176,7 @@ gpg --armor --detach-sig dist/apache-superset-X.Y.Zrc1.tar.gz
```
#### Upload to staging
```bash
# Upload to Apache staging
svn co https://dist.apache.org/repos/dist/dev/superset
@@ -202,11 +221,13 @@ Thanks,
```
#### Voting Rules
- **Duration**: Minimum 72 hours
- **Required**: 3 +1 votes from PMC members
- **Veto**: Any -1 vote must be addressed
#### Testing Checklist
```markdown
- [ ] Source builds successfully
- [ ] Docker image builds
@@ -219,6 +240,7 @@ Thanks,
### 4. Release Approval
#### Tally Votes
```
Subject: [RESULT][VOTE] Release Apache Superset X.Y.Z RC1
@@ -245,6 +267,7 @@ Thank you to everyone who tested and voted!
### 5. Perform Release
#### Promote RC to Release
```bash
# Tag final release
git tag -a vX.Y.Z -m "Apache Superset X.Y.Z"
@@ -256,12 +279,14 @@ svn mv https://dist.apache.org/repos/dist/dev/superset/X.Y.Zrc1 \
```
#### Publish to PyPI
```bash
# Upload to PyPI
python -m twine upload dist/*X.Y.Z*
```
#### Build Docker Images
```bash
# Build and push Docker images
docker build -t apache/superset:X.Y.Z .
@@ -273,6 +298,7 @@ docker push apache/superset:latest
### 6. Post-Release Tasks
#### Update Documentation
```bash
# Update docs version
cd docs
@@ -310,6 +336,7 @@ The Apache Superset Team
```
#### Update GitHub Release
```bash
# Create GitHub release
gh release create vX.Y.Z \
@@ -322,12 +349,14 @@ gh release create vX.Y.Z \
### During Feature Freeze
#### What's Allowed
- ✅ Bug fixes
- ✅ Documentation updates
- ✅ Test improvements
- ✅ Security fixes
#### What's Not Allowed
- ❌ New features
- ❌ Major refactoring
- ❌ Breaking changes
@@ -336,6 +365,7 @@ gh release create vX.Y.Z \
### Testing RCs
#### How to Test
```bash
# Install RC from staging
pip install https://dist.apache.org/repos/dist/dev/superset/X.Y.Zrc1/apache-superset-X.Y.Zrc1.tar.gz
@@ -345,6 +375,7 @@ docker pull apache/superset:X.Y.Zrc1
```
#### What to Test
- Your use cases
- New features mentioned in release notes
- Upgrade from previous version
@@ -352,8 +383,10 @@ docker pull apache/superset:X.Y.Zrc1
- Critical workflows
#### Reporting Issues
```markdown
Found issue in RC1:
- Description: [what's wrong]
- Steps to reproduce: [how to trigger]
- Impact: [blocker/major/minor]
@@ -363,21 +396,26 @@ Found issue in RC1:
### CHANGELOG Maintenance
#### Format
```markdown
## X.Y.Z (YYYY-MM-DD)
### Features
- feat: Description (#PR_NUMBER)
### Fixes
- fix: Description (#PR_NUMBER)
### Breaking Changes
- BREAKING: Description (#PR_NUMBER)
Migration: Steps to migrate
```
#### Generating CHANGELOG
```bash
# Use git log to generate initial list
git log --oneline vX.Y-1.Z..vX.Y.Z | grep -E "^[a-f0-9]+ (feat|fix|perf|refactor|docs)"
@@ -390,31 +428,38 @@ git log --oneline vX.Y-1.Z..vX.Y.Z | grep -E "^[a-f0-9]+ (feat|fix|perf|refactor
### Documentation Required
#### UPDATING.md Entry
```markdown
````markdown
# X.Y.Z
## Breaking Change: [Title]
### Description
What changed and why.
### Before
```python
# Old way
old_function(param1, param2)
```
````
### After
```python
# New way
new_function(param1, param2, param3)
```
### Migration Steps
1. Update your code to...
2. Run migration script...
3. Test that...
```
````
### Deprecation Process
@@ -423,7 +468,7 @@ new_function(param1, param2, param3)
@deprecated(version="3.0.0", remove_in="4.0.0")
def old_function():
warnings.warn("Use new_function instead", DeprecationWarning)
```
````
2. **Version N+1**: Keep deprecated with warnings
@@ -432,12 +477,14 @@ new_function(param1, param2, param3)
## Security Releases
### Expedited Process
- No RC required for critical security fixes
- Coordinate with security@apache.org
- Embargo period may apply
- CVE assignment through ASF security team
### Security Advisory Template
```markdown
CVE-YYYY-XXXXX: [Title]
@@ -458,11 +505,13 @@ Credit:
## Resources
### Internal
- [Apache Release Policy](https://www.apache.org/legal/release-policy.html)
- [Superset Release History](https://github.com/apache/superset/releases)
- [Version Strategy Discussion](https://github.com/apache/superset/discussions)
### Tools
- [Release Scripts](https://github.com/apache/superset/tree/master/scripts/release)
- [Superset Repository Scripts](https://github.com/apache/superset/tree/master/scripts)

View File

@@ -117,16 +117,19 @@ You can also [download the .svg](https://github.com/apache/superset/tree/master/
## Additional Resources
### Official Documentation
- [Apache Superset Documentation](https://superset.apache.org/docs/intro)
- [API Documentation](https://superset.apache.org/docs/api)
- [Configuration Guide](https://superset.apache.org/admin-docs/configuration/configuring-superset)
### Community Resources
- [Apache Superset Blog](https://preset.io/blog/)
- [YouTube Channel](https://www.youtube.com/channel/UCMuwrvBsg_jjI2gLcm04R0g)
- [Twitter/X](https://twitter.com/ApacheSuperset)
### Development Tools
- [GitHub Repository](https://github.com/apache/superset)
- [PyPI Package](https://pypi.org/project/apache-superset/)
- [Docker Hub](https://hub.docker.com/r/apache/superset)

View File

@@ -29,12 +29,14 @@ Learn how to create and submit high-quality pull requests to Apache Superset.
## Before You Start
### Prerequisites
- [ ] Development environment is set up
- [ ] You've forked and cloned the repository
- [ ] You've read the [contributing overview](./overview.md)
- [ ] You've found or created an issue to work on
### PR Readiness Checklist
- [ ] Code follows [coding guidelines](../guidelines/design-guidelines.md)
- [ ] Tests are passing locally
- [ ] Linting passes (`pre-commit run --all-files`)
@@ -82,6 +84,7 @@ type(scope): description
```
**Types:**
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation only
@@ -95,6 +98,7 @@ type(scope): description
- `revert`: Reverting changes
**Scopes:**
- `dashboard`: Dashboard functionality
- `sqllab`: SQL Lab features
- `explore`: Chart explorer
@@ -105,6 +109,7 @@ type(scope): description
- `config`: Configuration
**Examples:**
```
feat(sqllab): add query cost estimation
fix(dashboard): resolve filter cascading issue
@@ -119,23 +124,28 @@ Use the template from `.github/PULL_REQUEST_TEMPLATE.md`:
```markdown
### SUMMARY
Brief description of changes and motivation.
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
[Required for UI changes]
### TESTING INSTRUCTIONS
1. Step-by-step instructions
2. How to verify the fix/feature
3. Any specific test scenarios
### ADDITIONAL INFORMATION
- [ ] Has associated issue: #12345
- [ ] Required feature flags:
- [ ] API changes:
- [ ] DB migration required:
### CHECKLIST
- [ ] CI checks pass
- [ ] Tests added/updated
- [ ] Documentation updated
@@ -158,11 +168,13 @@ gh pr create --title "feat(sqllab): add query cost estimation" \
## PR Best Practices
### Keep PRs Focused
- One feature/fix per PR
- Break large changes into smaller PRs
- Separate refactoring from feature changes
### Write Good Commit Messages
```bash
# Good
git commit -m "fix(dashboard): prevent duplicate API calls when filters change"
@@ -173,6 +185,7 @@ git commit -m "updates"
```
### Include Tests
```python
# Backend test example
def test_new_feature():
@@ -190,15 +203,19 @@ test('renders new component', () => {
```
### Add Screenshots for UI Changes
```markdown
### Before
![Before](link-to-before-screenshot)
### After
### After
![After](link-to-after-screenshot)
```
### Update Documentation
- Update relevant docs in `/docs` directory
- Add docstrings to new functions/classes
- Update UPDATING.md for breaking changes
@@ -206,7 +223,9 @@ test('renders new component', () => {
## CI Checks
### Required Checks
All PRs must pass:
- `Python Tests` - Backend unit/integration tests
- `Frontend Tests` - JavaScript/TypeScript tests
- `Linting` - Code style checks
@@ -217,6 +236,7 @@ All PRs must pass:
### Common CI Failures
#### Python Test Failures
```bash
# Run locally to debug
pytest tests/unit_tests/ -v
@@ -224,12 +244,14 @@ pytest tests/integration_tests/ -v
```
#### Frontend Test Failures
```bash
cd superset-frontend
npm run test -- --coverage
```
#### Linting Failures
```bash
# Auto-fix many issues
pre-commit run --all-files
@@ -243,6 +265,7 @@ pre-commit run --all-files
## Responding to Reviews
### Address Feedback Promptly
```bash
# Make requested changes
edit files...
@@ -254,11 +277,13 @@ git push origin feature/your-feature-name
```
### Request Re-review
- Click "Re-request review" after addressing feedback
- Comment on resolved discussions
- Thank reviewers for their time
### Handling Conflicts
```bash
# Update your branch
git fetch upstream
@@ -276,6 +301,7 @@ git push --force-with-lease origin feature/your-feature-name
## After Merge
### Clean Up
```bash
# Delete local branch
git checkout master
@@ -291,6 +317,7 @@ git push origin master
```
### Follow Up
- Monitor for any issues reported
- Help with documentation if needed
- Consider related improvements
@@ -298,6 +325,7 @@ git push origin master
## Tips for Success
### Do
- ✅ Keep PRs small and focused
- ✅ Write descriptive PR titles and descriptions
- ✅ Include tests for new functionality
@@ -306,6 +334,7 @@ git push origin master
- ✅ Be patient with the review process
### Don't
- ❌ Submit PRs with failing tests
- ❌ Include unrelated changes
- ❌ Force push to master

View File

@@ -177,14 +177,14 @@ plugins: [
'@apache-superset/core': { singleton: true, import: false },
},
}),
]
];
```
This configuration does several important things:
**`exposes`** - Declares which modules are available to the host application. Superset always loads extensions by requesting the `./index` module from the remote container — this is a fixed convention, not a configurable value. Extensions must expose exactly `'./index': './src/index.tsx'` and place all API registrations (views, commands, menus, editors, event listeners) in that file. The module is executed as a side effect when the extension loads, so any call to `views.registerView`, `commands.registerCommand`, etc. made at the top level of `index.tsx` will run automatically.
**`shared`** - Prevents duplication of common libraries like React and Ant Design, and, for `@apache-superset/core`, is the mechanism that gives each extension an isolated context (see below). The `singleton: true` setting ensures only one *logical* instance of each library exists — for `react`/`react-dom`/`antd` that means the host's actual instance is reused; for `@apache-superset/core` it means the extension's container defers to whatever module the host's loader supplies for it at init time, which is not the same object for every extension (see [Runtime Resolution](#runtime-resolution)).
**`shared`** - Prevents duplication of common libraries like React and Ant Design, and, for `@apache-superset/core`, is the mechanism that gives each extension an isolated context (see below). The `singleton: true` setting ensures only one _logical_ instance of each library exists — for `react`/`react-dom`/`antd` that means the host's actual instance is reused; for `@apache-superset/core` it means the extension's container defers to whatever module the host's loader supplies for it at init time, which is not the same object for every extension (see [Runtime Resolution](#runtime-resolution)).
### Runtime Resolution

View File

@@ -34,45 +34,40 @@ Alert component for displaying important messages to users. Wraps Ant Design Ale
<StoryWithControls
component={Alert}
props={{
closable: true,
type: 'info',
message: 'This is a sample alert message.',
description: 'Sample description for additional context.',
showIcon: true
}}
closable: true,
type: 'info',
message: 'This is a sample alert message.',
description: 'Sample description for additional context.',
showIcon: true,
}}
controls={[
{
name: 'type',
label: 'Type',
type: 'select',
options: [
'info',
'error',
'warning',
'success'
]
},
{
name: 'closable',
label: 'Closable',
type: 'boolean'
},
{
name: 'showIcon',
label: 'Show Icon',
type: 'boolean'
},
{
name: 'message',
label: 'Message',
type: 'text'
},
{
name: 'description',
label: 'Description',
type: 'text'
}
]}
{
name: 'type',
label: 'Type',
type: 'select',
options: ['info', 'error', 'warning', 'success'],
},
{
name: 'closable',
label: 'Closable',
type: 'boolean',
},
{
name: 'showIcon',
label: 'Show Icon',
type: 'boolean',
},
{
name: 'message',
label: 'Message',
type: 'text',
},
{
name: 'description',
label: 'Description',
type: 'text',
},
]}
/>
## Try It
@@ -95,13 +90,13 @@ function Demo() {
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `closable` | `boolean` | `true` | Whether the Alert can be closed with a close button. |
| `type` | `string` | `"info"` | Type of the alert (e.g., info, error, warning, success). |
| `message` | `string` | `"This is a sample alert message."` | Message |
| `description` | `string` | `"Sample description for additional context."` | Description |
| `showIcon` | `boolean` | `true` | Whether to display an icon in the Alert. |
| Prop | Type | Default | Description |
| ------------- | --------- | ---------------------------------------------- | -------------------------------------------------------- |
| `closable` | `boolean` | `true` | Whether the Alert can be closed with a close button. |
| `type` | `string` | `"info"` | Type of the alert (e.g., info, error, warning, success). |
| `message` | `string` | `"This is a sample alert message."` | Message |
| `description` | `string` | `"Sample description for additional context."` | Description |
| `showIcon` | `boolean` | `true` | Whether to display an icon in the Alert. |
## Usage in Extensions
@@ -112,11 +107,7 @@ import { Alert } from '@apache-superset/core/components';
function MyExtension() {
return (
<Alert
closable
type="info"
message="This is a sample alert message."
/>
<Alert closable type="info" message="This is a sample alert message." />
);
}
```
@@ -128,4 +119,4 @@ function MyExtension() {
---
*This page was auto-generated from the component's Storybook story.*
_This page was auto-generated from the component's Storybook story._

View File

@@ -39,11 +39,7 @@ All components are exported from the `@apache-superset/core/components` package:
import { Alert } from '@apache-superset/core/components';
export function MyExtensionPanel() {
return (
<Alert type="info">
Welcome to my extension!
</Alert>
);
return <Alert type="info">Welcome to my extension!</Alert>;
}
```
@@ -68,7 +64,7 @@ export default {
},
};
export const InteractiveMyComponent = (args) => <MyComponent {...args} />;
export const InteractiveMyComponent = args => <MyComponent {...args} />;
InteractiveMyComponent.args = {
variant: 'primary',

View File

@@ -169,6 +169,7 @@ from .api import MyExtensionAPI
- **Host context**: `/api/v1/` with original ID
For an extension with publisher `my-org` and name `dataset-tools`, the endpoint above would be accessible at:
```
/extensions/my-org/dataset-tools/hello
```

View File

@@ -34,10 +34,10 @@ Extensions run in the same context as Superset during runtime. This means extens
The core packages follow [semantic versioning](https://semver.org/) and provide stable, documented APIs:
| Package | Language | Description |
|---------|----------|-------------|
| Package | Language | Description |
| ----------------------- | --------------------- | -------------------------------------------------- |
| `@apache-superset/core` | JavaScript/TypeScript | Frontend APIs, UI components, hooks, and utilities |
| `apache-superset-core` | Python | Backend APIs, models, DAOs, and utilities |
| `apache-superset-core` | Python | Backend APIs, models, DAOs, and utilities |
**Benefits of using core packages:**
@@ -116,12 +116,14 @@ Abstracting libraries like React or SQLAlchemy would:
Extension developers should depend on and use core libraries directly:
**Frontend (examples):**
- [React](https://react.dev/) - UI framework
- [Ant Design](https://ant.design/) - UI component library (prefer Superset components from `@apache-superset/core/components` when available to preserve visual consistency)
- [Emotion](https://emotion.sh/) - CSS-in-JS styling
- ...
**Backend (examples):**
- [SQLAlchemy](https://www.sqlalchemy.org/) - Database toolkit
- [Flask](https://flask.palletsprojects.com/) - Web framework
- [Flask-AppBuilder](https://flask-appbuilder.readthedocs.io/) - Application framework

View File

@@ -35,7 +35,7 @@ Packaging is handled by the `superset-extensions bundle` command, which:
To deploy an extension, place the `.supx` file in the extensions directory configured via `EXTENSIONS_PATH` in your `superset_config.py`:
``` python
```python
EXTENSIONS_PATH = "/path/to/extensions"
```

View File

@@ -80,6 +80,7 @@ dataset-references/
```
**Note**: With publisher `my-org` and name `dataset-references`, the technical names are:
- Directory name: `dataset-references` (kebab-case)
- Backend Python namespace: `my_org.dataset_references`
- Backend distribution package: `my_org-dataset_references`

View File

@@ -30,19 +30,19 @@ Extensions can add a chat interface to Superset by registering a trigger and a p
A chat registration consists of two React components:
| Component | Role |
|-----------|------|
| Component | Role |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Trigger** | Always-visible entry point (e.g., a floating button). Rendered in the bottom-right corner in floating mode, or as a fixed overlay in panel mode. |
| **Panel** | The chat UI itself (message list, input, etc.). Mounted by the host in the active display mode. |
| **Panel** | The chat UI itself (message list, input, etc.). Mounted by the host in the active display mode. |
## Display Modes
The host supports two display modes, switchable by the user or the extension at runtime:
| Mode | Behavior |
|------|----------|
| `floating` | Panel floats above page content, anchored to the bottom-right corner. |
| `panel` | Panel is docked to the right side of the application as a resizable sidebar, sitting beside the page content. |
| Mode | Behavior |
| ---------- | ------------------------------------------------------------------------------------------------------------- |
| `floating` | Panel floats above page content, anchored to the bottom-right corner. |
| `panel` | Panel is docked to the right side of the application as a resizable sidebar, sitting beside the page content. |
The user's last selected mode and open/closed state are persisted across page reloads.
@@ -107,7 +107,11 @@ export default function ChatPanel() {
return (
<div style={{ height: mode === 'panel' ? '100%' : '80vh' }}>
<button onClick={() => chat.setDisplayMode(mode === 'panel' ? 'floating' : 'panel')}>
<button
onClick={() =>
chat.setDisplayMode(mode === 'panel' ? 'floating' : 'panel')
}
>
{mode === 'panel' ? 'Float' : 'Dock'}
</button>
{/* message list and input */}
@@ -120,20 +124,20 @@ export default function ChatPanel() {
All methods are available on the `chat` namespace from `@apache-superset/core`:
| Method / Event | Description |
|----------------|-------------|
| `registerChat(descriptor, trigger, panel)` | Register a chat extension. Returns a `Disposable` to unregister. |
| `open()` | Open the chat panel. No-op if already open or no registration. |
| `close()` | Close the chat panel. |
| `isOpen()` | Returns `true` if the panel is currently open. |
| `getDisplayMode()` | Returns the current display mode (`'floating'` or `'panel'`). |
| `setDisplayMode(mode)` | Switch between `'floating'` and `'panel'` mode. |
| `onDidOpen(listener)` | Subscribe to panel open events. Returns a `Disposable`. |
| `onDidClose(listener)` | Subscribe to panel close events. Returns a `Disposable`. |
| `onDidChangeDisplayMode(listener)` | Subscribe to display mode changes. Returns a `Disposable`. |
| `onDidRegisterChat(listener)` | Subscribe to registration events. |
| `onDidUnregisterChat(listener)` | Subscribe to unregistration events. |
| `onDidResizePanel(listener)` | Subscribe to panel resize events (panel mode only). Not all hosts provide a resizer — do not rely on this firing. Returns a `Disposable`. |
| Method / Event | Description |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `registerChat(descriptor, trigger, panel)` | Register a chat extension. Returns a `Disposable` to unregister. |
| `open()` | Open the chat panel. No-op if already open or no registration. |
| `close()` | Close the chat panel. |
| `isOpen()` | Returns `true` if the panel is currently open. |
| `getDisplayMode()` | Returns the current display mode (`'floating'` or `'panel'`). |
| `setDisplayMode(mode)` | Switch between `'floating'` and `'panel'` mode. |
| `onDidOpen(listener)` | Subscribe to panel open events. Returns a `Disposable`. |
| `onDidClose(listener)` | Subscribe to panel close events. Returns a `Disposable`. |
| `onDidChangeDisplayMode(listener)` | Subscribe to display mode changes. Returns a `Disposable`. |
| `onDidRegisterChat(listener)` | Subscribe to registration events. |
| `onDidUnregisterChat(listener)` | Subscribe to unregistration events. |
| `onDidResizePanel(listener)` | Subscribe to panel resize events (panel mode only). Not all hosts provide a resizer — do not rely on this firing. Returns a `Disposable`. |
## Next Steps

View File

@@ -30,16 +30,16 @@ Extensions can replace Superset's default text editors with custom implementatio
Superset uses text editors in various places throughout the application:
| Language | Locations |
|----------|-----------|
| `sql` | SQL Lab, Metric/Filter Popovers |
| `json` | Dashboard Properties, Annotation Modal, Theme Modal |
| `css` | Dashboard Properties, CSS Template Modal |
| `markdown` | Dashboard Markdown component |
| `yaml` | Template Params Editor |
| `javascript` | Custom JavaScript editor contexts |
| `python` | Custom Python editor contexts |
| `text` | Plain text editor contexts |
| Language | Locations |
| ------------ | --------------------------------------------------- |
| `sql` | SQL Lab, Metric/Filter Popovers |
| `json` | Dashboard Properties, Annotation Modal, Theme Modal |
| `css` | Dashboard Properties, CSS Template Modal |
| `markdown` | Dashboard Markdown component |
| `yaml` | Template Params Editor |
| `javascript` | Custom JavaScript editor contexts |
| `python` | Custom Python editor contexts |
| `text` | Plain text editor contexts |
By registering an editor for a language, your extension replaces the default Ace editor in **all** locations that use that language.
@@ -170,7 +170,7 @@ Superset passes keyboard shortcuts via the `hotkeys` prop. Each hotkey includes
```typescript
interface EditorHotkey {
name: string;
key: string; // e.g., "Ctrl-Enter", "Alt-Shift-F"
key: string; // e.g., "Ctrl-Enter", "Alt-Shift-F"
description?: string;
exec: (handle: EditorHandle) => void;
}
@@ -185,9 +185,9 @@ Superset passes static autocomplete suggestions via the `keywords` prop. These i
```typescript
interface EditorKeyword {
name: string;
value?: string; // Text to insert (defaults to name)
meta?: string; // Category like "table", "column", "function"
score?: number; // Sorting priority
value?: string; // Text to insert (defaults to name)
meta?: string; // Category like "table", "column", "function"
score?: number; // Sorting priority
}
```

View File

@@ -106,7 +106,11 @@ This example adds primary, secondary, and context actions to the editor:
import { commands, menus, sqlLab } from '@apache-superset/core';
commands.registerCommand(
{ id: 'my-extension.format', title: 'Format Query', icon: 'FormatPainterOutlined' },
{
id: 'my-extension.format',
title: 'Format Query',
icon: 'FormatPainterOutlined',
},
async () => {
const tab = sqlLab.getCurrentTab();
if (tab) {

View File

@@ -33,9 +33,11 @@ Model Context Protocol (MCP) integration allows extensions to register custom AI
MCP enables extensions to extend Superset's AI capabilities in two ways:
### MCP Tools
Tools are Python functions that AI agents can call to perform specific tasks. They provide executable functionality that extends Superset's capabilities.
**Examples of MCP tools:**
- Data processing and transformation functions
- Custom analytics calculations
- Integration with external APIs
@@ -43,9 +45,11 @@ Tools are Python functions that AI agents can call to perform specific tasks. Th
- Business-specific operations
### MCP Prompts
Prompts provide interactive guidance and context to AI agents. They help agents understand how to better assist users with specific workflows or domain knowledge.
**Examples of MCP prompts:**
- Step-by-step workflow guidance
- Domain-specific context and knowledge
- Interactive troubleshooting assistance
@@ -76,6 +80,7 @@ This creates a tool that AI agents can call by name. The tool name defaults to t
The `@tool` decorator accepts several optional parameters:
**Parameter details:**
- **`name`**: Tool identifier (AI agents use this to call your tool)
- **`description`**: Explains what the tool does (helps AI agents decide when to use it)
- **`tags`**: Categories for organization and discovery
@@ -213,6 +218,7 @@ Agent: I generated the number 42 for you.
```
The AI agent sees your tool's:
- **Name**: How to call it
- **Description**: What it does and when to use it
- **Parameters**: What inputs it expects (from Pydantic schema)
@@ -377,18 +383,21 @@ async def troubleshoot_charts(ctx: Context) -> str:
### Prompt Best Practices
#### Content Structure
- **Use clear headings** and sections for easy navigation
- **Provide actionable steps** rather than just theory
- **Include examples** relevant to the user's domain
- **Offer next steps** to continue the workflow
#### Interactive Design
- **Ask questions** to engage the user
- **Provide options** for different scenarios
- **Reference specific Superset features** by name
- **Link to related tools** when appropriate
#### Context Awareness
```python
@prompt("analytics_extension.context_aware_guide")
async def context_aware_guide(ctx: Context) -> str:

View File

@@ -36,9 +36,9 @@ This page serves as a registry of community-created Superset extensions. These e
| [SQL Lab Export to Parquet](https://github.com/rusackas/superset-extensions/tree/main/sqllab_parquet) | Export SQL Lab query results directly to Apache Parquet format with Snappy compression. | Evan Rusackas | <a href="/img/extensions/parquet-export.png" target="_blank"><img src="/img/extensions/parquet-export.png" alt="SQL Lab Export to Parquet" width="120" /></a> |
| [SQL Lab Query Comparison](https://github.com/michael-s-molina/superset-extensions/tree/main/query-comparison) | A SQL Lab extension that enables side-by-side comparison of query results across different tabs, with GitHub-style diff visualization showing added/removed rows and columns. | Michael S. Molina | <a href="/img/extensions/query-comparison.png" target="_blank"><img src="/img/extensions/query-comparison.png" alt="Query Comparison" width="120" /></a> |
| [SQL Lab Result Stats](https://github.com/michael-s-molina/superset-extensions/tree/main/result-stats) | A SQL Lab extension that automatically computes statistics for query results, providing type-aware analysis including numeric metrics (min, max, mean, median, std dev), string analysis (length, empty counts), and date range information. | Michael S. Molina | <a href="/img/extensions/result-stats.png" target="_blank"><img src="/img/extensions/result-stats.png" alt="Result Stats" width="120" /></a> |
| [Editor Snippets](https://github.com/michael-s-molina/superset-extensions/tree/main/editor-snippets) | A SQL Lab extension for managing and inserting reusable code snippets into the editor, with server-side persistence per user. | Michael S. Molina | <a href="/img/extensions/editor-snippets.png" target="_blank"><img src="/img/extensions/editor-snippets.png" alt="Editor Snippets" width="120" /></a> |
| [Editor Snippets](https://github.com/michael-s-molina/superset-extensions/tree/main/editor-snippets) | A SQL Lab extension for managing and inserting reusable code snippets into the editor, with server-side persistence per user. | Michael S. Molina | <a href="/img/extensions/editor-snippets.png" target="_blank"><img src="/img/extensions/editor-snippets.png" alt="Editor Snippets" width="120" /></a> |
| [SQL Lab Query Estimator](https://github.com/michael-s-molina/superset-extensions/tree/main/query-estimator) | A SQL Lab panel that analyzes query execution plans to estimate resource impact, detect performance issues like Cartesian products and high-cost operations, and visualize the query plan tree. | Michael S. Molina | <a href="/img/extensions/query-estimator.png" target="_blank"><img src="/img/extensions/query-estimator.png" alt="Query Estimator" width="120" /></a> |
| [Editors Bundle](https://github.com/michael-s-molina/superset-extensions/tree/main/editors-bundle) | A Superset extension that demonstrates how to provide custom code editors for different languages. This extension showcases the editor contribution system by registering alternative editors that can replace Superset's default Ace editor. | Michael S. Molina | <a href="/img/extensions/editors-bundle.png" target="_blank"><img src="/img/extensions/editors-bundle.png" alt="Editors Bundle" width="120" /></a> |
| [Editors Bundle](https://github.com/michael-s-molina/superset-extensions/tree/main/editors-bundle) | A Superset extension that demonstrates how to provide custom code editors for different languages. This extension showcases the editor contribution system by registering alternative editors that can replace Superset's default Ace editor. | Michael S. Molina | <a href="/img/extensions/editors-bundle.png" target="_blank"><img src="/img/extensions/editors-bundle.png" alt="Editors Bundle" width="120" /></a> |
## How to Add Your Extension

View File

@@ -117,7 +117,11 @@ import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Store with a 5-minute TTL
await ctx.storage.ephemeral.set('job_progress', { pct: 42, status: 'running' }, { ttl: 300 });
await ctx.storage.ephemeral.set(
'job_progress',
{ pct: 42, status: 'running' },
{ ttl: 300 },
);
// Retrieve
const progress = await ctx.storage.ephemeral.get('job_progress');
@@ -155,7 +159,11 @@ import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
await ctx.storage.ephemeral.shared.set('shared_result', { data: [1, 2, 3] }, { ttl: 3600 });
await ctx.storage.ephemeral.shared.set(
'shared_result',
{ data: [1, 2, 3] },
{ ttl: 3600 },
);
const result = await ctx.storage.ephemeral.shared.get('shared_result');
```
@@ -198,7 +206,9 @@ import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Store a saved SQL snippet
await ctx.storage.persistent.set('snippet:top_customers', { sql: 'SELECT ...' });
await ctx.storage.persistent.set('snippet:top_customers', {
sql: 'SELECT ...',
});
// Retrieve
const snippet = await ctx.storage.persistent.get('snippet:top_customers');
@@ -268,7 +278,10 @@ result.entries.forEach(entry => {
console.log(result.count); // total matching entries across all pages
// Shared (global) scope
const shared = await ctx.storage.persistent.shared.list({ page: 0, pageSize: 10 });
const shared = await ctx.storage.persistent.shared.list({
page: 0,
pageSize: 10,
});
```
```python

View File

@@ -37,6 +37,7 @@ FEATURE_FLAGS = {
```
When GTF is disabled:
- The Task List UI menu item is hidden
- The `/api/v1/task/*` endpoints return 404
- Calling or scheduling a `@task`-decorated function raises `GlobalTaskFrameworkDisabledError`
@@ -79,10 +80,10 @@ print(task.status) # "success"
### Async vs Sync Execution
| Method | When to Use |
|--------|-------------|
| `.schedule()` | Long-running operations, background processing, when you need to return immediately |
| Direct call | Short operations, when deduplication matters, when you need the result before responding |
| Method | When to Use |
| ------------- | ---------------------------------------------------------------------------------------- |
| `.schedule()` | Long-running operations, background processing, when you need to return immediately |
| Direct call | Short operations, when deduplication matters, when you need the result before responding |
Both execution modes provide the same task features: deduplication, progress tracking, cancellation, and visibility in the Task List UI. The difference is whether execution happens in a Celery worker (async) or inline (sync).
@@ -100,15 +101,15 @@ PENDING ──→ IN_PROGRESS ────→ SUCCESS
└─────────────┴──────────→ ABORTED (user cancel)
```
| Status | Description |
|--------|-------------|
| `PENDING` | Queued, awaiting execution |
| `IN_PROGRESS` | Executing |
| `ABORTING` | Abort/timeout triggered, abort handlers running |
| `SUCCESS` | Completed successfully |
| `FAILURE` | Failed with error or abort/cleanup handler exception |
| `ABORTED` | Cancelled by user/admin |
| `TIMED_OUT` | Exceeded configured timeout |
| Status | Description |
| ------------- | ---------------------------------------------------- |
| `PENDING` | Queued, awaiting execution |
| `IN_PROGRESS` | Executing |
| `ABORTING` | Abort/timeout triggered, abort handlers running |
| `SUCCESS` | Completed successfully |
| `FAILURE` | Failed with error or abort/cleanup handler exception |
| `ABORTED` | Cancelled by user/admin |
| `TIMED_OUT` | Exceeded configured timeout |
## Context API
@@ -139,11 +140,11 @@ Call `update_task()` once per iteration for best performance. Frequent DB writes
The `progress` parameter accepts three formats:
| Format | Example | Display |
|--------|---------|---------|
| Format | Example | Display |
| ----------------- | ------------------- | ---------------------- |
| `tuple[int, int]` | `progress=(3, 100)` | 3 of 100 (3%) with ETA |
| `float` (0.0-1.0) | `progress=0.5` | 50% with ETA |
| `int` | `progress=42` | 42 processed |
| `float` (0.0-1.0) | `progress=0.5` | 50% with ETA |
| `int` | `progress=42` | 42 processed |
:::tip
Use the tuple format `(current, total)` whenever possible. It provides the richest information to users: showing both the count and percentage, while still computing ETA automatically.
@@ -159,10 +160,10 @@ In the Task List UI, when a payload is defined, an info icon appears in the **De
Register handlers to run cleanup logic or respond to abort requests:
| Handler | When it runs | Use case |
|---------|--------------|----------|
| `on_cleanup` | Always (success, failure, abort) | Release resources, close connections |
| `on_abort` | When task is aborted | Set stop flag, cancel external operations |
| Handler | When it runs | Use case |
| ------------ | -------------------------------- | ----------------------------------------- |
| `on_cleanup` | Always (success, failure, abort) | Release resources, close connections |
| `on_abort` | When task is aborted | Set stop flag, cancel external operations |
```python
@task
@@ -187,6 +188,7 @@ Multiple handlers of the same type execute in LIFO order (last registered runs f
**All registered handlers will always be attempted, even if one fails.** This ensures that a failure in one handler doesn't prevent other handlers from running their cleanup logic.
For example, if you have three cleanup handlers and the second one throws an exception:
1. Handler 3 runs ✓
2. Handler 2 throws an exception ✗ (logged, but execution continues)
3. Handler 1 runs ✓
@@ -200,6 +202,7 @@ Write handlers to be independent and self-contained. Don't assume previous handl
## Making Tasks Abortable
When users click **Cancel** in the Task List, the system decides whether to **abort** (stop) the task or **unsubscribe** (remove the user from a shared task). Abort occurs when:
- It's a private or system task
- It's a shared task and the user is the last subscriber
- An admin checks **Force abort** to stop the task for all subscribers
@@ -229,6 +232,7 @@ def abortable_task(items: list[str]) -> None:
```
**Key points:**
- Registering `on_abort` marks the task as abortable and starts the abort listener
- The abort handler fires automatically when abort is triggered
- Use a flag pattern to gracefully stop processing at safe points
@@ -283,11 +287,11 @@ The timeout timer starts when the task begins executing (status changes to `IN_P
### Timeout Precedence
| Source | Priority | Example |
|--------|----------|---------|
| `TaskOptions.timeout` | Highest | `options=TaskOptions(timeout=600)` |
| `@task(timeout=...)` | Default | `@task(timeout=300)` |
| Not set | No timeout | Task runs indefinitely |
| Source | Priority | Example |
| --------------------- | ---------- | ---------------------------------- |
| `TaskOptions.timeout` | Highest | `options=TaskOptions(timeout=600)` |
| `@task(timeout=...)` | Default | `@task(timeout=300)` |
| Not set | No timeout | Task runs indefinitely |
Call-time options always override decorator defaults, allowing tasks to have sensible defaults while permitting callers to extend or shorten the timeout for specific use cases.
@@ -345,11 +349,11 @@ def shared_task(): ...
def system_task(): ...
```
| Scope | Visibility | Cancel Behavior |
|-------|------------|-----------------|
| `PRIVATE` | Creator only | Cancels immediately |
| `SHARED` | All subscribers | Last subscriber cancels; others unsubscribe |
| `SYSTEM` | Admins only | Admin cancels |
| Scope | Visibility | Cancel Behavior |
| --------- | --------------- | ------------------------------------------- |
| `PRIVATE` | Creator only | Cancels immediately |
| `SHARED` | All subscribers | Last subscriber cancels; others unsubscribe |
| `SYSTEM` | Admins only | Admin cancels |
## Task Cleanup
@@ -393,11 +397,11 @@ By default, abort detection and sync join-and-wait use database polling. Configu
### TaskContext Methods
| Method | Description |
|--------|-------------|
| `update_task(progress, payload)` | Update progress and/or custom payload |
| `on_cleanup(handler)` | Register cleanup handler |
| `on_abort(handler)` | Register abort handler (makes task abortable) |
| Method | Description |
| -------------------------------- | --------------------------------------------- |
| `update_task(progress, payload)` | Update progress and/or custom payload |
| `on_cleanup(handler)` | Register cleanup handler |
| `on_abort(handler)` | Register abort handler (makes task abortable) |
### TaskOptions
@@ -429,6 +433,7 @@ def risky_task() -> None:
```
On failure, the framework records:
- `error_message`: Exception message
- `exception_type`: Exception class name
- `stack_trace`: Full traceback (visible when `SHOW_STACKTRACE=True`)

View File

@@ -40,6 +40,7 @@ Sentence case is predominantly lowercase. Capitalize only the initial character
- User input that is reflected in the UI. E.g. a user-named a dashboard tab
**Sentence case vs. Title case:**
- Title case: "A Dog Takes a Walk in Paris"
- Sentence case: "A dog takes a walk in Paris"
@@ -110,12 +111,12 @@ Primary buttons have a fourth style: dropdown.
**Purpose:**
| Button Type | Description |
|------------|-------------|
| Primary | Main call to action, just 1 per page not including modals or main headers |
| Secondary | Secondary actions, always in conjunction with a primary |
| Tertiary | For less prominent actions; can be used in isolation or paired with a primary button |
| Destructive | For actions that could have destructive effects on the user's data |
| Button Type | Description |
| ----------- | ------------------------------------------------------------------------------------ |
| Primary | Main call to action, just 1 per page not including modals or main headers |
| Secondary | Secondary actions, always in conjunction with a primary |
| Tertiary | For less prominent actions; can be used in isolation or paired with a primary button |
| Destructive | For actions that could have destructive effects on the user's data |
### Format
@@ -173,9 +174,9 @@ In all cases, encountering errors increases user friction and frustration while
Select one pattern per error (e.g. do not implement an inline and banner pattern for the same error).
| When the error... | Use... |
|------------------|--------|
| Is directly related to a UI control | Inline error |
| When the error... | Use... |
| --------------------------------------- | ------------ |
| Is directly related to a UI control | Inline error |
| Is not directly related to a UI control | Banner error |
#### Inline

View File

@@ -43,7 +43,7 @@ This is a list of statements that describe how we do frontend development in Sup
- We organize our repo so similar files live near each other, and tests are co-located with the files they test.
- See: [SIP-61](https://github.com/apache/superset/issues/12098)
- We prefer small, easily testable files and components.
- We use OXC (oxlint) and Prettier to automatically fix lint errors and format the code.
- We use OXC (oxlint and oxfmt) to automatically fix lint errors and format the code.
- We do not debate code formatting style in PRs, instead relying on automated tooling to enforce it.
- If there's not a linting rule, we don't have a rule!
- See: [Linting How-Tos](../contributing/howtos.md#typescript--javascript)

View File

@@ -58,21 +58,25 @@ superset-frontend/src/components
**Reference naming:** Use `PascalCase` for React components and `camelCase` for component instances
**BAD:**
```jsx
import mainNav from './MainNav';
```
**GOOD:**
```jsx
import MainNav from './MainNav';
```
**BAD:**
```jsx
const NavItem = <MainNav />;
```
**GOOD:**
```jsx
const navItem = <MainNav />;
```
@@ -80,11 +84,13 @@ const navItem = <MainNav />;
**Component naming:** Use the file name as the component name
**BAD:**
```jsx
import MainNav from './MainNav/index';
```
**GOOD:**
```jsx
import MainNav from './MainNav';
```
@@ -92,11 +98,13 @@ import MainNav from './MainNav';
**Props naming:** Do not use DOM related props for different purposes
**BAD:**
```jsx
<MainNav style="big" />
```
**GOOD:**
```jsx
<MainNav variant="big" />
```
@@ -104,23 +112,27 @@ import MainNav from './MainNav';
**Importing dependencies:** Only import what you need
**BAD:**
```jsx
import * as React from "react";
import * as React from 'react';
```
**GOOD:**
```jsx
import React, { useState } from "react";
import React, { useState } from 'react';
```
**Default VS named exports:** As recommended by [TypeScript](https://www.typescriptlang.org/docs/handbook/modules.html), "If a module's primary purpose is to house one specific export, then you should consider exporting it as a default export. This makes both importing and actually using the import a little easier". If you're exporting multiple objects, use named exports instead.
_As a default export_
```jsx
import MainNav from './MainNav';
```
_As a named export_
```jsx
import { MainNav, SecondaryNav } from './Navbars';
```
@@ -138,10 +150,10 @@ Validate all props with the correct types. This replaces the need for a run-time
```tsx
type HeadingProps = {
param: string;
}
};
export default function Heading({ children }: HeadingProps) {
return <h2>{children}</h2>
return <h2>{children}</h2>;
}
```
@@ -152,7 +164,8 @@ Use `type` for your component props and state. Use `interface` when you want to
In order to improve the readability of your code and reduce assumptions, always add default values for non required props, when applicable, for example:
```tsx
const applyDiscount = (price: number, discount = 0.05) => price * (1 - discount);
const applyDiscount = (price: number, discount = 0.05) =>
price * (1 - discount);
```
## Functional components and Hooks

View File

@@ -60,21 +60,21 @@ const StatusThing = styled.div`
export const InfoThing = styled(StatusThing)`
background: blue;
&::before {
content: "";
content: '';
}
`;
export const WarningThing = styled(StatusThing)`
background: orange;
&::before {
content: "⚠️";
content: '⚠️';
}
`;
export const TerribleThing = styled(StatusThing)`
background: red;
&::before {
content: "🔥";
content: '🔥';
}
`;
```
@@ -138,14 +138,20 @@ function FakeGlobalNav(props) {
const menuItemStyles = css`
display: block;
border-bottom: 1px solid cadetblue;
font-family: "Comic Sans", cursive;
font-family: 'Comic Sans', cursive;
`;
return (
<Nav>
<a css={menuItemStyles} href="#">One link</a>
<Link css={menuItemStyles} to={url}>Another link</Link>
<div css={menuItemStyles} onClick={() => alert('clicked')}>Another link</div>
<a css={menuItemStyles} href="#">
One link
</a>
<Link css={menuItemStyles} to={url}>
Another link
</Link>
<div css={menuItemStyles} onClick={() => alert('clicked')}>
Another link
</div>
</Nav>
);
}
@@ -158,21 +164,29 @@ function FakeGlobalNav(props) {
By default the `css` prop uses the object syntax with JS style definitions, like so:
```jsx
<div css={{
borderRadius: 10,
marginTop: 10,
backgroundColor: '#00FF00'
}}>Howdy</div>
<div
css={{
borderRadius: 10,
marginTop: 10,
backgroundColor: '#00FF00',
}}
>
Howdy
</div>
```
But you can use the `css` interpolator as well to get away from icky JS styling syntax. Doesn't this look cleaner?
```jsx
<div css={css`
border-radius: 10px;
margin-top: 10px;
background-color: #00FF00;
`}>Howdy</div>
<div
css={css`
border-radius: 10px;
margin-top: 10px;
background-color: #00ff00;
`}
>
Howdy
</div>
```
You might say "whatever… I can read and write JS syntax just fine." Well, that's great. But… let's say you're migrating in some of our legacy LESS styles… now it's copy/paste! Or if you want to migrate to or from `styled` syntax… also copy/paste!
@@ -261,9 +275,7 @@ AntD uses a cool trick called compound components. For example, the `Menu` compo
Let's say you want to override an AntD component called `Foo`, and have `Foo.Bar` display some custom CSS for the `Bar` compound component. You can do it effectively like so:
```jsx
import {
Foo as AntdFoo,
} from 'antd';
import { Foo as AntdFoo } from 'antd';
export const StyledBar = styled(AntdFoo.Bar)`
border-radius: ${({ theme }) => theme.borderRadius}px;

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