3426 Commits

Author SHA1 Message Date
Fraser
afa79587c2 Lint without building cljs (#83718) 2026-10-07 16:06:33 +13:00
Jeff Bruemmer
b9b5c25e7a docs - transform indexes (#83598) 2026-10-06 20:26:52 +00:00
Jeff Bruemmer
012e199084 docs - mcp tool documentation gen (#82592) 2026-10-06 12:58:25 -04:00
Sébastien
db875cbd2a Add a Refresh button to the embedded question when automatic reruns are off (#83732) 2026-10-06 16:54:33 +02:00
github-automation-metabase
66c6739fdd Auto-update documentation for master (#83697)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-10-06 10:48:35 -04:00
Jeff Bruemmer
12f8e514d4 docs - 432 note on remote sync (#83667) 2026-10-06 13:21:59 +00:00
Andrei Simionescu
83f20bc0b5 Add Claude Opus 5.5 and Sonnet 5.5 to Metabot (#83647) 2026-10-06 14:00:04 +01:00
Paolo Rascunà
457b3c3fa5 Offer DeepSeek Flash under its documented deepseek-flash id (#83397)
Offer DeepSeek Flash under its documented deepseek-flash id

DeepSeek now documents Flash as deepseek-flash, and its /models catalog no
longer lists deepseek-v4-flash. Flash had disappeared from the model picker.

- Offer deepseek-flash ("DeepSeek Flash") in the DeepSeek whitelist and make
  it the DeepSeek mini model.
- Declare deepseek-v4-flash as a retired model of the DeepSeek provider type,
  with the :retired-models mechanism from #83522. A saved
  deepseek/deepseek-v4-flash shows as DeepSeek Flash, and requests use
  deepseek-flash.
- Add DeepSeek to the self-test whitelist check, update the DeepSeek tests,
  and regenerate docs/ai/providers.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 14:33:07 +02:00
Fraser
48b9e66904 Use oxlint (#82015) 2026-10-05 22:41:31 +13:00
Andrei Simionescu
d7c6ddb54b Support Bedrock inference profiles and unlisted Claude models (#83433) 2026-10-02 23:45:41 +00:00
Andrei Simionescu
18b6929ad7 Add xAI (Grok) as a Metabot provider (#83431)
* Add xAI (Grok) as a Metabot provider

* Scroll the provider buttons into view in the setup e2e test

* Turn off reasoning on Grok 4.3 for structured output

* Report reasoning support for Grok 4.3

* Add xAI to the shared LLM test connections
2026-10-02 22:40:30 +00:00
github-automation-metabase
4e6f460e9d Auto-update documentation for master (#83603)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-10-02 21:27:49 +00:00
Alex Yarosh
7efe272763 docs: data studio redesign - draft (#83392) 2026-10-02 16:59:42 +00:00
Voytek Pituła
d443b6bd42 [BOT-2148] Keep Qwen3.8 Max's OpenRouter handling under its dated id (#83522)
* Keep Qwen3.8 Max's OpenRouter handling under its dated id

OpenRouter now lists only `qwen/qwen3.8-max-0902`. Key the catalog entry on
the dated id and alias the undated one to it, so settings saved with
`qwen/qwen3.8-max` keep the tool_choice downgrade, mandatory reasoning,
forced-call token floor and context window.

* move to Paolos approach

* remaining comments
2026-10-02 16:50:00 +00:00
metamben
3200343d92 Add MSAL4J dependency for SQL Server (#82511)
* Support managed identity and other AD auth methods for SQL Server

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-10-01 23:59:50 +00:00
github-automation-metabase
7953e39c55 Auto-update documentation for master (#83462)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-10-01 17:22:15 -04:00
Jeff Bruemmer
8fa7cbfbf4 docs - remove workspaces (#83457)
remove workspaces
2026-10-01 13:49:45 -07:00
metamben
36348665e6 Snowflake workload identity federation (#82931)
Add Workload Identity Federation support for Snowflake
2026-10-01 17:33:44 +03:00
github-automation-metabase
5d116801cc Auto-update documentation for master (#83377)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-10-01 13:17:46 +00:00
John Swanson
d60c8f2e3b UXW-5198: Improved data analysts grace period (#81969)
* EMB-2341 Don't honor features from an invalid token status

The store's 403 for an expired token still includes the full feature
list in its body, and since the token-grace-period refactor (#64938)
we never checked :valid — we just keyed off the features present. So
an expired token kept all premium features active (e.g. embed
branding stayed hidden).

The design principle: store faithfully what the store returned, and
enforce :valid at the point of access. Provenance is structural, not
data — the fetch layer either returns an authoritative answer (any
response with a parseable body, including a definitive 4xx rejection)
or throws for anything transient, so whatever reaches the caches is
holdable by construction.

- *token-features* returns #{} unless the stored status is :valid
- canonically-has-feature? answers a definitive false for a
  canonical-but-invalid token
- a 4xx with no body now throws (like 5xx) instead of returning a
  synthetic non-canonical status: previously one bodyless 4xx from an
  intermediary would be cached fresh and drop features for up to the
  12h soft TTL, defeating the grace period; real 4xx answers (expired,
  does not exist) still replace the cache immediately, as they should

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2yeC4Tzjnk2NWeKxDZYYS

* EMB-2341 Restore legible timeout errors; specify transient-failure behavior

A hung token-check request surfaced as "Cannot throw exception because
the return value of Throwable.getCause() is null": Diehard's
TimeoutExceededException has no cause, so the FailsafeException unwrap
threw nil (an NPE). It still failed safe, but the admin-visible error
was gibberish. Catch the timeout explicitly and restore the pre-64938
"Token validation timed out." message; guard the generic unwrap against
other causeless FailsafeExceptions while we're at it.

Test coverage for previously unspecified behavior, all transient
(thrown, never cached, grace period preserved) except the last:

- hung request: times out legibly, not cached (replaces the dead
  :timeout stub in token-checker-test that was never exercised)
- unparseable body (a proxy's HTML error page): not cached
- 2xx with no body: not cached
- 2xx with a :valid false verdict: authoritative and cached, same as
  a definitive 4xx

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2yeC4Tzjnk2NWeKxDZYYS

* EMB-2341 Harden the authoritative/transient boundary on token checks

- A response body that is missing, unparseable (e.g. a proxy's HTML error
  page), or not a JSON object is never a verdict: throw a legible error
  instead of relying on schema validation (which is disabled in prod) or
  leaking a raw Jackson parse error.
- A bare 403/404 with no body IS a verdict: the store may reject a token
  without elaboration, so synthesize an authoritative invalid status and
  cache it rather than refetching forever.
- do-refresh! now refuses to cache anything not marked :canonical?,
  enforcing in code the invariant the comments described.
- Setting a token busts the cache first, so re-entering a just-renewed
  token validates against the store instead of a stale expired verdict.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012tetFZMMxsgj7NBQgABraX

* EMB-2341 Negative-cache transient failures; widen breaker window

Move the error boundary inside the local memoize: failure maps now
memoize for local-ttl like any value, so a store outage costs one
network attempt per 5s per instance instead of one per feature check,
and concurrent misses share a single attempt (core.memoize
single-flights values, but not thrown exceptions). Synthetic maps still
never reach the durable db-hash cache, which sits inside the boundary.

Widen the circuit breaker window 60s -> 180s: 10 worst-case failures
(10s timeout + 5s negative cache apiece) span ~135s, so a 60s window
could never accumulate 10 slow failures and the breaker would never
open against a slow-failing store.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012tetFZMMxsgj7NBQgABraX

* Gate Data Analysts membership additions on advanced-permissions

Adding someone to the Data Analysts magic group now requires the
`:advanced-permissions` premium feature.

The check lives at the model layer, on `add-users-to-groups!` -- that
function inserts via raw HoneySQL and so never fires Toucan's
before-insert hook, and direct `t2/insert!` on the model is refused
outright, which makes it the one place every production caller passes
through. That covers the membership API, the `is_data_analyst`
user-update path, invites, LDAP/SSO sync (whose per-add catch already
logs and continues, so logins never break over it) and SCIM (which
surfaces the 402 to the identity provider).

Only additions are gated this way - after downgrade, the group can only shrink.

* Make the SCIM group PUT membership update diff-based

PUT /Groups/:id cleared the group and re-added the whole desired member
list. On a downgraded instance with grandfathered Data Analysts that
made every push fail: a removal-only push, and even an idempotent
resync, re-added members who were already there, tripped the
addition gate, 402'd and rolled back -- so a member could never be
removed via SCIM.

Apply the difference instead: remove (current - desired), add (desired -
current). A removal-only push and a resync now touch no additions and
succeed without the feature, while a push introducing a genuinely new
member still 402s so the drift is visible at the IdP. It also stops
churning membership row ids for members who never changed.

Group PATCH has no membership path -- only /Users/:id -- so PUT and the
POST create path were the only callers.

* Data Analysts group is visible iff advanced-permissions or it has active members

The group's visibility was a straight feature check. This had bad
implications: a user who was still in the group could get permissions
from an "invisible" group that couldn't be seen anywhere in the
permissions graph. We needed to do permissions graph surgery (basically
removing the group in OSS or when downgraded) to prevent this bad state.

Now we don't hide the group unless it's empty. This eliminates the
"hidden permissions" entirely - an empty group doesn't provide any
permissions.

* Render the Data Analysts group removal-only without advanced-permissions

The model-layer gate refuses additions to the Data Analysts group when
advanced-permissions is absent, but the group stays visible while it has
members. Without a matching UI state, every add affordance stayed live and
failed with a 402 on click. Mirror the gate in the frontend instead.

getAddMembersDisabledReason is the single seam: it pairs the group with the
advanced_permissions token feature (read through useHasTokenFeature) and
returns either null or the tooltip text. Removal paths never consult it, so
a grandfathered member can always be taken out -- in MembershipSelect and
GroupsMultiSelect the gate is skipped entirely once the person is already in
the group, which keeps deselect and the pill remove button working. The
gated membership row is also marked aria-disabled, since cursor styling
alone is invisible to assistive tech.

The API-key group picker is included because an API key becomes a member of
its group and so hits the same server-side refusal. Keeping the key's
current group is not an insert, so it is exempt the same way, and
EditApiKeyModal can still save an unchanged key.

GroupDetail wraps its button in a Tooltip only when there is a reason to
disable it, so the with-feature DOM is unchanged. Pinning, sort order, and
the bolt icon key off magic_group_type alone and are untouched; with the
feature present nothing changes.

Frontend code I'm least confident in so this could use a thorough FE
review.

* Gate Data Analyst app access on advanced-permissions

What we want:

- data studio is available to superusers in OSS

- you can also give access to Data Analysts, but only with the necessary feature

We formerly did this by removing all members from the Data Analysts
group on downgrade. This is fragile. Now, we just... gate access on
feature availability as well as `is_data_analyst` (in other words, you
can be a superuser OR you can be a data analyst with the feature
enabled).

The rule for what pauses: a Data Analyst capability survives a downgrade
iff the permissions graph renders it. Curate on the Library collection,
manage-table-metadata on every table, and any assigned data, collection,
or application permissions are durable state and stay put. App access
that appears in no graph exists only because the role does, so it
follows the token.

`is-data-analyst?`: are you a member of the Data Analysts group (or a superuser)?

`entitled-data-analyst?`: the above, plus a feature check in the Data Analysts group case.

Moved to `entitled-data-analyst?`:

- the Data Studio API surfaces (data-model table endpoints, glossary, library,
  table publish, transforms listings),

- measure and segment write/create,

- Metabot's write-transforms capability,

- the transform, job, and tag models,

- `enabled-source-types-for-user`, `can_access_transforms` in the current-user
  permissions map,

- the user-list authorization,

- and the people-list `can_access_data_studio` filter, where the SQL disjunct
  on `is_data_analyst` is dropped when the feature is absent.

- `canAccessDataStudio` and the glossary page apply the same predicate on the
  frontend.

Left on role membership: `data_permissions` and its SQL, `collection.clj`,
`permissions/user.clj`, the search context, the dependencies module, and the
request plumbing for the flag.  `is_data_analyst` on the current user stays raw
too; the frontend ANDs it with the token.

api.common cannot require premium-features (settings sits between them
and requires api.common back), so the feature read is late-resolved, the
way `metabase.settings.models.setting` reads `has-feature?`.

Tests pin every moved reader in both feature states for a non-admin
analyst, with superusers shown unaffected. Analyst-driven tests that
previously needed only a transforms feature now grant
`:advanced-permissions` alongside it.

Under an OSS build every premium feature is false, so a non-admin
analyst is never entitled there. Tests that assert an analyst succeeds
are EE-only via `mt/when-ee-evailable`; the refusal cases still run in
OSS. The transforms API tests run once per requesting user through
`with-transforms-api-users!`: a superuser in every edition, and a data
analyst when EE is available.

* Delete the OSS startup demotion of the Data Analysts group

Every OSS startup ran a sync routine that mutated permission state: if the
Data Analysts magic group had members, it renamed the group in place with a
"(converted)" suffix, nulled its magic type, minted a fresh empty magic group
under the original name, and cleared `is_data_analyst` instance-wide. Because
a token check can be indeterminate as well as negative, the routine had to be
tri-state, retrying in a background future until it got a canonical answer.

This kind of state-change on startup due to a feature being missing
is... risky. If someone's token expires, it's a big annoyance if they
have to manually copy users and permissions from their old "Data
Analysts" group to the new one.

And the previous commits made it unnecessary:

- you can no longer add new members to the Data Analysts group unless
  the feature is enabled.

- almost all permissions of Data Analysts are still active after a
  downgrade. They still have curate access to the Library collection,
  `manage-table-metadata` permissions on every table, and any data,
  collection, or application permissions you assigned. Only Data Studio,
  and the app access that exists purely because of the role (writing
  measures, segments and transforms), pauses.

- when the last user is removed from the Data Analysts group, it
  disappears.

So we can remove it: startup no longer touches permission state, a much
happier place to be.

Deleted: `sync-data-analyst-group-for-oss!`, `do-sync-conversion!`,
`unique-converted-group-name`, `grant-library-permissions!`,
`seconds-to-sleep-per-attempt`, the `*allow-modifying-magic-groups*` escape
hatch that only the conversion used, the `metabase.core.core` startup call, the
`permissions.core` re-export, six now-orphaned `permissions.db` helpers, and
the routine's five tests. `canonically-has-feature?` is untouched; it has other
callers.

* Update docs/people-and-groups/managing.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Read data_layer through the schema overlay in the Data Studio access tests

Table edits land in the user-settings overlay since #82246, so a bare
`t2/select` on `:model/Table` reports sync's value. Read it the way the
OSS Data Studio table tests do.

* Reword the Data Analysts add-members tooltip around plans, not feature names

Review feedback: "Advanced Permissions" is not a term the docs use. Match the
docs' framing of a plan that includes the Data Analysts group.

* Pause every role-granted Data Analyst capability on downgrade, not just Data Studio

Review feedback: Data Studio entry paused when the plan lost
advanced-permissions, but Monitor diagnostics, the metric dependencies tab and
relationships section, and analyst-wide visibility in the dependencies API
still keyed off bare group membership.

The rule the PR set out is that capabilities rendered by a permissions graph
survive a downgrade, while capabilities that come with the role alone pause.
Dependency viewing is the latter, so:

- getUserIsEntitledAnalyst (current-user) is the feature-aware selector, and
  Data Studio, Monitor diagnostics, and both metric spots use it.
- The dependencies API builds its visibility opts from entitled-data-analyst?.

* Announce every non-clickable membership row as disabled

Review feedback: the click handler and cursor already key off isDisabled, so
aria-disabled should too, not only the feature-gated Data Analysts case.

* Make each membership row a real toggle button

Review feedback: the row was a clickable li, which keyboard and assistive
technology users couldn't operate or interpret. Each row is now an li holding
a full-width button (aria-pressed for membership) with the group-manager
toggle beside it, since a button cannot contain another button. aria-disabled
rather than disabled keeps a gated row focusable and hoverable so the tooltip
can still explain why it can't be toggled.

* Tighten the data-analyst visibility clause docstring

Review suggestion, taken verbatim.

* Name the token-status marker after the flag it sets

Review nit: the helper stamps :canonical?, so call it canonical.

* Leave SCIM group membership alone when no pushed member is a known user

Review feedback: the diff-based PUT emptied a group when every member value
was unknown, where the previous code was a no-op. Restore the no-op and warn,
since the IdP is naming users this instance never provisioned and a silent
wipe would hide that drift behind a 200.

* Make adding an existing group member a no-op

Review feedback asked for a test of PUT /api/user/:id re-asserting
is_data_analyst on someone already in the group after a downgrade. Writing it
showed two failures: a 402 from the Data Analysts addition gate, and, with the
feature on, a 500 from the membership unique index. Both because the add path
never checked whether the row already existed.

add-users-to-groups! now drops pairs that already exist before anything else
runs, so the tenant checks, the addition gate, the insert, the flag updates
and the events only ever see genuine additions. Every caller becomes
idempotent, not just the user PUT.

* Treat a bodyless 4xx token check as transient, not as a rejection

Review feedback: nothing shows the store rejecting a token without a body;
observed 403/404s carry JSON. A proxy or WAF can strip one, though, and caching
that as "token is not valid" while an HTML error page from the same proxy is
treated as transient was the wrong way round. A missing or undecodable body now
always takes the transient path: not cached, retried under the breaker, with
the previous canonical status standing meanwhile.

* Only cache a token-status body that satisfies MinimalTokenStatus

Review feedback: any JSON object, even {}, was stamped canonical and cached.
A body must now satisfy MinimalTokenStatus, a boolean :valid, a non-blank
:status and, when present, a features list, before it counts as the store's
answer. The schema's docstring records why it is used instead of TokenStatus:
one surprising optional field in a real answer would otherwise become a
transient failure refetched forever.

* fix icon alignment, small cleanup

* Enable advanced-permissions for the data-analyst MCP tool tests

A data analyst's segment, measure, and transform writes now key off the
advanced-permissions feature, which no OSS build can have. The three MCP
v2 tool tests that drive an analyst were still running with the feature
off, so the analyst was refused where the test expected success.

Follow the pattern used elsewhere on this branch: run the analyst-positive
paths only with EE available and the feature enabled, keep the denials
unconditional, and assert the analyst is refused once the feature is gone.

* Enable advanced-permissions for the metabot transform read tests

A data analyst's transform reads now key off the advanced-permissions
feature: transform-readable? goes through api/entitled-data-analyst?,
which is false for a Data Analysts member while the feature is off. The
metabot get_transform_details tool tests and the transform resource test
still drove rasta as an analyst with the feature off, so every read was
refused where the test expected the source query to render.

Follow the pattern used elsewhere on this branch and add the feature to
those tests' premium-feature sets. The source-card refusal test gets it
too, so its 403 is about the private card rather than the missing
entitlement.

* Make the analyst-driven metabot transform read tests EE-only

The previous fix turned advanced-permissions on for these tests, but
with-premium-features cannot flip a feature on an OSS build: the
entitlement check bottoms out in config/ee-available?, so rasta as a data
analyst was still refused before the test reached the source-export gate
it pins. The EE jobs passed and only the OSS app-db job failed.

Wrap every deftest that reads a transform as an analyst in
mt/when-ee-evailable, as the MCP tool tests on this branch already do.
That covers the four tests that failed and two more that only passed on
OSS because the refusal they assert happened for the wrong reason.

* Expect Monitor to pause with Data Studio for an unentitled analyst

The app-switcher spec was written when only Data Studio paused on a plan
without advanced-permissions, and asserted Monitor stayed. A later commit
on this branch made Monitor diagnostics key off the entitled-analyst
selector too, so the assertion went stale. Assert both are hidden without
the feature, and both shown with it.

* Find membership popover rows by button role in the group-managers e2e spec

The rows became real buttons without an aria-label, so findByLabelText no
longer matches them. Query by role and name instead, as the unit spec does.

---------

Co-authored-by: dan sutton <dan@dpsutton.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Kevin Kelleher <kevin.kelleher@metabase.com>
2026-10-01 05:04:43 -07:00
Chris Truter
f35a8a0077 Untangle util and a few other cross-module cycle knots (#77954)
* Untangle util and the shallow cross-module cycle knots

Cut util's upward edges into settings and system, and break four shallow
cross-module cycle knots, so the module graph's remaining cycles are the
deep ones worth arguing about.

Raise :cross-subtree-cycle-pairs to 38 for pairs master formed while
this branch sat below it: `permissions <-> users` and
`sso.auth-identity <-> users` appeared and `metrics <-> queries` went
away, for a net +1. The updater only blesses decreases.

* Make time and CORS configuration explicit

* Address time and CORS review findings

* Preserve explicit week semantics

* Use conventional module paths

* Default frontend time config while loading

* Make date formatting config explicit

* Normalize exported time config

* Use time config for picker bounds

* Close the time-config and handler option schemas

Master now checks at load time that every mu/defn argument has a schema and that every map schema is closed.
Share one closed time-config schema from lib.schema.common, close the private copy in util.date-2, and type
the comparison-range and server handler arities that had none.

* Fix closed config boundary regressions

* Separate locale from time config

* Address remaining util review findings

* Cast the invalid start-of-week through unknown in the picker spec

The test passes a deliberately invalid value to reach the runtime check, and TypeScript rejects a direct
cast between types that don't overlap.

* Nest the Quartz secure delegates in their own task module

app-db.quartz was the only reason app-db required task. The delegates now live in task.secure-delegate,
which task exports, so app-db depends on that leaf instead.

The generated classes move to the metabase.task.secure_delegate package. Running from source compiles
them into a temp directory shared by every checkout, and a stale class under the old name would still
point at the old namespace.

* Exempt task.secure-delegate from driver tests, and cap only top-level triggering modules

* Count a nested driver-triggering module unless its parent triggers too

* One sentence per line in the driver-cap docstring

* Test which driver-triggering modules the cap counts

* Name the session middleware as the one that loads mcp.core

* Drop the test-handler hooks the explorations helper needed

Master re-enabled explorations and deleted metabase.explorations.test-util, the only caller of the dynamic
handler binding.

* Keep the test handler a private no-arg function

Master reduced it to that shape, and the arity taking routes had no caller once the explorations helper went.

* Drop the u.date arities that default to the current time

Old two-argument calls like (u.date/truncate t :day) landed on the new
time-config arity and quietly used the current time in prod, where
mu/defn does not validate. Record the signature changes in the driver
changelog.

* Pass time config straight through the date formatters

Nothing outside the tests calls these formatters, so they need neither
the JS config normalization nor the week-of-year branch, which threw in
locales like ru and uk where dayjs's ordinal returns a number.

* Late-bind the API routes in the test handler again

A static require made loading metabase.test load every API namespace,
about 400 more namespaces on a cold start.

* Name app-db, not task, in the Quartz hook comments

* Keep one copy of require-time-config in impl-common

* Move the segment endpoints to metabase.segments-rest.api

Matches the other REST modules, and the openapi path filter now picks
the file up.

* Leave the driver-test cap counting as it was

With the task.secure-delegate override the old count stays at 47, and
the new counting would stop noticing a child like queries.rest that
starts triggering driver tests on its own. Changing it belongs in its
own PR.

* Look up the week start directly and test a Monday week

A Record keyed by DayOfWeekId cannot miss, so the throw and its test go.
One picker test now uses a Monday week, which the default fallback
could not satisfy.

* Drop the date-2 tests for the removed current-time arities

* Give drivers time functions that fill in the instance time config

driver-api/date-extract, date-truncate, date-bucket, date-range,
date-comparison-range, desugar-filter-clause and negate-boolean-expression
take the old arguments, so a driver migrates by changing the namespace
rather than threading a config map through each call. lib-be/time-config
replaces the map literal at the QP call sites.

* Tighten comments, docstrings and alignment in the review fixes

* Pass the current time explicitly where tests used the removed arities

Formatting today's date as yyyy-MM-dd needs no truncation, so those
bucketing tests format the current time directly.

* Explain in the driver changelog why to prefer the driver-api time functions

* Inject MCP auth and routes into the server so it no longer depends on mcp

The session middleware took MCP UI credentials from mcp.core and OAuth
bearer tokens from oauth-server, and the routes mounted the OAuth
endpoints directly, so passing CORS in alone left server depending on
mcp. The application now supplies all of these: mcp.http-handler/options
carries the CORS, bearer and UI-credential fns, and make-routes takes
the api, auth, oauth and well-known handlers as a map. A handler built
without the credential fns does not authenticate those credentials.

* Keep the segment endpoints in metabase.segments.rest.api

The segments.rest module's namespaces now match its name, so it needs no
:ns-prefix. The openapi path filter also matches src/metabase/*/rest/api.clj,
so a change to these endpoints still runs the OpenAPI checks.

* Rebuild the dev handler when its options var is redefined

make-handler also takes the options as a var. The dev handler watches it
like the middleware vars, so re-evaluating mcp.http-handler/options
reaches a running server; the prod handler derefs it once when built.

* Tighten the MCP handler docstrings and the middleware list wrappers

* Tell drivers how to replace the removed current-time arities

Also realign the comparison-range parameters left uneven by the arity
removal.

* Fail at startup when the handler is built without credential fns

The handler options now require the CORS, OAuth bearer and MCP UI
credential entries, and make-handler validates them explicitly because
mu/defn does not check schemas in prod. A server wired without them
would otherwise start and quietly refuse those credentials.

* Keep week-of-year labels on the locale's week rules

Numbering them by the configured start of week changes what users see
(week 53 and late-December dates), so it waits for frontend review.
Extraction and formatting go back to dayjs's week and Java's w pattern.

* Address remaining review findings

Drops a to-range comment the new :week branch made stale, switches the
handler test to mt/with-dynamic-fn-redefs, tightens the oauth bearer
scope schema to NonBlankString, and notes the TimeConfig duplication
and the inert start-of-week placeholder in format-diff. Leaves TODOs
on optimize-temporal-filters' per-clause time-config calls pointing at
threading it through once, like lib.filter.desugar does.

* Pass time-config explicitly in align-literal-to-unit

#81947 landed a caller of the two-argument u.date/truncate while this
branch was open. Master's version wasn't wrong -- that arity read
start-of-week through the same implicit global setting this branch
removes -- but the explicit time-config argument is now required, so
the call needs it passed in directly.
2026-09-30 22:11:55 +00:00
Jacob Joseph
14550d36bd [docs] Modify Docker build command in developers guide (#83151)
* Modify Docker build command in developers guide

Updated the Docker build command to include a VERSION argument and clarified the versioning instructions. VERSION is a required build-arg.

* Correct version format in Docker build instructions

Updated version format in build instructions to remove patch
2026-09-30 20:50:02 +00:00
Andrei Simionescu
912b2ba3b9 Support Model Garden endpoints on the Google provider (#82276)
A Google connection can now name a Model Garden endpoint, which then shows up in the model picker and is called over Chat Completions. A Chat Completions stream that fails partway now ends in an error instead of looking complete.
2026-09-30 18:18:45 +01:00
Jeff Bruemmer
2e51e9ded1 docs - security best practices (#83260) 2026-09-30 11:00:23 -04:00
github-automation-metabase
2d79e75917 Auto-update documentation for master (#83293)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-09-29 21:24:43 +00:00
Robert Kosara
f40e8e13da Clarify reference questions scope (#83264)
* Small spacing fix

* Add short paragraph about scope that's being searched

* Move new paragraph below the image

* Jeff's rewording

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-09-29 20:50:19 +00:00
Michael Eby
3ec11a26ab docs: auth settings UI (#82971)
* docs: auth settings UI

* Optimized 6 images, saved 212.5 KB (49.8% smaller)

* Apply batched suggestions from code review

Co-authored-by: Jeff Bruemmer <jeffbruemmer@gmail.com>

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Jeff Bruemmer <jeffbruemmer@gmail.com>
2026-09-29 17:22:01 +00:00
Jeff Bruemmer
cf2d4d8b86 docs - domain page (#82683) 2026-09-29 14:51:00 +00:00
Oleh K
a522f86267 Update supported browsers doc and pin browserslist (#80477)
* GDGT-3128: Pin browserslist to the versions we actually support

The documented floor (Chrome 70, Firefox 68, Edge 17, Safari 11) had drifted
far from reality. Auditing the shipped bundles turned up features that break
well above it:

  - subgrid (Chrome 117), unguarded in two CSS modules
  - :has() (Firefox 121), 248 occurrences; the postcss polyfill is disabled
  - color-mix() (Chrome 111), including the ui/colors base palette
  - toSorted/findLast (Safari 16.4) and URL.canParse (Chrome 120, Safari 17)

There are no polyfills to fall back on: core-js is not a dependency, so
preset-env injects nothing.

browserslist said "defaults", which resolves to Chrome 109 among others --
below our own floor -- so the build was targeting browsers the code breaks
on. Pin it to the audited versions instead.

The rspack swc-loaders hardcoded env.targets: ["defaults"], bypassing
package.json entirely. Dropping targets lets swc fall back to the
browserslist config, matching babel-loader and postcss.

Verified against the real postcss pipeline over all 826 CSS files. Prefix
output only improves: -webkit-backdrop-filter is now emitted (Safari needs it
through 17.6, and it was previously missing), and -webkit-background-clip is
dropped, which is safe because Chrome 120 is exactly where the unprefixed
form lands. The -moz-column-*/-o-* prefixes that go away were for Firefox
versions far below 121.

* GDGT-3128: Use the :global() function form in CSS modules

Pinning browserslist dropped `op_mini all` from the targets, and Opera Mini
was the only thing keeping postcss-preset-env on its expanded nesting
desugaring. With it gone, preset-env emits the spec-correct `:is()` form:

    .editor :global .cm-panels     ->  :is(.editor :global) .cm-panels

That pulls `:global` inside `:is()`, where its positional "everything after
this is global" semantics no longer apply. css-loader then scoped the classes
it was meant to leave alone:

    :local(.editor) .cm-panels     ->  :is(:local(.editor)) :local(.cm-panels)

CodeMirror renders real `.cm-editor`/`.cm-panels`/`.cm-content` elements, so
every rule in those blocks silently stopped applying -- 20 scoped selectors and
0 global in CodeMirror.module.css alone. That took out three e2e specs:
cc-typing-suggestion, native-reproductions and transforms.

The `:global()` function form binds global-ness to a selector node instead of a
position, so no amount of selector rearrangement can separate it from the class.
Verified to hold three levels deep, including under `:is()` wrapping.

Selector output is otherwise unchanged: compiling each file under the old and
new configs and comparing the post-CSS-modules selector sets gives an exact
match, except for a `::-moz-placeholder` that the browserslist pin drops on its
own (Firefox 121 has it unprefixed).

The stylelint rule catches the bare form. It also flags a top-level `:global {}`
block, which happens to work today only because a lone `:global` is a single
compound and escapes the `:is()` wrap -- one more nesting level and it breaks
the same way.

* GDGT-3128: Raise the Safari floor to 18.2 for auxclick

`auxclick` lands in Safari and iOS Safari 18.2 -- every version through 18.1
reports `n` in caniuse. There are 12 unguarded `onAuxClick` handlers in app
source (19 counting tests), so 17 was never a floor we actually met.

Chrome (55), Firefox (53) and Edge (79) are all far below their current floors,
so only Safari moves.

Side effect: `-webkit-backdrop-filter` is no longer emitted. Safari needed it
only through 17.6, so past 18.2 autoprefixer correctly drops it. The same bump
also covers scrollbar-gutter/width/color, which all wanted exactly Safari 18.2.
2026-09-29 10:59:14 +02:00
Jakub Chodorowicz
bc828de810 Gdgt 3239 update api changelog for v64 (#82753)
update api changelog (gadget v64)
2026-09-29 09:32:14 +02:00
github-automation-metabase
0e59c12a16 Auto-update documentation for master (#82989)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-09-28 20:54:54 -04:00
Nemanja Glumac
ebfaff69d0 Update the checkout action to v7 (#82914) 2026-09-28 17:31:18 +02:00
YB
176d0682e2 Document where action runs are logged (#82742)
document where action runs are logged
2026-09-28 13:18:46 +08:00
Andrei Simionescu
f2e185369f Always show the Metabot illustrations toggle (#82946)
* Always show the Metabot illustrations toggle
* Only mention the chat sidebar in the illustrations label and docs
* Test the illustrations toggle with the default icon
2026-09-25 21:30:29 +01:00
Riley Thompson
cdc7f386af Compile mbql stages to CTEs for postgres (#81914)
* initial commit

* Use CTEs for every multi-stage Postgres query

Drop the "standalone statement" gate and the native/persisted-stage and
join-source fallbacks. Postgres accepts WITH everywhere we embed a compiled
query (JOIN parens, CTE bodies, card-reference subqueries, CREATE TABLE AS,
INSERT INTO), so the only remaining condition is the driver opting in and
the query having more than one stage.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix changelog

* simplify with mapv

* comments

* Build CTE tests with lib and assert results only

Rewrite the four multi-stage tests added on this branch to build their
queries with lib/query and a metadata provider instead of mt/mbql-query,
and drop the compiled-SQL string assertions so they only check that each
query runs on Postgres and returns the expected rows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* trim comments

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 14:09:50 +00:00
github-automation-metabase
d994a365f7 Auto-update documentation for master (#82878)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-09-23 09:40:25 -04:00
YB
12a22c0392 [GDGT-3229] read ClickHouse indexes from SHOW CREATE TABLE instead of system tables (#82573)
ClickHouse denies SELECT on system.data_skipping_indices, so index verification failed for every request (the index itself was created). fetch-table-indexes now reads one SHOW CREATE TABLE and parses its INDEX and ORDER BY lines. A failed warehouse read now carries the driver's message on the request and as warehouse_error on the indexes list, with an alert on the indexes page.
2026-09-23 21:14:23 +08:00
Michael Eby
812e9b2254 add IP allowlist page to nav (#82774)
* add IP allowlist page to nav

* fix nav and metabase ip addresses label
2026-09-21 12:40:46 -04:00
Jeff Bruemmer
72e2e9b234 docs - ai providers updates (#82376) 2026-09-20 14:33:58 +00:00
Aleksandr Lesnenko
3d924036db bind dev Docker ports, socket REPL, and rspack dev server to loopback only (#82707) 2026-09-19 10:27:04 +07:00
Michael Eby
61b6635f13 docs: IP allowlist (#82761)
* docs: IP allowlist

* edits from jeff
2026-09-18 15:16:45 -04:00
Alexander Polyankin
86b1f4bca4 Transform tests (#82495) 2026-09-18 14:50:16 -04:00
github-automation-metabase
f24251fb4e Auto-update documentation for master (#82710)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-09-18 11:51:01 -04:00
John Beers
3d8a3901a9 docs: update URL configuration (#82744)
[docs] Add theme keyword
2026-09-18 09:11:12 -04:00
github-automation-metabase
bfc9d9aa91 Auto-update documentation for master (#82604)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-09-17 09:34:23 -04:00
Mahatthana (Kelvin) Nomsawadi
d53a909a92 Revert "Integration branch for Embedding settings reorganization (#80336)" (#82570)
* Revert "Integration branch for Embedding settings reorganization (#80336)"

This reverts commit b9d217cbb4.

Also drop enable_embedding_modular from the closed stats snapshot
schema. #82447 (Require typed, closed argument schemas in mu/defn)
added that line after #80336, so git revert leaves it behind while
removing the key from the snapshot.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sqWaxii4kHFrYmW9c45zZ

* fix: keep writing embedding_theme.is_default

The is_default migration stays after the revert, since it may already
have run and migrations cannot be removed, so the column still exists.

- Restore its serdes :skip entry and the theme API key-set
  expectations for endpoints that return the whole row.
- Keep marking seeded Light/Dark themes as default, so the flag stays
  meaningful when the embedding hub work is picked up again.
- Keep returning it from the theme API, including the list endpoint,
  as #80336 did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sqWaxii4kHFrYmW9c45zZ

* refactor: keep the settings-components module

#80336 moved the settings page primitives into the shared
settings-components module. That move is not part of what is being
reverted, and later master work builds on it (#82389, #82462), so keep
it: restore the module, its lint entries, and point imports back at it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sqWaxii4kHFrYmW9c45zZ

* refactor: keep the setup guide rename

#79514 renamed the embedding hub checklist code to setup guide, which is
what the UI already calls it. It is a rename only: the API path, setting
names and persisted state keep their embedding-hub names. Re-apply it on
top of the revert so the name stays free for the embedding hub section
when that work is picked up again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sqWaxii4kHFrYmW9c45zZ

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 14:08:13 +01:00
Chris Truter
7c771f3c33 Add GPT-6 Astra support (#82499)
* Add GPT-6 Astra to the OpenAI, Azure and Bedrock model pickers

The OpenAI allowlist stopped at the 5.6 family, and the reasoning/temperature
check keyed off a gpt-5 prefix, so a forced request would have sent
temperature, which Astra rejects. Widen the check to GPT-5 and GPT-6 and add
the model to the three adapters that sell it directly.

OpenRouter is left out: its allowlist needs a live reasoning probe per model.

* Correct Bedrock context window comment
2026-09-16 20:17:17 +00:00
Sloan Sparger
efe0882aca [Metabot] Remove transform_codegen profile (#82208) 2026-09-16 09:17:13 -05:00
github-automation-metabase
c19c1bfdeb Auto-update documentation for master (#82532)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-09-16 02:02:55 +00:00
Michael Eby
94aea9ae24 docs: 2FA v2 (#81962)
* docs: 2FA v2

* verify admin path and require options

* edit from jeff
2026-09-15 12:46:43 -04:00