* 🤖 backported "Security Center" (#72346)
* Security Center (#71661)
* security center data model (#71660)
* add security_center model
* wip: migration
* kondo
* Advisory security endpoints (#71704)
* Security center admin page and advisory list (#71707)
* Use :admin-security-center feature flag and restore premium-handler on route
* Reuse notification system components for security center channel config (#71723)
* Security center settings (#71807)
* feat: add security-center recipients settings
* feat(FE): add security-center settings
* tests
* feat(FE): hook to settings
* Security center matching engine (#71747)
* upgrade banner (#71800)
* added banner (#71816)
* moved the security center into the top bar (#71821)
* fixed an e2e test
* Gate Security Center for non-trial subscriptions (#71799)
* Gate Security Center for non-trial subscriptions
Trial subscriptions should not have access to Security Center to
prevent abuse via easily-obtainable trial enterprise tokens.
Adds `is-trial?` and `assert-not-trial` to the premium features
token check, and applies a `+require-non-trial` middleware to the
security-center route that returns 402 for trial tokens.
* Handle check-token exceptions in is-trial?
Fail open (return false) if the token status check throws, matching
the same pattern used by *token-features*. Prevents a 500 when
MetaStore is unreachable.
* Use token-status setting instead of check-token directly
Follow the existing pattern used by billing and cloud-add-ons.
* Use -token-status instead of the setting getter
* Gate Security Center for non-trial subscriptions
Trial subscriptions should not have access to Security Center to
prevent abuse via easily-obtainable trial enterprise tokens.
Adds is-trial? and security-center-enabled? to premium features
token check, and a +check-not-trial middleware on the security
center API routes that returns 402 for trial tokens.
* Security center notification (#71814)
* feat: add last_notified_at column
* feat: add security-advisory-match event
* feat: security advisory email template
* feat: add slack renderer
* feat: notify
* email fixes
* kondo
* fix: hydrate
* chore: quartz
* test
* send notification sync
* fix: guard against no smtp config
* fix: bcc
* more tests
* only on has feature
* switch to util
* move url builder
* feat: use all-admin-recipients
* Security center: fetch and scheduled evaulation (#71830)
* addressed stas feedback
* all-admins and recipients are no longer exclusive (#71895)
* Fix read only connection for security center (#71898)
* added sync button (#71905)
* Security center unify tasks + CI green (#71894)
* pull notify task into sync task
* make CI green
* chore: exclude security-advisory
* fmt
* require settings in init
* kondo
* set wor
* fixes
* exclude is-hosted
* check-enabled with open-api wrap
* change error
* missing
* fix: emails
* fix use an user-id
* fixes
* init test-users
* enable on dev
* rollback to enforce no writes
* fix: add index
* index before fk
* may not error
* Security center test notification (#71915)
* test notifications
Closes GDGT-2174
* test
* fix
* addressed PR feedback (#71919)
* fix parsing published_at timestamp durign fetch
* fix fetch test to use string published_at matching real API response
The test was using #t tagged literals for published_at which bypassed
the string→timestamp coercion path, masking the bug we just fixed.
* added tests for recipients settings (#71963)
* make recipients non nullable (#71967)
* Treat error match_status as affected (fail-open) (#71961)
* treat error match_status as affected (fail-open)
Per the matching engine spec, when a matching query fails, the advisory
should be treated as potentially affected. The isAffected check was only
looking for "active" status, missing the "error" case.
* fix type errors in createAdvisory mock
Add return type annotation so string literals narrow to the Advisory
type instead of widening to string when spread with Partial<Advisory>.
* Security center: force sync endpoint (#71899)
* Security center cursor (#71969)
* feat: add updated_at
* feat: cursor on updated_at
* feat: since tests
* fix fetch tests
* appease the linter
* fix test
* remove seed
* small fixes
* fix
* feature token properly propagates (#71970)
* added polling for sync button (#71971)
* fix
* fix
* fix
* Add Snowplow tracking for Security Center (#71972)
* Add Snowplow tracking for Security Center
Track 3 events using the existing simple_event schema:
- security_center_page_viewed (FE, on page mount)
- security_advisory_acknowledged (BE, with severity)
- security_advisory_notification_sent (BE, with channel/result/trigger)
* Derive notification channels from handlers instead of config
Instead of re-checking configured-channels at tracking time, derive
the channel list from the notification's actual handlers.
* Move last_notified_at update inside try block
* add :admin-security-center to excluded features in stats test
* kondo
* update schema (#72031)
* hook full feature logic to premium features exposed to the FE (#72026)
* hook full feature logic to premium features exposed to the FE
* tests
* fix test
* chore: error in FE
* fix
* fix e2e test
* lint
* tighten schemas
* fix hydration
* chore: defensively check-superuser
* tighter schemas
* fix test
* chore: simpler schema as we'd need to duplicate with :api/regex
* e2e test should only run on ee
* fix: recipients default (#72035)
* Add testing endpoint for security advisories (#71977)
* fix model boundary violations for SecurityAdvisory
* relax schema
* move to 45 (#72073)
* chore: migrations in 001 file for backporting to 45
* mark-ran preconds
* reorder
* consolidate
* add set null
* Mobile improvements (#72071)
* move to 55
* move severity->repeat-days into an overridable setting
Closes GDGT-2208
* reformat
* typo
* deal with nits
* switch to select-fn->fn
* explicit map building
* more nits
* align
* nit
* add not-empty
* use custom executor instead of future
* use semver4j
* fix test
* restrict queries to selects (#72162)
* reorder
* Security center no h2 (#72215)
* disable security-center for h2 appdbs
* tests
* fix last-checked at, store in setting
* fix tests
* enable for e2e tests
* fix merge conflicts
* Revert "Security center no h2 (#72215)"
This reverts commit 41dc93794d.
* fix: persist last-synced-at in a setting
* fix test
* disable on h2 (enabled for tests) (#72263)
* UI feedback on Security Center (#72214)
* fixed imports
* chore: max 2 mins for advisory query
* kondo
* chore: use sql-jdbc.execute
* kondo
---------
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Co-authored-by: Sébastien <sebastien@metabase.com>
* fixed conflicts
* seed advisories on first run (#72446)
* Updated UI for Security Center (#72518)
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
* fix: re-evaluate active advisories even if they've been acked (#72610)
---------
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Co-authored-by: Sébastien <sebastien@metabase.com>
* remove non related tests that snook in
* type
---------
Co-authored-by: github-automation-metabase <166700802+github-automation-metabase@users.noreply.github.com>
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Co-authored-by: Sébastien <sebastien@metabase.com>
Add installation of Astral and Python3 pip (#72645)
* Add installation of Astral and Python3 pip
If you build Metabase with Docker it will fail unless uv and pip are installed
* Update Dockerfile to remove python3-pip installation
Removed installation of python3-pip from Dockerfile.
Co-authored-by: da <paoliniluis@gmail.com>
* [QP] Change the nested query alias from `source` to `__mb_source` (#70955)
closes#70224
Fixes QUE2-396.
This is necessary because `source` is a reasonably common name for a
column, and databases diverge on how they treat a reference like
`"source"."source"`:
- Postgres et al see the relation `source` in scope, and access its
column called `source`, and all is well.
- Athena et al:
- See that there is a **column** `source` in scope that doesn't require a prefix.
- Assume it's a nested column with `ROW` type, and try to access the
nested `source` field.
- Type mismatch! It's a string or whatever, not `ROW`.
This PR doesn't *eliminate* the problem, but there's not really anything
we can do to fix Athena's honestly pretty odd choice of how to resolve this
ambiguous parse tree. But by changing our hard-coded alias for all
nested queries from `source` to `__mb_source`, we can make it extremely
unlikely that it will collide with a column that's in scope.
* adjust a new test to use the old QP API
---------
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Fix null effective_type for sample database fields (GHY-3367) (#72571)
* Set effective_type for sample database fields (GHY-3367)
Every field entry in resources/sample-content.edn was missing :effective_type,
so CreateSampleContentV2 inserted metabase_field rows with null effective_type
on fresh installs. Default effective_type to match base_type for all 71 fields.
* Test that sample-db fields have non-null effective_type (GHY-3367)
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Grant admin access to Helping Hand support user (#72478)
fetch-or-create-support-user! now sets is_superuser=true on all paths
(new user, reactivation, and existing active user). On grant revocation,
is_superuser is set back to false. This ensures the support user has
full admin access as promised by the grant access dialog.
Fixes: UXW-3725
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Downgrade all netty pins to 4.2.9.Final (#72546)
Netty 4.2.12 introduced a breaking change in HttpObjectEncoder that
causes AWS SDK netty-nio-client to fail with "unexpected message type:
LastHttpContent" errors. Revert to 4.2.9.Final which is compatible
with the AWS SDK while still being in the 4.2.x line.
Closes: #72532
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Pick random host when testing Redshift from `MB_REDSHIFT_TEST_HOSTS` (#72498)
* Pick random host when testing Redshift from MB_REDSHIFT_TEST_HOSTS
* Debugging
* Update CI config
* Oops
* Simplify connection details
* Kicc CI
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
Make CLJS dev port configurable in CSP via MB_CLJS_DEV_PORT (#72530)
The frontend dev port was already configurable via MB_FRONTEND_DEV_PORT,
but the CLJS REPL port (shadow-cljs) was still hardcoded to 9630. This
causes CSP violations when running multiple Metabase instances with
dynamic port allocation.
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Fix dashboard PUT response (#72173)
Extract shared `apply-card-permission-filters` helper used by both GET and
PUT paths to ensure consistent card visibility filtering. Also fix
`set-download-perms-on-dashcards` to handle empty dataset_query maps
gracefully.
Fixes: UXW-3571
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
fix n+1s in db, table, group creation (#72087)
* fix n+1s in db, table, group creation
this batches permissions changes to fix cluster lock timeouts with large numbers of groups, database, and tables.
When we created a new group, table, or database, we obtained O(NxM) fine-grained cluster locks, and did NxM separate inserts into data permissions.
This does batch operations instead. Obtains a single cluster-wide shared lock for batch operations (which actually might not be necessary at all for database and group creation - think it's still needed for creating a table though), then does the insert in batches.
Reduces the total number of queries dramatically:
- group creation: scaling with NxM -> ~10
- db creation: scaling with NxM -> ~10
- table creation: scaling with NxM -> ~8
* Fixup tests, improve perf more
* comment cleanup
* fix test
* remove dead code + unnecessary api epxansion
* Fix cluster lock contention
This is a fairly big change on its own, but it's fairly straightforward
and an additional performance improvement that should help with
concurrent processes trying to modify permissions at the same time.
Essentially, I realized that currently our cluster lock system provides
exactly one type of lock, an exclusive lock. But that's not the only
type of potential lock! Both Postgres and MariaDB/MySQL support locking
a row as *shared*. This conflicts with exclusive locks (`FOR UPDATE`)
but does not conflict with other shared locks.
This way, we can design a two-level lock system in which:
- most operations require:
- a *shared* lock on `::batch-permissions-update`, and
- an *exclusive* lock on `::batch-permissions-update-<db>`
- some operations require only an *exclusive* lock on
`::batch-permissions-update`.
As one example, modifying permissions with the graph API requires an
exclusive lock on `::batch-permissions-update`. We don't want sync
adding a table at the same time that someone is modifying permissions,
e.g. moving from granular -> coalesced or vice versa.
On the other hand, sync itself just requires a *shared* lock on
`::batch-permissions-update`, because it can happily coexist with other
syncs that are for different databases. But they'll all take exclusive
locks on `::batch-permissions-update-<db>`, so any permissions changes
they're making to the database will be serialized.
Co-authored-by: John Swanson <john.swanson@metabase.com>
Update cheshire version to 6.2.0 (#72279)
* Update cheshire version to 6.2.0
https://github.com/dakrone/cheshire/commits/master/
patches the jackson-core dep issue
* Make JSON error test resilient to parser version changes
Use regex matching instead of exact string equality so the test
doesn't break when the JSON parser reports a different column offset.
---------
Co-authored-by: da <paoliniluis@gmail.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
Add GitHub Action to auto-resolve backport conflicts with Claude (#71158)
* Add GitHub Action to auto-resolve backport conflicts with Claude
Adds a new workflow triggered by the `auto-resolve-conflicts` label (or
manual dispatch) that uses Claude Code to automatically resolve cherry-pick
conflicts on backport PRs. This eliminates the manual step of checking out
the branch, running backport.sh, and hand-resolving conflicts.
* Add kondo and typescript checks
* Add syntax validation and formatting to backport conflict resolver
- Prepare backend (JDK/Clojure) and frontend (Node/Bun) environments
- Run cljfmt and eslint --fix to auto-format resolved files
- Run clj-kondo and tsc to validate syntax before completing cherry-pick
- Claude loops on errors until files are clean before committing
* Make Claude max turns configurable in backport conflict resolver, default to 50
* Fix Bash permission pattern for cljfmt in backport conflict resolver
Use colon-star syntax (cljfmt:*) to match other Bash tool permission
patterns, fixing permission denial for ./bin/mage cljfmt-files.
* Detect yarn vs bun for older release branches in backport resolver
Release branches ≤58 use yarn, ≥59 use bun. Detect the package manager
by checking for bun.lock after checkout, then use it for the CLJS build
step, allowed_tools permissions, and Claude prompt instructions.
* Set NODE_VERSION=22 for claude-code-base-action step
The action internally runs setup-node with 18.x by default, overriding
the Node 22 installed by prepare-frontend. This caused yarn engine
check failures on older release branches. The action respects a
NODE_VERSION env var, so set it to 22.
* Improve backport resolver: detect max turns, add commit details to success message
- Bump default max turns from 50 to 75
- Detect when Claude exits due to max_turns exceeded and post a specific
comment explaining the issue with a link to re-run the workflow
- Include a commit link and collapsible changed files list in the success comment
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
* Don't trigger result-metadata write based on non-default parameters (#72007)
If you have a parameterized card with computed columns, there is no Field from which to pull fingerprints, and the query-processor runs a fingerprint process based on the results of the query. Because the query is parameterized, the result is specific to whatever random parameter was used. `record-metadata!` saw this difference and updated the result-metadata on the card.
The fix: we will no longer persist `result_metadata` when non-default parameterized values are present.
* Add missing require
* stuff getting moved around but not really, just 'convenience facade' noise
---------
Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>
Co-authored-by: Timothy Dean <timothy@timothydean.dev>
docs: Update links in CONTRIBUTING.md to latest version (#72300)
Update links in CONTRIBUTING.md to latest version
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Require authentication for eid-translation API endpoints (#72174)
The /api/eid-translation routes were unauthenticated despite only being
used by frontend routes behind the IsAuthenticated guard. Wrap with +auth
and remove the stale "public facing" comment.
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
chore: replace vulnerable underscore with a util (#70784)
* chore: replace vulnerable underscore with a util
* missed another function
* remove underscore
Co-authored-by: Uladzimir Havenchyk <125459446+uladzimirdev@users.noreply.github.com>
Block database routing when transforms already exist (#71931)
Prevent enabling database routing on a database that already has transforms, since running transforms on databases with DB routing is not supported
Backend: added validation check in PUT /api/ee/database-routing/router-database/:id that returns 400 if transforms exist for the database
Frontend: disables the routing toggle in the UI when transforms exist, with a descriptive message
Also wired through the existing but unused database-id filter param in the transforms list API
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
docs - Fix formatting of Agent API link in documentation (#71941)
Fix formatting of Agent API link in documentation
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Fix usage_info IN clause exceeding 65K parameter limit (GHY-2413) (#71856)
- Fixes `GET /api/database/:id/usage_info` failing when a database has more than 65K tables
- The segment count query was passing all table IDs as parameters to an `IN` clause, which exceeds PostgreSQL's 65,535 parameter limit
- Replaced the `IN` clause with a subselect (`SELECT id FROM metabase_table WHERE db_id = ?`), eliminating the parameter explosion
- Removed the now-unnecessary `select-pks-set` call and `table-ids` argument from `database-usage-query`
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Fix sync_schema silently dropping when executor is busy (GHY-3254) (#71756)
* Add failing test reproducing GHY-3254: sync_schema silently drops when executor is busy
The quick-task executor uses a single thread. If any task gets stuck
(e.g., a hanging JDBC connection), all subsequent manual sync requests
queue forever while the endpoint returns 200.
* Add per-task timeout to quick-task executor
Each task submitted to the quick-task executor now runs on a child
thread with a configurable timeout (*task-timeout-ms*, default 2h).
If a task exceeds the timeout, it is cancelled and the executor moves
on to the next queued task. This prevents a single stuck task from
blocking all subsequent manual sync requests.
The stuck thread's stack trace is logged for diagnostics.
* Use MB_QUICK_TASK_TIMEOUT_MINUTES env var for task timeout
Replace the dynamic var with a real env var (default 120 minutes).
* Use config/config-int for MB_QUICK_TASK_TIMEOUT_MINUTES
Read the env var via metabase.config.core instead of System/getenv,
consistent with how other config values are read in the codebase.
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Fix support access grant password reset failing for deactivated users (#71598)
* Fix support access grant password reset failing for deactivated users
When a support user was deactivated (e.g. after a previous grant expired),
creating a new grant would leave the user inactive. The password reset
token authentication would succeed, the :after method would consume the
token and change the password, but create-session! would then reject the
login because is_active was false. with-fallback would swallow this and
fall back to emailed-secret-password-reset which also failed, resulting
in an opaque "Invalid reset token" error with the token irreversibly
consumed.
Fix: fetch-or-create-support-user! now reactivates deactivated users.
Also adds tests for the deactivated user flow, pre-existing auth identity
cascade, with-fallback error swallowing behavior, and direct login! calls
for easier debugging.
* fixup! cljfmt
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
[QP] Do coercions (eg. Unix timestamps) with native sandboxing (RCLS) (#70885)
Fixes QUE2-376.
For MBQL queries, type coercions (like integers to Unix timestamps) only
get applied on the earliest stage where that field is introduced. When
the table the field comes from is sandboxed by a native query, an
extra stage is introduced but it doesn't do the coercion.
Decorates the metadata of any native sandbox column whose table counterpart had coercion defined.
It's unfortunately complicated inside lib since the metadata needs to be propagated through exactly one
stage boundary. If it propagates all the way then we get double-coercion and SQL errors.
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Fix notification send test retry config key (:max-attempts → :max-retries) (#71689)
The test overrode :max-attempts but diehard uses :max-retries, so the
override was silently ignored and all 6 retries ran with exponential
backoff (~31s). With the correct key the test finishes in ~1s.
Done: task/fix-notification-retry-key
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Fix field filter dropdowns for users without create-queries permission GHY-1605 (#71046)
## Summary
Field filter dropdowns on native query cards show as text inputs ("Enter some text") for users who have view-data permission but lack create-queries permission on the underlying table.
**Root cause:** Two issues combined to break this:
1. **Frontend couldn't determine dropdown type** — The frontend needs `has_field_values` from field metadata to decide whether to show a dropdown vs text input. This metadata came from `GET /api/database/:id`, which returns 403 for users without `create-queries` permission. Without it, the widget falls back to a text input.
2. **Backend param values endpoint was too restrictive** — Even if the frontend showed a dropdown, the card param values endpoint (`GET /api/card/:id/params/:key/values`) would fail because `search-values-from-field-id` does `api/read-check` on the Field (which requires `create-queries`), and the QP permission check also required `create-queries`.
**Fix:**
- **Hydrate `param_fields` on Card API response** (matching existing Dashboard pattern) — includes `has_field_values` so the frontend can show the correct widget type without needing `GET /api/database/:id`
- **Populate metadata store with `param_fields`** on card load in the query builder
- **Bind `*param-values-query*`** in card param values endpoints (like dashboards already do) so the QP only checks `view-data` permission
- **Skip `api/read-check` on Field** in `search-values-from-field-id` when `*param-values-query*` is true
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Hide destination DBs from permissions (#71395)
* FE: do not show destination DBs in permissions editor
If you add a destination database, don't show it in the perms editor.
This was a temporary bug (disappears on refresh) BUT if you edit permissions
for the destination database then that is persisted, which is not great. I
will fix that in a separate PR.
* Don't add data permissions rows for destination DBs
- Exclude destination databases from the permissions graph
- Don't add permissions for destination DBs when creating a new group
Co-authored-by: John Swanson <john.swanson@metabase.com>
* feat: admin password reset link for users (#70464)
* feat: admin password reset link for users
* fixup! add missing dep to modules.edn
* fixup! response schema position
* fixup! reset e2e tests
* fix: store temporary password in Redux after no-SMTP password reset
The handleResetConfirm function called updatePassword via RTK Query but
never dispatched storeTemporaryPassword, so the temporary password modal
never appeared.
* fix: replace smart quotes with straight apostrophes in password reset modal
The modal title and body strings used Unicode RIGHT SINGLE QUOTATION MARK
(U+2019) instead of ASCII apostrophe, causing E2E tests to fail on text
matching.
* fix: correct reset URL assertion in e2e test
The test expected "password-reset" but the actual URL path is
"reset_password".
* fix: add missing storeTemporaryPassword export and resolve duplicate interface name
The people.js module was missing the storeTemporaryPassword action creator
export, and UserPasswordResetModal.tsx had two interfaces with the same name
causing the test file to see the wrong type signature.
---------
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
Pin google auth dependency to avoid driver mismatches (#70958)
* pin dep
* trigger ci tests
* update test
Co-authored-by: Riley Thompson <riley@metabase.com>
Wrap sqlserver boolean expressions in a case statement (#67136)
* wrap in case
* wrap case in cast, cleanup
* comments
* rename
* add test
* move comparison operators to lib.schema.filter
* Add boolean ops
* add and, or, not. rename comparison to predicate
* clean up tests
Co-authored-by: Riley Thompson <riley@metabase.com>
Fix silent data loss when importing unparseable YAML files (#71421)
* Surface ingestion errors instead of silently skipping unparseable YAML files
The serdes ingestion layer was silently dropping YAML files that failed
to parse (introduced in #41887 as defensive coding for editor temp
files). This caused remote sync imports to silently lose entities when
YAML files were malformed or exceeded SnakeYAML's nesting depth limit,
with no error reported to the user.
Add `ingestion-errors` to the Ingestable protocol so the ingestion
layer collects parse failures and surfaces them through `load-metabase\!`.
When `continue-on-error` is false (default, used by remote sync), the
import fails immediately on ingestion errors. When true, errors are
collected and reported alongside load-phase errors.
The dotfile filter from #41567 is preserved — editor temp files are
still silently skipped before parsing is attempted.
Fixes#71257
* Rename ingestion-errors to ingest-errors, extract populate-cache\! helper, add e2e tests
- Rename protocol method to ingest-errors for consistency with ingest-list/ingest-one
- Extract populate-cache\! helper to DRY up duplicated cache-population logic
- Add e2e test for continue-on-error true/false with ingestion errors
* Add tests for ingest-errors on IngestableSnapshot and wrapper delegation
* Fix log/warnf misuse, tighten tests, remove stale comment
- log/warnf -> log/warn to prevent MissingFormatArgumentException
when error messages contain % characters
- Add tests for ingest-errors ordering contract and multi-file corruption
- Tighten continue-on-error assertion to check exact error count
- Remove stale comment describing pre-fix behavior
* Include file names in ingestion error messages
Wrap parse/read exceptions with ex-info containing the file path,
so the error message shows which files failed, e.g.
"Failed to read 1 file(s) during ingestion: bad_card.yaml"
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
[Params] Always return `[]` for param `/values` requests (#71302)
Fixes#71164.
On the BE, always return an empty list rather than nil. Old models with `:id` different from `:field_ref` in their metadata could result in `{:values nil ...}` being returned, which breaks the schema and FE. See #71164 for full details.
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Remove sync buttons for managed cloud databases (#71203)
* Remove sync buttons for managed cloud databases
* Remove sync settings button for table in attached data warehouse in admin > table metadata and data studio
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Small positioning adjustments to the data studio nav bar (#71379)
* Small positioning adjustments to the data studio nav bar
* pr feedback
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
display sql transforms errors in editor (#71092)
* update setupCardDataset to use named params
* display sql transform errors in editor
* improve mock data in test
* use isObject helper
# Conflicts:
# enterprise/frontend/src/metabase-enterprise/tenants/components/CreateTenantsOnboardingStep/hooks/use-field-distinct-values.unit.spec.tsx
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
Update response on set token with network error (#70959)
* Update response on set token with network error
* report error message from checker when setting token
Currently when anything goes wrong during token checking while we're
setting a token, we *always* report that the token is invalid. This is
incorrect.
The token checker already gives us a descriptive `status` for the token,
which can tell the user whether the token is invalid or if we just
weren't able to check it.
One slight change here is to add `:canonical? true` to responses we
receive from MetaStore directly. This allows us to respond with the
correct HTTP status, since if we receive a response from the MetaStore
that tells us the token is invalid, that's a 400 error, where if we
weren't able to get a canonical response at all, that's a 503.
* add unit test
---------
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Co-authored-by: John Swanson <john.swanson@metabase.com>
Revive and merge PR #67694: disable sync_schema side-effect in db-operations-test (#71201)
Fix H2 lock timeout in db-operations-test by mocking sync task
Split the monolithic db-operations-test into three focused tests:
- non-admin-sync-schema-test: mocks quick-task/submit-task! to prevent
the actual sync job from running, eliminating the race condition with
DATA_PERMISSIONS cleanup in mt/with-all-users-data-perms-graph!
- non-admin-discard-field-values-test: isolated test for discard_values
- non-admin-rescan-field-values-test: isolated test for rescan_values
Also renames update-database-test, delete-database-test, and fetch-db-test
to non-admin-* for consistency, and adds explicit permission-denial (403)
test cases to each test.
Revives the fix from closed PR #67694.
[QP] Override `LIMIT` for pivot queries to ensure consistent results (#71033)
Closes#70963
Fixes QUE2-431.
Previously, pivot queries got the same default row limits added as any
aggregated query. But since pivot queries synthesize the results from
several inner queries with different subsets of breakouts, they
have different row counts.
The main ("row details") query the user wrote has all the breakouts,
so it has the most rows. If that query gets truncated, only a subset
of the data is returned, leaving gaps in the pivot table. Worse, the
sub-queries with other subsets of the breakouts, intended to collect
group, column and row subtotals, and the grand total, are inconsistent
with the details in the cells, and with each other, because they can
all end up `SUM`ing (etc.) over different sets of the raw rows.
With this change, a new and much larger row limit is permitted for the
pivot sub-queries. The pivot table viz contains one cell for each
aggregation in the query, multiplied by the rows of the main query.
We budget for **200k cells**, divide by the number of aggregations,
and that becomes the row limit.
If the row details query reaches that limit, the query is rejected:
- Other sub-queries are skipped
- A `pivot-rows-truncated` flag in the results signal the FE
- Which shows an error suggesting the user add a filter or remove
breakouts to lower the row count.
Some reasonable pivot queries might still be excluded, but now we never
run a pivot query with incorrect data in it. If we execute the query and
render the pivot results, then all the returned data should be correct.
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Don't generate join alias that matches source table name (#70876)
* include source name in taken names
* add test
* Update src/metabase/lib/join.cljc
* fix tests
* fix test
* Fix test metadata for self-join test
* e2e test fix attempt
* second attempt
---------
Co-authored-by: Riley Thompson <riley@metabase.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
Ghy-3258/table tag dependencies missing in incremental transforms (#71316)
Include table tags as dependencies of native queries
Co-authored-by: Ben Grabow <ben.grabow@metabase.com>
fix: cancel serialization when client disconnects (#69864)
* fix: cancel serialization when client disconnects
* fix: complete serialization virtual thread streaming response
- Fix channel signal direction: use >!! to write to done-chan instead of <!! (read)
- Fix streaming response: use io/copy instead of .write for File objects
- Set explicit 200 status on success, set-status!/set-content-type! on error path
- Add Content-Disposition header on success for proper download behavior
- Clean up temp files on cancel and use finally for deterministic cleanup
- Remove commented-out old synchronous code
- Use canonical clojure.core.async alias (a instead of async)
- Add server module to enterprise/serialization allowed dependencies
- Relax full_stacktrace test threshold (200 -> 50 lines) to avoid JVM-dependent flakiness
---------
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: John Swanson <john.swanson@metabase.com>
Clarify that SSO provisioning also allows reactivating accounts (#67524)
* Clarify that SSO provisioning also allows reactivating accounts
* Update wording in docs
* ditto LDAP
* Use radio buttons instead of a toggle
* lint/wording
* lint
* Revert changes to autogenerated docs
* Fix eslint rule + improve wording
* Make OIDC provisioning setting consistent with other providers
* Add detailed descriptions only to env var docs, not UI
* Fix E2E test
* fix: update ESLint configuration file path from .eslintrc.js to eslint.config.mjs
* run lint when we change component tests specs
* fixing linting
* ignore linting issue in embedding test
---------
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Co-authored-by: Nicolò Pretto <info@npretto.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
Fix timeline form icon input (#71199)
* Add icon to timeline icons
* Use Select from mantine/ui for timeline form
* Add test for icon in timeline creation
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Convert dataref to ts (#71062)
* Convert dataref to ts
* Fix unit test
* Fix actions
* Fix field reference
* Fix native data reference
* Fix field pane
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Batch metabase_table update migration (#70996)
* fix: batched metabase_table update on data_layer
* don't replace inline
* preserve
* no need for rollback in liquidbase
* run outside of a transaction
* runInTransaction:false
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Hide 'New metric' and 'Publish a table' actions on Data Studio Library empty state when in read-only mode (#71112)
* Fix: Hide metric creation and table publishing actions in read-only mode
In read-only instances (remote sync read-only mode), the Library still showed:
- 'New metric' action link in the Metrics empty state
- 'Publish a table' action button in the Data empty state
- 'New snippet' action link in the SQL snippets empty state
While the +New button was already hidden in read-only mode, the empty state
action links were not checking for this permission, allowing users to attempt
actions that should be disabled.
Changes:
- Add read-only mode check to EmptyStateAction component in LibrarySectionLayout
- Empty state actions now return null when in remote sync read-only mode
- Add e2e test to verify actions are hidden in read-only mode
* Refactor: use hideAction param and call-site guard instead of returning null from EmptyStateAction
Leverage the existing third param of createEmptyStateItem to suppress
actionUrl for metrics/snippets in read-only mode (consistent with how
the snippet tree handles it). Guard the 'Publish a table' button at
the EmptyStateAction call site in LibrarySectionContent, outside the
component itself. Reorganise the e2e test into the empty state describe
block.
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
* Fix StackOverflowError in deduplicated column name resolution (#71096)
Add a dynamic guard `*in-deduplicated-column-resolution?*` and convert the
mutual recursion between `resolve-nonexistent-deduplicated-column-name` and
`resolve-from-previous-stage-or-source` into a loop. Previously, resolving
a field like `name_5000` would create O(N) deep mutual recursion, overflowing
the JVM stack at ~3000-4000 frames.
* Remove cherry-picked tests that depend on features not in 1.59
The resolve-in-implicit-join-should-use-source-field-join-alias and
resolve-in-implicit-join-should-use-source-field-name tests were
cherry-picked from master but test features (source-field-join-alias
disambiguation) not present on the 1.59 branch.
* Remove remaining master-only tests from backport
Remove resolve-field-ref-missing-table-previous-stage-metadata-test,
resolve-field-ref-wrong-join-alias-missing-card-previous-stage-metadata-test,
and resolve-field-ref-missing-parent-field-test which were accidentally
brought over from master during the cherry-pick conflict resolution.
---------
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Remove `X-Metabase-Session` from autogenerated API docs in favor of `X-API-Key` (#71155)
* X-API-Key capitalization in docs
* Use X-API-Key instead of X-Metabase-Session in Scalar API docs
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Fix string field IDs leaking into bulk-metadata queries (#71167)
Add pos-int? guard to all-implicitly-joined-field-ids pattern match,
matching the guard already used by all-field-ids. String field names
(e.g. from native/model sources) were being collected and passed to
bulk-metadata, causing Postgres type mismatch errors.
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Add ci:run-<driver> and ci:run-all-drivers labels to mage driver decisions (#70894)
* Add ci:run-<driver> and ci:run-all-drivers labels to mage driver decisions
Allow force-running specific drivers or all drivers via PR labels,
overriding quarantine. Inserted at priority 3 (after H2/Postgres
always-run, before quarantine check). Added Labels of Interest and
All Drivers sections to help output.
* Add hint about ci:run labels in CI driver decisions output
Shows a helpful message in CI logs pointing users to the new labels
and the local help command for more info.
---------
Co-authored-by: bryan <bryan.maass@gmail.com>
Co-authored-by: Ben Grabow <ben.grabow@gmail.com>
fix: handle recycled jetty http response objects (#70674)
* fix: handle recycled jetty http response objects
In the streaming response handler. Make sure that the response object is
both committed and that its AsyncContext has not been timedout.
Attempting the write after the timeout results in an NPE.
* fixup! missing reify method
* make async-context-completed? private
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Docs: improve embedding appearance theming section (#70967)
* Docs: improve embedding appearance theming section
Rewrite the basic theming section for clarity: rename to "Dark mode and
light mode", simplify the explanation, and preserve the old
#basic-theming anchor for existing links.
* Update docs/embedding/appearance.md
---------
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Add snowplow events when creating new job (#70279)
* Add snoplow events when creating new job
* Fix e2e
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Correctly hide/show card filters based on permissions (#70980)
Backend (query_processor/dashboard.clj): Added an explicit view-data permission check using most-permissive-database-permission-for-user. This returns 403 when a user has no view-data access, taking precedence over parameter validation errors (400).
Frontend (DashCardVisualization.tsx): Decoupled the three concerns:
* Inline parameters render when inlineParameters.length > 0 AND the user has view access (no 403 on the card result)
* DashCardMenu (download button) renders when DashCardMenu.shouldRender() is true (requires canEditQuestion or canDownloadResults)
* 403 from backend hides both inline params and menu — no point showing UI for data the user can't access
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Fix flaky metabase-enterprise.dependencies.api-test (#71024)
* Drain the single-threaded async executor to ensure all pending dependency work completes before model cleanup deletes cards, avoiding lock timeouts.
* Use fresh-dependency-async-executor-fixture on every test
Co-authored-by: Ben Grabow <ben.grabow@metabase.com>
docs - Fix typo in JWT group mapping documentation (#71017)
Fix typo in JWT group mapping documentation
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Add retry loop to fetch-artifact download step
Wrap the downloadArtifact API call with a retry loop (3 attempts,
exponential backoff at 15s/30s) to handle transient GitHub API 500
errors that have been causing e2e and health-check job failures.
Co-authored-by: mendral-app[bot] <233154221+mendral-app[bot]@users.noreply.github.com>
Show expected type in custom expression error message (#70400)
* initial attempt at better error message
* clean up
* Clean up
* improve doc string
* fix cljc test
* add test
* fix test
* exclude perf functions
* have schema produce user facing expected type
* clean up
* Add test
* fix kondo
* defer i18n
* try test fix
* address comments
* update tests
Co-authored-by: Riley Thompson <riley@metabase.com>
Inline parameter in clickhouse honeysql method (#70905)
* suggested fix and test
* Clean up test
* clean up test
Co-authored-by: Riley Thompson <riley@metabase.com>
Aliases for table template tags (#70893)
* auto include aliases
* simplify hover info
* add unit test for emit tables toggle
---------
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
Fix 500 error in check-card endpoint for cards with broken dependents (#70828)
Fix unhandled exception in POST /api/ee/dependencies/check-card that causes a 500 when a transitive dependent card fails to compile
When check-query-soundness iterates over all dependents, if any card's query throws during compilation (e.g. alias resolution errors), the exception propagated uncaught and crashed the entire endpoint
Added try/catch around check-entity calls in check-query-soundness, returning a validation-exception-error instead of crashing — consistent with the pattern already used in `/dependencies/findings.clj`
On the stats instance, card 4523 has 2,557 transitive card dependents. One of those dependents (a native query referencing card 34523 via a template tag) fails during query compilation with `Missing ::desired-alias->escaped for "email_domain"`. This compilation error is unrelated to the proposed edit but was bringing down the whole endpoint.
Test plan
- Verify POST /api/ee/dependencies/check-card returns 200 with {success: false, bad_cards: [...]} instead of 500 when a dependent card has a query compilation error
- Verify that cards with compilation errors appear in the response as validation-exception-error findings
- Existing dependency check tests still pass
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Track OSS transform usage in Snowplow (#70925)
move snowplow transform metrics to OSS, as transforms are now available on OSS
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Skip running transform jobs if there are no transforms to run (#70926)
* fix: don't run transform jobs if there are no tranforms to run
* chore: add test
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Reduce number of tests kept in memory for embedding SDK component tests (#70928)
* Add memory management settings to SDK component test Cypress config
Add experimentalMemoryManagement: true and numTestsKeptInMemory: 0 to
the embedding SDK component test config. The config spreads defaultConfig
which lacks these settings, causing Cypress to retain 50 DOM snapshots
per test (the default). This leads to Chrome renderer OOM crashes during
content-translations.cy.spec.tsx.
- experimentalMemoryManagement: true triggers gc() between tests
- numTestsKeptInMemory: 0 prevents DOM snapshot heap accumulation
* Use numTestsKeptInMemory: 1 to match main CI config convention
Change from 0 to 1 per review feedback. This matches the value used in
the main e2e config (config.js:190) and keeps the last snapshot available
for debugging while still preventing OOM from the default of 50.
* New password generation for users (#70646)
* New password generation for users
* update to use window.crypto
* updating types
---------
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
Fix flaky schema-change integration test on Redshift (#70863)
Fix flaky python-transform-schema-change-integration-test on Redshift
Replace fixed Thread/sleep with polling for correct field metadata.
The transform pipeline sets run status to :succeeded before
complete-execution! (which runs the metadata sync) finishes. On
Redshift, the sync takes longer due to network latency, so the
2-second sleep was insufficient — the QP would query with stale
Field records (still referencing the old "age" column).
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Add 403 error handling to rerun-workflows.yml (#70916)
Handle 403 errors in rerun-workflows.yml
Wrap the reRunWorkflowFailedJobs API call in a try/catch that
gracefully handles HTTP 403 errors. This prevents false-positive CI
failures when the target run is cancelled, a PR run, or otherwise
ineligible for retry.
Also adds missing await to the API call so errors are properly caught.
Fix broken deps not surfaced for missing fields in :fields (GHY-3157) (#70865)
- The `:soft?` marking in `find-bad-refs-with-source` was too broad — it marked **all** bad refs in `:fields` clauses as soft, even when the field was completely missing from the source (not just inactive).
- Added `(not (:active column true))` guard so only **inactive** fields in `:fields` are marked `:soft?`. Missing/unresolvable fields remain hard errors and are properly surfaced by dependency analysis.
- This preserves the GHY-3044 fix (inactive fields the QP can drop are still soft) while fixing GHY-3157 (genuinely missing fields are reported).
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Update HAR file creation instructions to include sensitive data (#70394)
Updated the documentation to clarify that the HAR file contains sensitive data and revised the instructions for saving the HAR file accordingly. Also added a screenshot of the settings in Chrome.
---------
Co-authored-by: Robert Kosara <rkosara@me.com>
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Handle clickhouse dbname when it has spaces in it (#70822)
* take first name
* Add test
* fix test
* Add comment
* fix typos
Fix typo in comment regarding legacy `dbname` handling.
Co-authored-by: Riley Thompson <riley@metabase.com>
Fix token check errors on startup (#70789)
During startup, the database isn't migrated yet, so we can't check the
token hash.
If the database hasn't been started yet, skip checking the token hash in
the DB and just delegate to the lower-level checker that actually hits
the store.
Co-authored-by: John Swanson <john.swanson@metabase.com>
Ignore unknown settings in clickhouse (#70799)
* move additional options to clickhouse settings
* add test
* add test description
* add prefix and keep in subname
* just ignore unknown settings
* fix test
Co-authored-by: Riley Thompson <riley@metabase.com>
Fix SDK subscription not working under StrictMode (#70663)
* Fix can't click on the time dropdown on subscription sidebar in StrictMode
* Add tests
* update e2e test
* Fix unit tests
* improve code clarity
* Fix E2E tests
* Simplify code
* Make default value consistent
* Make the new Select button have dynamic size
* Fix unit tests
* Fix E2E tests
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
docs: maybe not deprecating (#70790)
Revise guidance on using Transforms over models
Updated recommendation for using Transforms instead of models.
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Get default port from nested connection properties (#70713)
* search for port in group fields
* add test
* update test
* simplify test
* fix sqlite
Co-authored-by: Riley Thompson <riley@metabase.com>
Prefer SQL DML for insert-from-source! to fix bigquery metadata consistency (#69753)
The legacy .insertAll API (and newer Storage API) do not work well with
tables that are created/dropped frequently. This is because their
metadata caches can take a long time to up date.
Python transforms use the drop-recreate fallback strategy for bigquery
so we observe this inconsistency for every run after the first, even
with absurd multi minute timeouts.
The SQL API does not have a problem, so we'll use that. We expect a
performance regression but its better to work slowly than not work at
all.
Other changes:
- Removed now redundant bigquery retry loop
- Dropped dictionary support, we cannot support it easily and it cannot be
considered higher prio than bigquery working at all.
- Added correct parameter typing for JSON.
- Fixed ordering issues in tests (assumed row order when it is
non-deterministic)
Co-authored-by: Dan Stone <wotbrew@gmail.com>
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Add retry + checksum to Clojure install, remove continue-on-error (#70700)
* Add retry + checksum to Clojure install, remove continue-on-error
Remove continue-on-error: true from the Install Clojure CLI step so failures
surface immediately instead of silently propagating to downstream steps.
Add retry logic (3 attempts with curl --retry and --fail) and a post-install
clojure --version gate to handle transient download failures from
download.clojure.org.
* Add explicit error message when all Clojure install retries fail
Handle Data Analyst group name conflict (#70594)
There are 30 instances on stats with groups named "Data Analysts". We
need to handle this case.
First, we modify the migration:
- set `validCheckSum` to `ANY` to handle the case where this migration
already ran
- skip if there's already a `data-analyst` magic group
- insert a group named "Data Analysts", if one doesn't already exist
- otherwise name it "Metabase Data Analysts" (there are 0 groups on
with this name in cloud, theoretically it's possible but someone would
have to have BOTH `Metabase Data Analysts` and `Data Analysts` for this
to be an issue).
Similarly, we create a "Data Analysts" group on startup in OSS if one
doesn't already exist. This group is an invisible placeholder, that will
become visible if the instance ever upgrades. Adopt similar logic here:
if the existing group for data analysts is called "Metabase Data
Analysts", rename it to "Metabase Data Analysts (converted)" and create
the new placeholder group as "Metabase Data Analysts".
Co-authored-by: John Swanson <john.swanson@metabase.com>
Add configurable CSV field separator setting (#69827)
* Add configurable CSV field separator setting
- Adds csv-field-separator setting for configuring CSV export delimiter
- Supports comma (default), semicolon, tab, and other delimiters
- Useful for European locales where semicolon is standard
- Configurable via MB_CSV_FIELD_SEPARATOR environment variable
- Includes tests for different separator types and quoting behavior
Fixes#10256
* Split CSV separator tests into smaller deftests and clean up comments
Break the monolithic csv-field-separator-test into four focused tests:
- csv-field-separator-default-test
- csv-field-separator-semicolon-test
- csv-field-separator-tab-test
- csv-separator-quoting-test (already separate, just removed extra nesting)
Remove the "Changed from hardcoded" comment in csv.clj and the unused
metabase.test.util require.
* fixup! eastwood and serialization baseline
* fixup! whitespace
---------
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: kevin raymond <kevray39@gmail.com>
docs: clarify transform perms (#70650)
clarify perms
Clarified the permissions required for viewing and executing transforms in Metabase.
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Improve modular embedding analytics (#70449)
* Add v3 for modular embedding analytics
* Add implementation
* Improve test readability
* Improve code format
* Make the code autocomplete-able to prevent human-error
* Add missing default value tests
* Format
* Ensure we assert all properties
* fix "id_new" and "id_new_native" tracking
* Update the implementation so it count 0 like before
* Fix logic
* Fix snowplow schema lint
* Remove too much linear ticket number references
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
[MBQL lib] Ignore `inherited-temporal-unit` on bucketed columns (#70512)
Fixes QUE2-394.
This issue was caused by losing the thread of a column between stages in
the case where it has a different `:inherited-temporal-unit` than its
proper `:temporal-unit`.
`lib.equality/=` was checking the `:temporal-unit`s, which match, and
then returning `false` because only one column had
`:inherited-temporal-unit` for a different, finer unit. That shouldn't
fail the match, since the `:inherited-temporal-unit` is obsolete when
the column has just been bucketed differently.
Co-authored-by: Braden Shepherdson <braden@metabase.com>
SSO users can reset password if provider disabled (#70219)
Previously, password-reset-disabled? blocked password reset for all
SSO users unconditionally (except Google when SSO was globally
disabled). After a license downgrade, EE SSO users were locked out —
they couldn't use SSO (no license) and couldn't reset their password
either.
Introduce sso-source-enabled? which checks whether a user's specific
SSO provider is currently active, using setting/get to respect the
:feature guards on EE settings. password-reset-disabled? now delegates
to this function, so password reset is only blocked when the provider
is actually usable.
Co-authored-by: John Swanson <john.swanson@metabase.com>
fix: allow dashboard caching in read-only mode (#70511)
* fix: allow dashboard caching in read-only mode
* fix: split out cache permissions from can-write?
We were denying changing caching policy for dashboards on read-only
remote-synced instances because we set can-write? to false for
dashboards when we are in read-only mode.
we also need to create a new boolean flag we can return to the frontend
to indicate that caching is still allowed even when editing a dashboard
is otherwise disabled.
* fixup! PR feedback
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Upgrade clickhouse to 0.9.7 with pinned dependencies (#70448)
* upgrade clickhouse jdbc to 0.9.7
* clean up todos
* update deps
Co-authored-by: Riley Thompson <riley@metabase.com>
Stop using 2am in tests to avoid DST issues (#70562)
* Stop using 2am in tests to avoid DST issues
* Scope to table cell data
Co-authored-by: Fraser <fraser@metabase.com>
Fix typo in self-dependency removal GHY-3198 (#70535)
There was a typo in a transducer where the cat and remove were swapped. The cat was meant to combine collections (`#{x})` and the remove was looking for `x`, but since it happened in the wrong order, it never removed them. This led to self-dependent entities, and therefore cycles which caused infinite loops.
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
fix: only skip deleting commonpy not pushing it (#70439)
* fix: only skip deleting commonpy not pushing it
* fixup! kondos
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
remove noisy logs from sdk component tests (#70416)
* should fix clj files imported from sdk component tests
* reduce noise when not finding the sdk package
* remove mantine from tests that don't need it
* eslint rule
Co-authored-by: Nicolò Pretto <info@npretto.com>
Fix duplicate alerts/subscriptions firing in multi-pod clusters (#70474)
* Fix duplicate alerts/subscriptions firing in multi-pod clusters
Set acquireTriggersWithinLock=true to force pessimistic locking during
trigger acquisition. Without this, Quartz uses an optimistic UPDATE that
is vulnerable to an ABA race condition where multiple cluster nodes can
acquire and fire the same trigger simultaneously.
* Add *warn-on-reflection* to custom_migrations/util
Fixes clj-kondo warning triggered by Java interop (System/setProperty,
System/clearProperty) added in the acquireTriggersWithinLock fix.
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Fix incomplete URL substring sanitization in LeafletMap (#70428)
The previous check used `.includes("openstreetmap.org")` which could be
bypassed by malicious domains like `openstreetmap.org.evil.com` or
`fake-openstreetmap.org`.
This fix validates that the hostname is either exactly `openstreetmap.org`
or a legitimate subdomain ending with `.openstreetmap.org`.
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Wrap buttons and title on smaller screens (#67681)
* Wrap title and buttons earlier when nav bar is open
* Wrap title in header at wider breakpoint
* Left align ad-hoc questions too
* Add gap when question title collapses
* Increase breakpoint
* Fix padding on ViewSection
* Use container query for query builder breakpoints
* Make padding more consistent with other headers on small screens
* Tweak question action buttons on small screens
* Add separator for actions
* Fix padding on filter panel
* Fix padding on back button
* Fix padding to match header
* Break sooner
* Do not break subheader as soon
* Fix test
* Remove reliance on query-builder from FilterPanel component
* Remove spurious margin
* Fix gap between header items
* Move container to header and footer
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Add snowplow events when creating measures and segments (#70218)
* Add snowplow events when creating measures
* Track also from the table measures page
* Add tracking events when creating segments
* Fix e2e
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Polish transform template tag frontend (#70095)
* Rename confusingly named setParameterAttribute
* Remove unnecessary check
* Add options to disable parameter settings
* Disable parameters settings in transform sidebar
* Add e2e test for parameter field settings
* Rename disableParamaterSettings to parametersAreUserVisible
* Make parametersAreUserVisible configurable all the way up to QueryEditor
* Update copy when parameters aren't visible to user
* Fix test
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Make excluded-datetime return integers for days too (#69915)
* Make excluded-datetime return integers for days too
Closes QUE2-254
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
Implement auto-generated props tables for modular embedding (#69407)
* Add TypeDoc-friendly interfaces for EAJS web component documentation
* Add TypeDoc config for EAJS web component docs generation
* Generate EAJS web component props tables via TypeDoc
* Replace manual parameter lists with auto-generated props tables
* Fixed file references in components.md and enforced types in embed.ts
* .
* .
* .
* added detail on a prop and uncommited *.md files
* added info about attributes needing to be stringified
* .
Co-authored-by: Sébastien <sebastien@metabase.com>
docs: a lot of updates (#70176)
* oops
* links
* more links
* Update docs/configuring-metabase/appearance.md
* Apply suggestions from code review
* Apply suggestions from code review
---------
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Missing space + log4j capitalization (#70271)
* Missing space + log4j capitalization
* Don't make changes in autogenerated MD files
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Add snowplow events when creating a metric (#69990)
* Add snowplow events when creating a metric
* Fix tests in data-studio-metrics.cy.spec.ts
* Fix prettier
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
* Diagnostics cleanup pulled from the metrics branch (#69926)
* fix test
---------
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
[deps] Ignore "soft" refs (in `:fields` clauses) in deps analysis (#69198)
Fixes QUE-3044.
The QP will ignore refs in `:fields` clauses which cannot be resolved, since they're output only and not critical to the meaning of the query. This change makes the deps analysis treat these "soft" refs the same way - they are not considered to break the queries.
I added some commented tests that are now captured as part of QUE-3081 rather than part of this PR.
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Docs: Tenant attributes and collections improvements (#70179)
* Tenant attributes and collections improvements
First round of edits to add the ability to create tenant attributes using SSO.
* Revise tenant-specific access for non-admin internal users
* Edits based on Alberto's comments
* Move tenant claims info to claims section, link to it from attributes
* Apply suggestion from @alexyarosh
* Moved tenant attribute logic and simplified sentence
* Fix a sentence, improve code example, and clean up permissions bullet points
---------
Co-authored-by: Robert Kosara <rkosara@me.com>
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Add snowplow event for opening Data Studio (#69880)
* Add snowplow event for when opening Data Studio
* Update triggered_from
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Migrate away from deprecated Cypress.env() API (#70189)
As of Cypress 15.10.0, `Cypress.env()` is deprecated. This commit migrates
all usages to the new recommended APIs:
- Non-sensitive config values → `Cypress.expose()` (synchronous)
- Sensitive token values → `cy.env()` (asynchronous)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add position field to dashboard parameters for stable serialization (#70107)
* revert sorting by id on parameters serialization, parameters ordering is significant and must be preserved
* revert, we're storing position
* feat: add :position to parameters, backfill
* feat: backfill position on imported parameters
* chore: tests
* FE: update position
* chore: gitignore python-sources.lock
* chore: ensure we get position
* restrict to dashboard params
* tests
* simpler approach: just sort by position on serialization export/import
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Fix bigquery routing test (#70154)
- Was using wrong project / creds
- Using two different sha names only worked when shas were not used as
qualifiers in the query (they are for bigquery)
Added the ability to override the hash-key used for tx/hash-dataset to
support forcing a hash collision (as is required by routing).
Co-authored-by: Dan Stone <wotbrew@gmail.com>
feat: error code on streaming response throw/fail (#62351)
* fix: real error codes in streaming responses
* fixup! try faking old errors deeper in the stack
* fixup! wrap fetch endpoint in embedding too
* fixup! treat string only errors differently
* fixup! handle errors in a couple other places
* fixup! hard to figure out what kind of error it is
* fixup! typecasts
* fixup! test arity
* fixup! remove blanket 403 page from dataset
* fixup! simplify backend 403 responses
* fixup! a couple missed tests
* fixup! add mockresponse for mockclient
* fixup! other failing tests
* fixup! last failing test
* fixup! add another OSS check
* fixup! one more oss test
* fixup! update status codes on some more tests
* fixup! use committed function
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
[Metabot] Prevent OSS SQL gen UI from showing in cloud migrated instances (#69649)
prevent oss sql gen ui from showing for customsers with had set it up locally and migrated to cloud
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
Ring middleware for public sharing endpoints (#70153)
* Ring middleware for public sharing endpoints
* Refactor test
* move +public-sharing-enabled to address module lint
* Fix documents test
Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
* Filter transforms based on permissions GHY-3152 (#70125)
Filter transforms based on permissions
We were leaking transforms in the :bad_transforms key
* Use underscore for old route.
---------
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
Update v59 sample Examples visualizations and dashboard. (#70075)
Adds Box Plot viz and a Scalar viz with conditional colors to the Example dashboard.
The resources/sample-content.edn was regenerated from the live instance content.
Co-authored-by: Katya Voropaieva <110612633+KorowkaMu@users.noreply.github.com>
Metakey helper (#68987)
* Use H.metaKey where applicable
* Add helper for meta key options
* Fix import
* Update more instances
* Fix test
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Always run Metabot-triggered refingerprinting in admin context to match sync behavior (#70087)
* always run fingerprinting in admin perms context
* address comment
Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
Only switch to full-width native preview at small breakpoint (#70048)
* Only switch to full-width native preview at small breakpoint
* Add e2e test for metabase#67767
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
re-generate lock file to remove stale deps (#70062)
* re-generate lock file to remove stale deps
* add sample apps to the deps for the package
Co-authored-by: Nicolò Pretto <info@npretto.com>
emb-1300: use plugin for handleLink in eajs and fix double sdk plugin init (#69961)
* emb-1300: use plugin for handleLink in eajs and fix double sdk plugin init
* typo and fix unit test
* restore old comment
Co-authored-by: Nicolò Pretto <info@npretto.com>
[QP] Move logging-only work inside the `log/*` call (#68362)
Move some logging-only computations into the `(log/* ...)` call so it won't be executed
unless the log level is sufficiently verbose for the log to actually be output.
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Drop table created in a e2e test (#70023)
* drop table created in a e2e test
* fix
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
Show Python upsell on self hosted (#69759)
* Show Python upsell on self hosted
* Add e2e tests
* Fix unit test
* Simplify TransformsUpsellPage a bit more, fix tests
* Simplify logic
* Fix e2e and unit test
* Update self-hosted python upsell as per new design / Code clean up
* Fix unit test and also add a new one for useTransformsBilling
* Remove e2e tests to be moved to a new PR
* Fix cta link and bullet points icon alignment
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
* fix: better check for dirty collection state (#69974)
Our frontend code that prevents sending unchanged collections missed
tenant collections being added to the payload. This fixes both the
frontend to make sure we don't send when there are no changed
collections and it updates the backend actually check if collections are
being changed rather than just checking if the collections map exists.
* Update RemoteSyncSettingsForm.unit.spec.tsx
---------
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
fix: transforms collections set setting on import (#69852)
* fix: transforms collections set setting on import
Also turns off the transforms sync setting if there are not transform
related models in the import
* fix: transform/snippet settings on collection sync
Updates our check for 'did transforms or snippets change on remote' to
examine collections in the respective namespaces so an import with only
transform collections (or snippet collection) creates the correct
settings on the importing instance.
* fixup! better handling for custom vs builtin tags
* fixup! better conflict checking of namespaced cols
* fixup! explicit connectionb for token cache
* fixup! PR feedback
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
feat(dashboard): move subscriptions to action menu (#64950)
* feat(dashboard): move subscriptions to action menu
* fix unit tests
* fix e2e tests
* fix console warning about uncontrolled component
* fix more tests
* fix remaining test
* bring test back
Co-authored-by: Uladzimir Havenchyk <125459446+uladzimirdev@users.noreply.github.com>
Transforms with params UI (#69728)
* Validate transform queries can be preprocessed
* remove prn
* update backend error messages
* Add support for custom toggleTemplateTagEditor
* Allow passing setTemplateTagConfig to TagEditorParam
* Add support for storing parameter values when question changes
* Add template-tags tab
* Add template tag sidebar
* Allow saving optional template tags or tags with a default value
* Show error message on save
* Add new spec for transform template tags
* Avoid sharing state when navigating
* Add combination test for template tag types in transforms
* Add definitionTab helper
* Add test for multiple template tags
* Fix error message
* Fix tooltips in test
* Remove tooltip check in tests
* Use getErrorMessage to get error message in toast
* Only return message if it is not empty
* Wrap error message in form
* Use H.createTestNativeQuery helper
* Move variableTemplateTags and isVariableTemplateTag to Lib
* Use more conventional key to reset uistate
* update backend error messages again
* Revert "Wrap error message in form"
This is now handled in the api
This reverts commit 9efecaf261.
* Fix test
---------
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: William Zimrin <william@metabase.com>
Use `core.setFailed` instead of throw for missing artifacts (#69897)
When an artifact doesn't exist (expected for new commits), the
fetch-artifact action was using throw new Error() which causes
GitHub Actions to report "Unhandled error" - confusing and noisy.
Using core.setFailed() cleanly marks the step as failed without
the scary error message.
Fixes: DEV-1581
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add debug echo to driver-decisions CI step (#69881)
Prints the mage command and args before execution so we can quickly
see what labels/flags were passed when debugging CI driver issues.
Closes: DEV-1577
Co-authored-by: bryan <bryan.maass@gmail.com>
docs: Fix step numbering + add details on how to confirm if using H2 (#69581)
* Fix step numbering + add details on how to confirm if using H2
* fix anchor links
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Remove unused HTTP action code paths (#69764)
* Remove dead code for actions
* Disable HTTP action type at API level
* clarify thrown exceptions
* Remove HTTP action tests
HTTP actions are now blocked at the API level; these tests cover
functionality that's no longer accessible.
* Remove remaining HTTP action references from api_test
The previous commit missed several HTTP action usages:
- all-actions-default helper function
- list-actions-test action-1 binding
- action-parameters-test (now uses query action)
Co-authored-by: bryan <bryan.maass@gmail.com>
Transforms with parameters (#69592)
We want to support transforms with template tags, as long as those tags aren't required or have default values. However, if we do that, the backend should actually verify that we do in fact have values for all relevant template tags. This pr adds basic validation logic to transform creation and update routes -- essentially, we just run qp.preprocess/preprocess and see if we get an error.
Co-authored-by: William <william@metabase.com>
Fix narrow symbol downloads with tests (#69811)
* Fix downloading currency values in narrowSymbol format (#69779)
* Add tests for narrowSymbol currency style in downloads
---------
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Will Bryant <will.bryant@gmail.com>
Move transform metering back into EE module (#69840)
* Move transform metering back into EE module
The defenterprise shadowing was not working as the metering function was
moved
* Add test of EE stats
Co-authored-by: Dan Stone <wotbrew@gmail.com>
Problem: When a database is configured for both SQL access and Transforms, any feature with SQL access (like raw SQL questions) inherits the elevated permissions (CREATE, DROP, INSERT, etc.) that Transforms need.
Solution: Admins can _optionally_ configure write credentials alongside existing read credentials. One logical database, two connection types. Specific code paths opt in to using write credentials; by default everything uses a read-only connection.
How: This PR adds a new `write_data_details` column on `Database`. If `write_data_details` isn't configured, everything will still use `details` as before. When it is configured, it acts as a set of overrides on top of `details`, but only in code paths that require write permissions. There should be no behavioral change for existing deployments.
Explain how DB routing and query caching work together (#69855)
* Explain how DB routing and query caching work together
* Update docs/configuring-metabase/caching.md
---------
Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Fix unreferenced dependency flakes (#69535)
* Scroll item into view
* Fix sidebar test
* Wait for page to be visible
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Dashboard category filter not correctly populated when using multiple datasources in one graph (#69318)
* Add repro e2e test
* Dashboard filter values when connected to card with multiple datasets
* Fix kondo
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
Merge remaining match -> match-many rewrites (#69686)
* [match] Implement match-many as a replacement for match
* [match] Add proper docs to match-lite and match-many
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
fix: cancelling remote sync tasks dismisses modal (#67613)
* fix: cancelling remote sync tasks dismisses modal
Previously we didn't close this modal until the task reached a
'cancelled' state which could take several seconds.
* fixup! PR feedback
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
split large data model shared spec cypress file (#69744)
* split large data model shared spec cypress file
* split 2nd group further, rename files
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
fix: allow uploads when schema is unrestricted (#69657)
* fix: allow uploads when schema is unrestricted
* fixup! add upload enabled flag
* Update impl.clj
* fixup! where upload flag is set
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Map Snowflake big integers to :type/BigInteger (#67609)
* Map Snowflake big integers to :type/BigInteger (fix#63600)
* Test fixes 🔧
* Test fixes 🔧
* Test fix 🔧
* More test fixes 🔧
* Another round of test fixes 🔧
* (Hopefully) final test fix 🔧
* Code cleanup
* Revert changes that broke Clickhouse test
* Test fix 🔧
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
Fix missing availableHeight on model native editor (#69723)
* Fix missing availableHeight on model native editor
* Add repro for metabase#69722
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Fix more measure unit tests (#69596)
* Rewrite test to use Lib.createTestQuery
* Force OpaqueDatasetQuery to be used
* Break cyclic imports
# Conflicts:
# frontend/src/metabase/querying/expressions/test/shared.ts
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
record group membership removals in activity log (#69316)
* record group membership removals in activity log
Previously the `PUT /api/membership/:group-id/clear` and
`DELETE /api/membership/:id` endpoints did not emit group membership
deletion events.
In the long run it would be better if `t2` were the interface for
PermissionsGroupMembership, so users didn't need to call these "blessed"
functions. But for now, let's go along with the existing pattern here,
have some blessed functions for doing things, and throw exceptions if
someone does a direct `t2/delete!` on a `:model/PermissionsGroupMembership`.
* use macro for more obvious workaround
Co-authored-by: John Swanson <john.swanson@metabase.com>
Add tracking events for when Dependency Graph is opened for an entity (#69604)
* Add events for transform run tags and dependency diagnostics row selection
* Fix e2e test
* Adjust event as per review / Fix e2e tests
* Add tracking events for when Dependency Graph is opened for an entity
* Add remaining e2e tests
* Update simple_event/jsonschema/1-0-0
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
[match] Implement match-many as a replacement for match (#68659)
[match-lite] Add support for &match anaphor and better nil handling
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
Add tracking events for transform run tags update and dependency diagnostics row selection (#69531)
* Add events for transform run tags and dependency diagnostics row selection
* Fix e2e test
* Adjust event as per review / Fix e2e tests
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Prevent editing snippets from question editor when remote sync is read-only (#69147)
* Prevent snippets to be edited from question editor when remote sync is read-only
* Fix test
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Audit DB should exclude databasechangeloglock (#69487)
auditdb should exclude databasechangeloglock as well
Co-authored-by: Nathan Voxland <nathan@metabase.com>
Fix ci-test-config driver quarantine name translation (#69615)
The ci-test-config.json uses driver directory names (e.g., "bigquery-cloud-sdk")
but the mage code uses internal driver keywords (e.g., :bigquery). This mismatch
meant quarantined drivers like bigquery were not being recognized.
Now uses the existing driver-directory->drivers mapping to translate config names
to internal keywords, with fallback to direct keyword conversion for names that
match (like "databricks").
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Native query test helper (#69402)
* Add schema for test-native-query-spec
* Implement test-native-query helper
* Add js wrapper for test-native-query
* Add ts wrapper for test-native-query
* Make common parts optional
* Fix types
* Fix temporal-unit test spec
* Handle snippet tags
* Fix temporal-unit tags
* Fix card tag spec
* Simplify schema
* Add unit tests for createNativeQuery
* Add tests for test-native-query
* Add missing options
* Fix types
* Actually resolve field ref
* Code style
* Add native-query api endpoint
* Add h.createTestNativeQuery helper
* Add test for required, widget-type and default options
* Move parsing into test-spec module as it is part of the implementation
* Add example e2e test use of H.createTestNativeQuery
* Use coercer instead of decoder to validate spec too
* Fix lint
* Move adjust to update-vals
* Match threading style
* Add test for optional template tagsfg
---------
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: Braden Shepherdson <braden@metabase.com>
When instance is not on trial, still allow them to start Transforms trial if available (#69499)
* show both transforms tiers even when on trial
* Show upgrade modal in place when clicking Upgrade to Pro
* Improve comments
* Show upsell transforms trial variant when available for instance not on trial
* Fix ts
* Say 'Start trial' when trial is available
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Move test helper parser to lib (#69405)
* Use correct type for order-bys
* Move parser for test-query-spec into implementation
* Be more strict in test
* Convert another e2e test to prove the parsing works
* Make args optional in test-query-spec
* Use threading instead of partial
---------
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: Braden Shepherdson <braden@metabase.com>
Don't attempt to add revisions for viewing docs (#69305)
Luckily a bug saved us from *actually* creating revisions here (the
`before-update` hook doesn't get an actual instance in this case). But
... we shouldn't be attempting it.
Co-authored-by: John Swanson <john.swanson@metabase.com>
Do not allow publishing tables without query perms (#69171)
* Do not allow publishing tables without query perms
Publishing a table changes query permissions. So you shouldn't be able
to publish a table that you don't have query permissions on, and then be
able to query it.
* fns for `can-publish?`, `can-publish-all-table?`
* switch to `library` ff
Co-authored-by: John Swanson <john.swanson@metabase.com>
Correct function for fetching field values in Metabot tools (#69589)
* switch function for metabot fetching field values
* refactor tests
* fix lint
* fix tests - keep existing behavior of auto-creating field values if needed
Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
Move app switcher into Dependency Graph (#69128)
* move app switcher into Dependency Graph
* adjusting unit test
* remove z-index nonsense
* moving the app switcher up to DependencyGraphPage, small change to SelectItem
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Fix 'Upgrade to Pro' button to open upgrade modal / Show two transforms tier options when on trial (#69387)
* show both transforms tiers even when on trial
* Show upgrade modal in place when clicking Upgrade to Pro
* Improve comments
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Update Jest snapshot headers for Jest v30 compatibility (#69564)
Jest v30 validates that snapshot files have the current documentation URL.
Updated the header from the old shortened URL to the new official URL.
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
GDGT-1776 Query Builder transform fails at join stage (#69552)
* Fix virtualized list items rendering
* Add a repro for GDGT-1776
* Fix GDGT-1776
* Remove isHidden prop from MiniPickerItem and instead just do not render items that should be hidden
* Clean up
* Fix var access
Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
Fix the release-log workflow (#69547)
Use prepare-release-scripts action in release-log workflow
Simplify the workflow by using the shared action instead of
manually setting up bun and building release scripts.
This works because the workflow always checks out master,
so the action from master (which uses bun) is always used.
Fixes: DEV-1544
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Fix broken measure unit tests (#69515)
* Allow passing measures to entities schema
* Fix measures test
* Use toJsQuery
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Update Upsell to match design (#69488)
* Update Upsell to match design
* Remove loader for trial message
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
Show confirmation popup when overwriting data during remote sync setup (#68525)
* Report conflicts on transforms/snippets/lib
[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)
* fixup! store conflicts in remote-sync-task table
* fixup! make conflict checking spec driven
* Restore initial implementation (implement conflict modal when pulling for the first time)
* Fix modal not opening when in data studio
* Don't set version in task when it fails with conflict / Adjust conflict options / Start e2e tests
* Add e2e tests
* Add some unit tests
* Fix remote sync settings update when creating new branch
* Isolate git config for initial import conflict test cases
* Report conflicts on transforms/snippets/lib
[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)
* fixup! store conflicts in remote-sync-task table
* fixup! make conflict checking spec driven
* fixup! tests failures
* fixup! lints
* fixup! exclude tags from conflict
* Fix unintended changes from merge in RemoteSyncSettingsForm.tsx
* Address PR comments
---------
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Co-authored-by: John Swanson <john.swanson@metabase.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
Add entity id and entity type to the dependency calculation error (#69001)
* Initial commit
* Fix tests
* Fix events test
Co-authored-by: da <paoliniluis@gmail.com>
Implement DB-level caching of premium features (#69241)
Premium feature token checks are cached per-instance in memory with a 12h TTL. During rolling deploys after a plan upgrade, different instances can disagree about which features are available:
1. Request hits instance A (old cache) → reports old features
2. Request hits instance B (freshly started, no cache) → reports new features
3. Frontend says "upgrade successful!"
4. Request hits instance A again → old features are back
This flapping means the frontend can't reliably detect when an upgrade has landed.
## Solution
### DB-hash-aware cross-instance cache
Replace the per-instance in-memory TTL cache with a two-layer caching scheme coordinated through the DB:
- A **local in-memory cache** holds the full token status (features, validity, etc.)
- A **DB table** (`premium_features_token_cache`) stores only a SHA-256 hash of the token status, keyed by a hash of the token itself. The DB never stores actual features — just enough to coordinate freshness across instances.
When a token check comes in:
- If the local cache matches the DB hash and is < 12h old: serve it immediately
- If it matches the DB hash and is < 36h old: serve the stale data and refresh asynchronously in the background
- If the DB hash doesn't match (another instance refreshed), or the cache is > 36h old, or this is a cold start: synchronous MetaStore fetch
This ensures all instances converge quickly after a plan change while keeping MetaStore traffic low. Cold-starting instances always hit the MetaStore — there's no way to bootstrap features from the DB alone, since it only stores hashes.
### Checker stack (inner to outer)
1. **`store-and-airgap-token-checker`** — hits MetaStore or validates airgap token
2. **`circuit-breaker-token-checker`** — circuit breaking + timeout
3. **`db-hash-aware-token-checker`** — the core caching layer (described above)
4. **`local-cached-token-checker`** — 5s TTL memoization to avoid hitting the DB on every request
5. **`error-catching-token-checker`** — wraps exceptions into `{:valid false}` responses
The 5s local cache means we hit the DB at most once every 5s, even during the grace period.
### Force-refresh endpoint
`POST /api/premium-features/token/refresh` clears all caches and synchronously re-checks against the MetaStore. The frontend uses this when polling for new features after a purchase (`useTokenRefreshUntil` in `UpgradeModalLoading`, `MetabotSettingUpModal`, `TransformsSettingUpModal`). A cookie-based mechanism propagates the invalidation to other instances so they clear their local caches on the next request.
Co-authored-by: John Swanson <john.swanson@metabase.com>
fix: Snyk workflow using wrong working directory for release/yarn.lock (#69510)
The previous fix ran `cd release && bun install --yarn` which changed the
working directory for subsequent commands. The sed command then tried to
access `release/yarn.lock` from within the `release/` directory, resulting
in "sed: can't read release/yarn.lock: No such file or directory".
Split into separate steps with explicit working-directory for clarity.
The sed commands now continue on error to let Snyk report parsing issues
directly rather than failing on the workaround.
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
feat: add a stable sort for card parameters serdes (#69478)
Sorts parameters by their uuid to ensure that we maintain an order for
parameters across exports no matter the order they are serialized to the
database in.
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
fix: Snyk scan failing after bun migration (#69498)
Root Cause:
Bun's `bun install --yarn` command has a bug where it normalizes version
ranges inconsistently in the generated yarn.lock:
- Alias entries normalize ranges: "safer-buffer@>= 2.1.2 < 3"
(converts "< 3.0.0" to "< 3")
- Dependency specs keep original: safer-buffer ">= 2.1.2 < 3.0.0"
(preserves the ".0.0")
Snyk performs exact string matching when resolving dependencies to their
lock file entries. When it sees `safer-buffer@>= 2.1.2 < 3.0.0` as a
dependency, it looks for that exact string in the alias list, but only
finds `safer-buffer@>= 2.1.2 < 3`, causing the error:
"Dependency safer-buffer@>= 2.1.2 < 3.0.0 was not found in yarn.lock"
Solution:
Add a post-processing sed command that normalizes version ranges in the
dependency specifications to match the aliases. This transforms:
- "< 3.0.0" → "< 3"
- "< 3.0" → "< 3"
This ensures Snyk can match dependencies to their resolutions.
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Remove `@peculiar/webcrypto` polyfill from ClojureScript tests (#69475)
This completes the removal of `@peculiar/webcrypto` from the codebase,
following the Jest setup cleanup in #69466.
Changes:
- Update `polyfills.cljc` to use Node's native `crypto.webcrypto`
- Remove `@peculiar/webcrypto` from package.json
The previous comment about needing Node v23+ was outdated:
- `crypto.webcrypto` available since Node 15
- `globalThis.crypto` available since Node 19
- Node 22 (current LTS) fully supports it
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Remove `@peculiar/webcrypto` polyfill from the Jest setup (#69466)
* Use native NodeJS cryppolyfill in fe unit tests
* Force jose library to use Node.js runtime in Jest tests
The jose library's browser runtime expects CryptoKey to be globally
available, which jsdom doesn't provide. This caused tests using JWT
signing (via jose) to fail with "CryptoKey is not defined" after
switching from @peculiar/webcrypto to Node's native webcrypto.
By mapping jose to its Node.js runtime via moduleNameMapper, we avoid
the CryptoKey dependency since the Node runtime uses require('crypto')
directly.
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Unify table visibility with can-query semantics (#69199)
* Unify table visibility with can-query semantics
Table visibility checks had drifted across different APIs.
- `(can-query? table)` checked whether you had view access
and create-queries access OR the table was published. This is incorrect:
the table is queryable if you have view access AND either the table is
published OR you have create-queries.
- the collections API included tables that were not queryable.
- the search API allowed you to view tables if a) you had data
permissions on the table, AND b) the table was unpublished or published
in a collection you had access to. This is incorrect, since publishing a
table shouldn't hide a previously visible table from search results.
Search should return tables for which you have view-data permissions
PLUS the table is either published or you have create-queries
permissions.
Fundamentally this change:
- correctly defines what `(can-query? table)` means, and
- uses that new definition of `can-query` to determine table visibility
across the collection, search, and table APIs.
Note that I did not change some existing usages of
`(mi/visible-filter-clause :model/Table ...)`, which will continue to
exclude tables for which the user does not have explicit data
permissions set (but could otherwise query due to being published). That
should be a simple followup PR.
- align SQL table visibility with mi/can-query? semantics for search paths
- add enterprise `published-table-visible-clause` and wire optional
- `published-via-collection` support into `(mi/visible-filter-clause :model/Table ...)`
- update search table fallback permission check to use canonical `mi/can-query?`
- fix collection table children filtering to include `published-via-collection` queryability
- make `(mi/can-query? :model/Table)` return explicit booleans
- add/adjust EE tests for:
- published-table SQL clause behavior
- collection items visibility under view/query perms
- search visibility when user lacks query perms
- search visibility for unpublished tables when user has data perms
- stabilize appdb negation test by avoiding brittle exact count for "customer" in shared index data
* don't use `published-tables` directly
and fix kondo config
* correct feature for library
* kondo
* ensure we bind `*current-user-id*` in search
fallbacks rely on functions that use dynamic vars to check permissions.
Search is designed to use only the search context (with its
`current-user-id` and `current-user-perms`) and binds those dynamic vars
accordingly.
Previously we just needed to bind `current-user-permissions-set` but now
we should also bind `current-user-id` as well.
* fix tests
* correct feature for library
Co-authored-by: John Swanson <john.swanson@metabase.com>
metabase.lib.convert/->legacy-MBQL{:message"Conversion to legacy MBQL is discouraged, please use Lib to manipulate MBQL queries"}
metabase.lib.core/->legacy-MBQL{:message"Conversion to legacy MBQL is discouraged, please use Lib to manipulate MBQL queries"}
metabase.lib.equality/find-column-indexes-for-refs{:message"Use lib.equality/closest-matches-in-metadata or lib.equality/find-closest-matches-for-refs instead of lib.equality/find-column-indexes-for-refs"}
metabase.lib.util.match/match{:message"Use lib.util.match/match-many instead of lib.util.match/match."}
metabase.lib.util.match/match-one{:message"Use lib.util.match/match-lite instead of lib.util.match/match-one."}
metabase.lib.util.match/replace{:message"Use lib.util.match/replace-lite instead of lib.util.match/replace."}
metabase-enterprise.transforms.interface/execute!{:message"Use metabase-enterprise.transforms.execute/execute! instead of metabase-enterprise.transforms.interface/execute!"}
next.jdbc/active-tx?{:message"Use metabase.app-db.core/in-transaction? to see if we are in a transaction"}
toucan2.core/debug{:message"Don't commit code using t2/debug"}
-**UI**: `metabase/ui` components built with Mantine v8
-**Build**: Rspack (primary), Webpack (legacy)
- **Testing**: Jest + React Testing Library, Cypress
-Check for hardcoded secrets, API keys, or credentials
-Look for SQL injection and XSS vulnerabilities
-Verify proper input validation and sanitization
-Review authentication and authorization logic
-Ensure enterprise features use the plugin system (no enterprise code in OSS)
### Coding Standards
### Performance Red Flags
#### Component Preferences
- Identify N+1 database query problems
- Spot inefficient loops and algorithmic issues
- Check for memory leaks and resource cleanup
- Review caching opportunities for expensive operations
- Prefer `metabase/ui`components over `metabase/common/components`
- Use `.tsx` for components, `.ts` for utilities
### Code Quality Essentials
#### Styling
- Functions should be focused and appropriately sized
- Use clear, descriptive naming conventions
- Ensure proper error handling throughout
- Remove dead code and unused imports
ALWAYS prefer Mantine style props,then CSS modules. DO NOT suggest styled components, they are deprecated.
### Review Style
#### TypeScript Migration
- Only flag actual issues worth mentioning
- Do not post "looks good" comments or congratulate following conventions
- Be specific and actionable in feedback
- Explain the "why" behind recommendations
- Ask clarifying questions when code intent is unclear
When heavily editing `.js`/`.jsx` files, create a separate PR to convert to TypeScript first, then implement changes.
### Review Format
#### Enterprise Features
- Condense feedback into as few comments as possible
- Prefer a single summary comment over dozens of inline comments
- Only use inline comments for critical issues that require immediate attention
- For non-critical issues, link to the specific line from the summary instead
- Delete all stale comments and summaries on each new push or CI run
Enterprise functionality MUST use the plugin system. It is very important to not expose enterprise code in the OSS version.
#### Testing Requirements
All PRs should include tests. Prefer Unit tests over E2E tests.
#### Localization
All user-facing strings MUST be localized using the ttag library. Localized strings should be complete phrases, do not concatenate a few separately localized strings. You should add context to strings where the meaning of the string might not be obvious in isolation: e.g. "Home" might have different words in some languages depending on whether you're talking about a dwelling or the landing page for a website.
Language-specific rules are in `.github/instructions/*.instructions.md`.
--allowedTools "Bash(bun run test-unit*),Bash(bun run lint-eslint-pure),Bash(./bin/mage*),Bash(clojure*),Bash(find*),Bash(ls*),Bash(grep*),Write,Read,Glob,Grep,Edit,MultiEdit"
allowed_tools:"Read,Edit,Write,Bash(git:*),Bash(grep:*),Bash(find:*),Bash(ls:*),Bash(cat:*),Bash(clojure:*),Bash(${{ steps.pkg.outputs.mgr }} run type-check-pure:*),Bash(${{ steps.pkg.outputs.mgr }} run lint-eslint:*),Bash(./bin/mage cljfmt:*),Glob,Grep"
prompt:|
You are resolving git cherry-pick merge conflicts for a Metabase backport PR.
## Context
A commit from the `master` branch is being cherry-picked onto the `${{ steps.pr.outputs.base_ref }}` release branch.
The cherry-pick has failed with conflicts in these files:
${{ steps.backport.outputs.conflicted_files }}
## How to read conflict markers
```
<<<<<<< HEAD
(code from the release branch - the current state)
=======
(code from master - the change being backported)
>>>>>>> <commit-sha>
```
## Common conflict patterns in Metabase backports
- **Module/namespace renames**: A Clojure namespace was renamed or moved between versions. Check what the correct namespace is on the release branch.
- **Test file divergence**: Tests may have been added or reordered differently. Keep the backported test changes while preserving existing release-branch tests.
- **Import path changes**: Frontend imports may reference different paths. Check actual file locations on this branch.
- **Translation files (.po)**: For translation conflicts, prefer the release branch version of existing translations and add new translations from the backported change.
- **Minor context differences**: Surrounding code changed slightly. Adapt the backported change to fit the release branch context.
## Instructions
1. Read each conflicted file to understand the conflict
2. For context, you may search the codebase to understand the current state of the release branch (e.g., check if a module exists at a certain path)
3. Resolve each conflict by editing the file to remove ALL conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) and leave only the correct resolved code
4. The goal is to apply the INTENT of the backported change while adapting it to the release branch's code structure
5. Verify no conflict markers remain by searching for them
6. Auto-format resolved files:
- **Clojure/ClojureScript** (.clj, .cljc, .cljs): run cljfmt to fix formatting:
```
./bin/mage cljfmt-files <file1> <file2> ...
```
- **TypeScript/JavaScript** (.ts, .tsx, .js, .jsx): run eslint with auto-fix:
```
${{ steps.pkg.outputs.mgr }} run lint-eslint --fix
```
7. Validate resolved files before committing:
- **Clojure/ClojureScript** (.clj, .cljc, .cljs): run clj-kondo to verify syntax:
```
clojure -M:kondo --lint <file1> <file2> ...
```
- **TypeScript/JavaScript** (.ts, .tsx, .js, .jsx): run the type checker:
```
${{ steps.pkg.outputs.mgr }} run type-check-pure
```
If either tool reports errors or warnings, fix them before proceeding. CI treats kondo warnings as errors.
Repeat steps 6-7 until all errors are resolved.
7. Once all files are clean, stage and complete the cherry-pick:
```
git add -A
git cherry-pick --continue
```
8. Push the result:
```
git push --force
```
IMPORTANT: Do not skip any conflicted files. Every conflict marker must be resolved.
- name:Check for max turns exceeded
if:always() && steps.claude.outcome != 'skipped'
id:check-failure
run:|
if [ -f "${{ steps.claude.outputs.execution_file }}" ]; then
'🤖 Auto-resolution of backport conflicts stopped because Claude reached the maximum number of turns (${{ github.event.inputs.max_turns || '75' }}).',
'',
'The conflicts may be too complex for automatic resolution, or Claude needed more turns to finish.',
'',
'You can try again with more turns by manually running the [resolve-backport-conflicts workflow](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/actions/workflows/resolve-backport-conflicts.yml) with a higher `max_turns` value, or resolve the conflicts manually by checking out the branch and running `./backport.sh`.',
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.