Edit: Can be merged, mgmt api deployed
Dashboard addition to frontend for access to the ISO 27001 certificate.
View for Team customers:
<img width="1737" height="1151" alt="image"
src="https://github.com/user-attachments/assets/cd62d24f-8b6e-4600-9ded-943a170cd124"
/>
Resolves SEC-799
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* ISO 27001 certificate added to Documents with a Download action,
confirmation modal, new-tab open on success, and error toast on failure.
* Users without billing permission see a no-permission view; users
missing entitlement see an “Upgrade to Team” prompt.
* **Refactor**
* Upgrade-to-Team flows for SOC2 and related upgrade UI standardized to
use the shared upgrade component.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved SQL query handling for vector bucket creation and Foreign
Data Wrapper operations
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes the RLS policies page showing self-contradictory or wrong
admonitions for tables with partial grants. Classifies each table using
the same `granted / custom / revoked` semantics used by the Data API
settings page so the two views agree on what counts as "exposed".
**Changed:**
- `PolicyTableRow` now uses `useTableApiAccessQuery` (shared cache with
the Table Editor sidebar) instead of a bespoke
`tables-roles-access-query`
- Boolean soup collapsed into a single `TableDataApiStatus`
discriminated union (`schema-not-exposed | no-grants | custom-grants |
publicly-readable | locked-by-rls | secured`) via a pure helper
- Admonition copy for `no-grants` and `locked-by-rls` updated; a table
with no policies but full grants now reads "No data will be returned via
the Data API as no RLS policies exist on this table." instead of the
earlier self-contradictory "can be accessed but no data will be
returned"
- `table-api-access-query.ts` now exposes a `grantStatus: 'granted' |
'custom'` on `access` entries — `granted` = all 3 API roles × all 4 CRUD
privileges (matches `getTableGrantsCTEs` in pg-meta)
**Added:**
- New `custom-grants` admonition: "This table has custom Data API
permissions — access may be restricted for some roles or operations."
- Unit tests for `getTableDataApiStatus`, `getTableAdmonitionMessage`,
and `isFullyGranted`
**Removed:**
- `data/tables/tables-roles-access-query.ts` and the `rolesAccess` key —
no more callers
## To test
On a project with the `public` schema exposed, for each scenario check
the admonition shown on `/project/{ref}/auth/policies`:
1. Table with full standard grants, RLS on, no policies → "No data will
be returned via the Data API as no RLS policies exist on this table."
2. Table with full standard grants, RLS off → yellow warning "can be
accessed by anyone"
3. Table with partial grants (e.g. only `GRANT SELECT ON t TO anon`) →
new "custom Data API permissions" admonition regardless of RLS state
4. Table with no anon/authenticated/service_role grants → "cannot be
accessed via the Data API"
5. Schema not in the exposed list → "schema not exposed" admonition with
link
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Added unit tests covering table Data API/RLS status classification and
API grant validation.
* **Refactor**
* Introduced a unified per-table API/RLS status model and reusable
utilities to derive display status and admonitions.
* Simplified UI logic to drive access indicators and warnings from the
new status.
* **Chores**
* Removed legacy role-based access query and its related keying logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Preserve `formattedError` through the `ResponseError` path and fall back
to splitting `error.message` on newlines so enhanced permission-denied
HINTs from supabase/postgres#2084 render as separate lines in the SQL
editor — users can actually read the GRANT example now.
**Context:** postgres#2084 adds a multi-line HINT to SQLSTATE 42501
errors, telling users exactly how to grant access per-table. Today the
SQL editor rendered the whole thing on one line because `formattedError`
was stripped by the fetchers' error handling and the `message` fallback
didn't split on `\n`. This PR fixes both.
Blocks [FE-3023](https://linear.app/supabase/issue/FE-3023) — the
project-creation toggle that flips default privileges; without readable
HINTs users land on RLS debugging rabbit holes when they hit a
permission denied.
**Changed:**
- `ResponseError` now carries an optional `formattedError` field;
`ConnectionTimeoutError` / `UnknownAPIResponseError` thread it through.
- `handleError` in `data/fetchers.ts` extracts `formattedError` from the
raw error body and forwards it to the thrown subclass.
- `UtilityTabResults.tsx` uses a new `getSqlErrorLines` helper — prefers
`formattedError`, falls back to splitting `message` on newlines when
it's multi-line (defense in depth since the exact field pg-meta
populates for the HINT depends on the path). Copy button now uses the
same lines.
**Added:**
- `getSqlErrorLines` pure helper + 9 unit tests.
- 5 new tests in `handleError.test.ts` covering `formattedError`
preservation on classified and unclassified errors.
## To test
1. Pull the branch, run `pnpm dev:studio`, open any project's SQL
editor.
2. Run a query that triggers the enhanced HINT (requires postgres#2084
deployed on the DB — currently staging-only). Example: `select * from
some_table_you_cant_read;` as a role without grants.
3. Expect the ERROR line, HINT line, and the `GRANT ...` example to each
render on their own `<pre>` line, plus the Copy button to copy the full
multi-line text.
4. Sanity check existing single-line errors (e.g. `select * from
nonexistent_table`) still render as `Error: relation "nonexistent_table"
does not exist` in the `<p>` fallback.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **New Features**
* Improved SQL error message formatting in the editor for better
readability and clarity.
* **Refactor**
* Centralized error formatting logic for more consistent error
presentation across the application.
* **Tests**
* Added comprehensive test coverage for SQL error message parsing and
formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Lets self-hosted Studio toggle flags in `enabled-features.json` at
container start time via `ENABLED_FEATURES_*` env vars, without
rebuilding the prebuilt image. Addresses
[FE-3036](https://linear.app/supabase/issue/FE-3036/allow-enabled-featuresjson-flags-to-be-overridden-via-env-vars)
and is a prerequisite for
[COM-205](https://linear.app/supabase/issue/COM-205/add-feature-flag-to-disable-all-logs-in-studio).
**Added:**
- `packages/common/enabled-features/overrides.ts` — pure parser that
maps `ENABLED_FEATURES_*` env vars to a disabled-features list
(forward-only key mapping, boolean validation, typo warnings) + 10
vitest tests
- `apps/studio/pages/api/enabled-features-overrides.ts` — Next.js API
route reading `process.env` at request time; no-op (`{
disabled_features: [] }`) when `IS_PLATFORM`
- `apps/studio/data/misc/enabled-features-override-query.ts` — React
Query hook with `staleTime: Infinity`, `enabled: !IS_PLATFORM`
- `packages/common/enabled-features/README.md` — docs the env var
convention, resolution order, `IS_PLATFORM` gating, and the
`Support.constants.ts` build-time caveat
**Changed:**
- `apps/studio/hooks/misc/useIsFeatureEnabled.ts` — merges the
override's `disabled_features` with `profile.disabled_features`
### Env var shape
One var per flag, prefixed `ENABLED_FEATURES_`. Feature key → env name:
uppercase with every non-alphanumeric char replaced by `_`.
```bash
ENABLED_FEATURES_LOGS_ALL=false
ENABLED_FEATURES_BRANDING_LARGE_LOGO=true
```
Values are `true`/`false` case-insensitively. Other values and prefixed
vars that don't match a known feature are logged and ignored.
### Resolution order (runtime, Studio only)
1. `ENABLED_FEATURES_*` (self-hosted, via API route → React Query →
hook)
2. `profile.disabled_features` (hosted, from `/platform/profile`)
3. `enabled-features.json` static value
4. Default (enabled)
`ENABLED_FEATURES_OVERRIDE_DISABLE_ALL` still short-circuits everything.
### Known limitation
`apps/studio/components/interfaces/Support/Support.constants.ts:4` calls
`isFeatureEnabled('billing:all')` at module load to build
`CATEGORY_OPTIONS`, which is spread into Zod form schemas. That call
site stays resolved from the JSON — documented in the package README.
`billing:all` isn't on the radar for self-hosted runtime toggling.
## To test
- `cd packages/common && pnpm exec vitest run enabled-features` — 10 new
tests pass
- `pnpm --filter studio run typecheck` clean
- Spin Studio locally with `NEXT_PUBLIC_IS_PLATFORM=false` and
`ENABLED_FEATURES_LOGS_TEMPLATES=false`;
`/project/[ref]/logs/explorer/templates` should reflect the flag after
the override fetch resolves
- Confirm the API route returns `{ disabled_features: [] }` when
`NEXT_PUBLIC_IS_PLATFORM=true`
- Set a typo like `ENABLED_FEATURES_LOGS_TMEPLATES=false` and check the
warning in container logs; flag stays enabled
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Runtime feature-flag overrides for self-hosted deployments (env var
driven), new API endpoint and client-side hook to fetch overrides, and
client logic now merges profile and runtime overrides.
* **Documentation**
* Added comprehensive README describing the feature-flag system and
override configuration.
* **Tests**
* Added unit tests for override parsing and E2E tests covering runtime
override behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
## What kind of change does this PR introduce?
Feature. Resolves DEPR-430.
## What is the current behaviour?
The homepage Advisor summary, shared Advisor panel, and top-nav Advisor
indicator only surface lints and notifications. Banned IPs are not
represented as dismissible Advisor items, so network bans are easy to
miss unless a user visits Database Settings directly.
The `public bucket allows listing` warning is no longer part of this PR.
That warning will move to a follow-up Splinter `WARN` lint so it can
flow through the standard lint surfaces instead of a bespoke Studio
signal path.
## What is the new behaviour?
- adds a new Advisor `signal` source for banned IPs on the platform
homepage, in the shared Advisor panel, and in the top-nav Advisor
indicator
- keeps dismissals client-side only for now, scoped by project and exact
IP fingerprint
- keeps banned IP signals at `warning` severity because they still
indicate suspicious traffic and remain actionable if a user wants to
review or remove a ban
- leaves `/project/[ref]/advisors/security` as follow-up work because
that surface is still lint-native, and banned IPs are management-plane
signals rather than Splinter lints
| After |
| --- |
| <img width="1728" height="997" alt="Mallet Toolshed
Supabase-65A60B4A-107E-4D79-B9A8-23F754BEAB08"
src="https://github.com/user-attachments/assets/c08ecbbb-c302-43bd-81bb-6ba7eb18b7b3"
/> |
## Reviewer testing notes
1. Use a throwaway project.
2. Get the database connection string for that project.
3. Attempt to connect with the wrong password 3-4 times until you hit an
`ECONNREFUSED`-style error, which should mean your IP has been banned.
4. Refresh Studio and confirm the project overview shows the new `Banned
IP address` signal.
5. Open the Advisor Center and confirm:
- the top-nav Advisor dot turns warning yellow
- the signal detail shows `Entity`, `Issue`, and `Resolve`
- `Edit network bans`, `Dismiss`, and `Learn more` are present
6. Open Database Settings > Network bans and confirm your banned IP
appears there and can be unbanned.
7. Note that `/project/[ref]/advisors/security` will not show this item.
That page is still lint-only, and this banned IP work is a short-term
client-side signal rather than a true lint.
Longer term, we likely want a more durable event model here so banned
IPs can power notifications, webhooks, emails, and other project-level
alerts.
---------
Co-authored-by: kemal <hello@kemal.earth>
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Overhauled SQL generation across the Studio: queries and helpers now
use safer, parameterized SQL construction for more robust and consistent
behavior.
* **Bug Fixes**
* Improved trigger update flow so event values are normalized before
saving, reducing errors when modifying webhooks/triggers.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## TL;DR
the table editor definition panel was showing incomplete SQL for views
with `WITH (security_invoker = true)`
ignoring the reloption and making it easy to accidentally strip it when
recreating the view
## prob
When viewing a security invoker view in the Table Editor, the Definition
panel only showed `CREATE VIEW ... AS ...`
without the `WITH (security_invoker = true)` clause
which caused two issues:
1. the displayed SQL was incomplete and didn't match the actual view
definition
2. users copying the SQL to recreate the view would unintentionally lose
the security_invoker setting
## ex:
| Before | After |
|--------|-------|
| `create view public.exposed_api as`<br>`select id, secret from
public.rls_protected_table;` | `create view public.exposed_api with
(security_invoker = true) as`<br>`select id, secret from
public.rls_protected_table;` |
## ref:
- closes https://github.com/supabase/supabase/issues/44934
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* View definitions now show the full CREATE statement (including
materialized views and WITH (...) options) and preserve security options
like security_invoker when viewed or opened in the SQL editor.
* **Tests**
* Added end-to-end test verifying security option preservation in view
definitions and when opening them in the SQL editor.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This PR integrates with the new marketplace db to allow Grafana (and
other partners) OAuth apps to install from the integrations page. A demo
of this working locally is available here:
https://supabase.slack.com/archives/C01GN60J0BS/p1775551752479709. End
to end flow is documented here:
https://www.notion.so/supabase/Grafana-Integration-Flow-33a5004b775f80eeaf91c098beb8071f.
TODO:
- [ ] Make sure `NEXT_PUBLIC_MARKETPLACE_API_URL` variable is set to the
new marketplace db.
- [x] Test with the `marketplaceIntegrations` enabled and disabled in
staging once https://github.com/supabase/platform/pull/31298 is merged
and available in staging.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Add OAuth "Install integration" button that detects installed
integrations and supports GET/POST install flows
* Marketplace listings now include install links, installation method,
partner info, and listing assets/logos
* **Infrastructure**
* Allow marketplace API origin for images and content in security and
image config
* Centralize marketplace types and switch marketplace data source for
more reliable listings
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
## Context
Preferred fix to this PR
[here](https://github.com/supabase/supabase/pull/44886)
On a security email template page (e.g. Reauthentication), if you edit
the Subject or Body without saving, then toggle **Enable notification**
in the Configuration card and click **Save changes**, the Content edits
are reverted to the last saved values.
## Changes involved
Opting to not invalidate the `authConfig` RQ cache on a successful
mutation when toggling the security email notification while on the
template editor page
## To test
- [ ] Open a security email template
- [ ] Make some changes to the template without saving
- [ ] Toggle the notification and save
- [ ] Ensure that the template changes are still present and not
reverted
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Optimized query cache handling for authentication configuration
updates to reduce unnecessary refresh operations.
* Enhanced type safety for form submissions in authentication settings
to prevent data validation errors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Display tax information in the upcoming invoice breakdown.
- Show a "Tax" line item with amount and rate tooltip when tax is
successfully calculated
- Show a warning row when tax estimation fails, prompting users to
verify their billing address
- Update Current Costs and Projected Costs tooltips to indicate whether
tax is included or could not be estimated
## Test plan
- [ ] Verify tax row appears with correct amount
when `tax_status` is `calculated`
- [ ] Verify tax rate percentage shows in the tooltip (e.g., "Estimated
tax at 10%...")
- [ ] Verify warning row appears when `tax_status` is `failed`
- [ ] Verify no tax row appears when `tax_status` is `not_applicable`
- [ ] Verify "Applicable tax included." appears in Current/Projected
Costs tooltips when tax is calculated
- [ ] Verify "Tax could not be estimated and is not included." appears
in tooltips when tax fails
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Upcoming invoices now include tax details and a tax status.
* Billing breakdown shows projected tax and conditionally displays
projected totals excluding tax when applicable.
* If tax estimation fails, a “Tax — Could not be estimated” row appears
and totals reflect the failure.
* Added "Stripe Projects" as a billing partner option and clarified that
projected amounts may be explicitly null.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
## Summary
Reorder AddPaymentMethodForm and PaymentMethodSelection to use a dry run
validation → Stripe payment setup → real update flow:
- Validate address and tax ID via `dry_run: true` before touching Stripe
- Proceed with Stripe payment method creation / 3DS only if validation
passes
- Persist the customer profile update with dry run disabled after Stripe
succeeds
- Add `dry_run` support
to `useOrganizationCustomerProfileUpdateMutation`
- Add `getFormValues()` to `PaymentMethodElementRef` to read address and
tax ID form state
- Delete the now-unused `organization-tax-id-update-mutation.ts`
## Test plan
### Adding a Payment Method
From the billing dashboard `/org/_/billing`:
- [ ] Add a payment method with a valid tax ID: should dry-run
validate, then create the payment method via Stripe, then persist the
billing profile
- [ ] Add a payment method with an invalid tax ID: should show a
validation error from the dry run and not proceed to Stripe payment
setup
- [ ] Add a payment method with the "primary billing address" checkbox
unchecked: should skip the customer profile update entirely and only
create the payment method
- [ ] Add a payment method where Stripe 3DS fails: billing profile
should not be persisted (only the dry run ran)
### Credit Top Up
- [ ] Top up credits with a new payment method and valid tax ID: should
dry-run validate, then create the payment method, then process the
top-up
- [ ] Top up credits with a new payment method and invalid tax ID:
should show a validation error from the dry run and not proceed to
Stripe payment method creation
### Plan Upgrade
- [ ] Upgrade plan with a new payment method and valid tax ID: should
dry-run validate before creating the payment method
- [ ] Upgrade plan with a new payment method and invalid tax ID: should
show a validation error and not proceed to Stripe
- [ ] Upgrade plan with an existing payment method: should proceed
without dry-run validation
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
This connects the Advisor from the splinter repo. Below are the list of
changes:
- Register advisor which should appear in both the legacy Advisors and
Advisors sidebar.
- Adds a "Dismiss" button to the admonition inside the bucket view.
- Makes the check for select policy on public buckets tiny bit
stricter/truer.
This is awaiting the [PR](https://github.com/supabase/splinter/pull/152)
in splinter going in!
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a security lint that flags public storage buckets allowing
listing, with a direct "View bucket" link.
* Users can dismiss public-bucket warnings per project+bucket for 14
days via a Dismiss button.
* **Improvements**
* Tightened policy detection to better target bucket-scoped select
policies and avoid unrelated matches.
* **Telemetry**
* Added events for policy removal and dismiss-button clicks.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Call the new `POST /platform/organizations/preview-creation` endpoint
when creating an organization on a paid plan to show a tax breakdown
before submission
- Preview is triggered reactively when the user completes the billing
address in the Stripe AddressElement (debounced, same pattern as
subscription upgrades)
- Displays plan price, tax line (with percentage), and total due today -
hides the plan price row when there's no tax adjustment
## Test plan
- [ ] Create a new org on the Free plan - no preview should appear
- [ ] Create a new org on Pro/Team - fill in billing address with all
fields including name
- [ ] Verify tax preview appears after address is complete (1s
debounce)
- [ ] Verify tax line shows for taxable jurisdictions (NY Zip Code
10001), hidden for non-taxable
- [ ] Verify plan price row is hidden when total equals plan price (no
tax)
- [ ] Change address country - verify preview updates
- [ ] Add a tax ID - verify preview updates
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Pricing preview during organization signup that shows plan price
differences, tax details (rate/amount or estimation failure), and “Total
due today.”
* Preview updates reactively based on selected plan and spend cap (PRO
without spend cap treated as PAYG) and appears only for paid plans after
preview initialization.
* Debounced billing address and tax ID input collection for accurate
previews; panel opacity reduced while fetching.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Reset the table rows query after the user confirms loading data on a
high-cost table, so React Query re-executes the fetch without the
preflight check
- Close the confirmation dialog after the user clicks "I understand,
proceed"
**Root cause:** `preflightCheck` is intentionally excluded from the
React Query query key (to avoid duplicate cache entries). When the user
clicked "Load data", the preflight flag flipped to `false` but the query
key stayed the same — so React Query returned the cached error instead
of refetching.
## Test plan
- [x] Navigate to a table with high estimated query cost (triggers "Data
not loaded to protect database performance")
- [x] Click "Load data" → "I understand, proceed"
- [x] Verify the dialog closes and table data loads
- [x] Verify the warning does not reappear for the same table in the
same session
To test this you can run this locally with COST_THRESHOLD set to a low
value (< 10)
Fixes FE-2979
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Confirming the high-cost warning now closes the dialog and proceeds
with loading as expected.
* Improved query cache key composition so queries reflect the full set
of relevant parameters for correct caching.
* Loading from the grid error now properly clears related cached results
and proceeds when the user confirms.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Consolidate tax ID saving into the `PUT
/organizations/{slug}/customer` endpoint instead of using a
separate `/tax-ids` endpoint
## Test plan
### Updating billing information
From the billing dashboard`/org/_/billing`:
- [ ] Manually test updating billing address + tax ID from org billing
settings - single API call should save both
- [ ] Clear the Tax ID in the org, save and assert that it has been
deleted
- [ ] Modify all the fields in the address form, including TaxID. Click
"Cancel" and assert that everything has returned to the previous values.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Billing address and tax ID updates are now sent in a single update
operation.
* Error messaging for billing updates consolidated into a single failure
notification.
* Tax ID handling clarified: you can clear tax ID explicitly or leave it
unchanged; omitting address fields no longer overwrites existing
address.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show OAuth server endpoints in oauth server settings page.
Preview: [OAuth Server
settings](https://studio-staging-git-chore-show-oauth-server-endpoints-supabase.vercel.app/dashboard/project/_/auth/oauth-server)
<img width="1138" height="496" alt="Screenshot 2026-01-09 at 12 00 31"
src="https://github.com/user-attachments/assets/eeca7726-0426-4abe-990d-271b702e4f7b"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an OAuth endpoints table showing Authorization, Token, JWKS, and
Discovery/OpenID URLs with copy-to-clipboard and a masked preview mode.
* Inline preview of the Authorization URL when an authorization path is
set.
* **Improvements**
* Reorganized OAuth server settings for clearer enable/disable flow,
conditional field visibility, and disable confirmation.
* Dynamic loading of the endpoints table, improved loading skeletons,
layout refinements, and form reset to reflect saved defaults.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Ali Waseem <waseema393@gmail.com>
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Refactor based on https://github.com/supabase/platform/pull/31325
## What is the current behavior?
We presented a page to Stripe users to let them either pick an existing
org or create one.
## What is the new behavior?
We're forcing them to create a new one (or show that there was one
already linked).
- It also adds the option to sign out when there's a conflict. Fixes
https://linear.app/supabase/issue/API-963/add-a-button-to-logout-from-the-page-you-must-be-logged-in-as-x-to
- And adds the link to root from the logo.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added organization preview creation endpoint for billing workflows.
* **Bug Fixes**
* Removed organization-picking flow from Stripe Projects login; users
now proceed directly with confirmation.
* Added a "Sign out" button on error pages.
* **Refactor**
* Removed a legacy billing partner option.
* Made the Supabase logo clickable for quick navigation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
Fixes#44587
index-delete-mutation.ts and index-create-mutation.ts construct SQL
using raw string interpolation for identifiers (schema, table, column
names) without escaping double quotes. Uses ident() from
@supabase/pg-meta/src/pg-format, same utility already used in the
database-queues mutations.
## Summary by CodeRabbit
* **Refactor**
* Improved identifier quoting/escaping for creating and dropping
database indexes to ensure consistent, safer index operations.
---------
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
## Problem
The disk throughput chart on the database observability report was gated
to Team plan and above. This prevented Free and Pro tier users from
seeing disk throughput data, which is a useful self-debugging aid when
hitting DiskIO-related resource exhaustion, especially on smaller
instances where baseline throughput limits are a major constraint.
The gate was originally introduced to reduce load on the metrics
infrastructure while observability queries were being scaled. That
constraint no longer applies.
## Fix
Remove the `entitlement` and `requiredPlan` fields from the
`disk-throughput` chart config in
`apps/studio/data/reports/database-charts.ts`. The rendering logic in
the database observability page only shows the upsell prompt when
`chart.entitlement` is set, so removing it makes the chart render
unconditionally for all tiers.
## How to test
- Open the database observability report at
`/project/<ref>/observability/database` on a Free or Pro project
- Confirm the Disk Throughput chart is visible and showing data (not an
upsell card)
- Confirm the chart still works correctly on a Team or Enterprise
project
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Removed plan-based access restrictions from disk-throughput metrics,
making them available to all users.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
- Passes billing address and tax ID from the payment form to the
subscription preview endpoint, so taxes are recalculated live as the
user updates their details
- Debounces address/tax ID changes (1s) in `NewPaymentMethodElement` to
avoid excessive API calls while typing
- Decouples the preview refetch from the payment form's mount state -
uses `keepPreviousData` so the form stays mounted and the breakdown dims
with `opacity-50` instead of unmounting/remounting during refetches.
Shimmer skeleton only shows on initial load.
- Disables the "Confirm upgrade" button while a refetch is in progress
to prevent submitting with stale tax data
- Respects the "Use address as my org's billing address" checkbox: the
preview should mirror what will actually happen - if the checkbox is
unchecked, the address won't be saved to Orb, so it shouldn't be used
for the tax estimate either. Otherwise the user sees one price and gets
charged another. The logic for this lives in `PlanUpdateSidePanel`
``` mermaid
flowchart TD
A[User opens upgrade dialog] --> B[Fetch subscription preview]
B --> C[Show payment form + price breakdown]
C --> D[User edits address or tax ID]
D -->|1s debounce| E{Use as billing address?}
E -->|Yes| F[Re-fetch preview with new address]
E -->|No| G[Re-fetch preview without address override]
F --> H[Update breakdown — form stays mounted]
G --> H
H --> C
```
## Test plan
- [x] Open the plan upgrade dialog, verify the payment form and
breakdown load normally on first open
- [x] Change the billing address country - verify the breakdown dims
briefly and updates with new tax amounts without the payment form
unmounting
- [x] Toggle the tax ID on/off and change its value - verify the
preview refreshes after ~1s debounce
- [x] Confirm the upgrade button is disabled while the preview is
refetching
- [x] Uncheck "Use address as my org's billing address" - verify the
preview refetches without address/tax overrides
- [x] Re-check the checkbox - verify the preview refetches again with
the current form address
- [x] Assert that adding a new billing address in the CreditTopUp form
works and saves the address
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Payment and subscription flows now propagate billing address and tax
ID via new callbacks; subscription preview requests include these values
and preserve prior results while fetching.
* Preview updates are debounced to reduce noise; loading state disables
confirm actions and visually dims charge breakdown.
* **UX**
* Address input emits complete normalized address updates (empty second
line cleared).
* Tax ID input emits updates and explicit clears (null).
* “Use address as my org's billing address” is now controlled and
reports changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes#44586
The `enabled` field in `useGetIndexAdvisorResult` had an OR branch that
bypassed the `enabled` prop for queries starting with `with
pgrst_source`. This meant the query could fire even when `enabled:
false` was passed (e.g. when the index_advisor extension isn't installed
or the result is already prefetched).
Restructures the logic to match the sibling hook in
`retrieve-index-from-select-query.ts`, which correctly ANDs `enabled`
with all conditions using an extracted `isValidQueryForIndexing`
variable.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved query validation in index advisor to more reliably handle SQL
query normalization and ensure consistent query processing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Similar to the Advisor, this adds an admonition enabling the user to
disable a public RLS select via dashboard.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Detect public buckets that have removable SELECT policies and show a
contextual warning on the bucket page.
* Let users remove the policy via a confirmation dialog that previews
the removal action.
* Show success/error feedback and automatically refresh storage views
after removal.
* Adjust page layout to surface the warning above the storage explorer.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
This PR moves the client-side "Charge Today" calculation to the backend
- relying on the `preview` endpoint data to show the `Charge Today`,
`Prorated Credits` and `Customer Balance` in the Subscription Upgrade
Preview.
It also includes fields for displaying Tax information in the preview,
only for enabled orgs. Do note that at the moment the Tax Preview will
not change if the address in the Subscription Preview changes, that will
be tackled in a follow-up PR.
## Changes
- Replace client-side charge calculation with backend data: The upgrade
dialog previously computed the prorated credit and total charge locally
(using subscription period timestamps and plan prices). This PR uses the
`upfront_charge` object returned by the subscription preview API
instead.
- Display itemized tax breakdown: When the backend returns tax data, the
dialog now shows a line-by-line breakdown: plan cost → subtotal (if
different) → tax (with rate %) → total charged today.
- Use `tax_status` from the subscription preview to conditionally show
tax details, and display a warning when tax calculation fails.
## Testing
### No taxes - Upgrade from Free to Paid Plan
- With a Free Org with a billing address in Canada or any other
non-enabled jurisdiction, start the upgrade to the Pro Plan
- Assert that only the Charge Today field is shown in the summary
<img width="410" height="298" alt="image"
src="https://github.com/user-attachments/assets/e8c7e12e-833d-41d5-aec3-00092b12782f"
/>
### Taxes - Upgrade Plan
- Update an Org's Orb Customer on the Free or Pro Plan with the
`automatic_tax_enabled: true` flag.
```
curl --location --request PUT 'https://api.withorb.com/v1/customers/external_customer_id/{ORG_SLUG}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: ••••••' \
--data '{
"tax_configuration": {
"tax_exempt": false,
"tax_provider": "numeral",
"automatic_tax_enabled": true
}
}'
```
- Update the Org address to a valid taxable address, like:
```
"address": {
"country": "US",
"line1": "100 Congress Ave",
"city": "Austin",
"state": "TX",
"postal_code": "78701"
}
```
- Assert that the tax information is shown in the preview, including Tax
Rate, Prorated credits (if applicable), Customer balance (if applicable)
and the price of the intended plan.
<img width="465" height="470" alt="image"
src="https://github.com/user-attachments/assets/dd6a7e27-1708-48a8-bbf3-5435e6d582c2"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added itemized breakdown of subscription charges, including plan cost,
unused time credits, subtotal, and applicable taxes.
* Enhanced billing estimates with detailed tax information display.
* **Improvements**
* Updated "Charge today" calculations to reflect real-time preview data
for greater accuracy.
* Improved billing estimate UI layout and clarity with better
organization of charge details.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Bug fix & feature
## What is the current behavior?
Customers with large schemas have trouble running:
pg-meta/{ref}/tables?include_columns=false
## What is the new behavior?
In the webhooks view some users with large schemas could not click a
table name as the underlying query times out. This just adds a light
weight query and fetches the table name
## Additional context
Add any other context or screenshots.
## Summary by CodeRabbit
* **Refactor**
* Optimized table name fetching in the database interface by introducing
an enhanced query mechanism that streams table metadata more efficiently
from the database.
Follow-up to #44451 which added `literal()` escaping to 4 queue message
files. The remaining 5 files in the same directory still use raw string
interpolation.
The create mutation was the biggest gap -- no `literal()` and no
`isQueueNameValid` at all. It could also interpolate `undefined` into
SQL when partition config is missing.
Applied the same pattern from #44451 to all 5 files: import `literal`,
wrap interpolated values. For the metrics query and create mutation,
also used `ident()` for table name references.
## Summary by CodeRabbit
* **Refactor**
* Improved internal SQL query construction for database queue operations
to enhance code reliability and maintainability.
Don't fire the `available-versions` request when `dbRegion` is falsy
(undefined or empty string). Fixes race condition where the request
fires before a region is selected.
## To test
- Confirm no invalid `available-versions` request in the network tab
- Confirm create new project still works
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved database region validation during project creation to
consistently handle empty or undefined values.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
INDATA-193
BACKEND: <https://github.com/supabase/platform/pull/30575>
<img width="1199" height="1005" alt="Screenshot 2026-04-03 at 11 54 29"
src="https://github.com/user-attachments/assets/38e9d676-449f-45c0-9e07-f273312a812f"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Consolidated read replica limit configuration to provide more
consistent behavior across different compute tiers.
* **Tests**
* Added comprehensive test coverage for read replica eligibility checks
and replica limit calculations based on compute tier.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Ever since the update to TypeScript 6, IDE auto-imports are suggesting
"node_modules/package_name/...." rather than the correct "package_name".
This is due to our deprecated bare specifier wildcard in paths,
replacing this with a listing of all bare specifiers we currently
support (while migrating away) to restore auto-import suggestions.
## What
Escapes user-controlled string values before interpolating them into SQL
in `apps/studio/data/database-queues/`.
## Why
Several queue message queries were constructing SQL via direct string
interpolation without sanitization:
| File | Value | Risk |
|------|-------|------|
| `database-queue-messages-send-mutation.ts` | `payload` | **High** —
arbitrary user-provided JSON; a single quote breaks the query and a
crafted payload could execute arbitrary SQL |
| `database-queue-messages-infinite-query.ts` | `afterTimestamp` |
Medium — sourced from a previous DB result, but still unsafe to
interpolate |
| `database-queue-messages-delete-mutation.ts` | `messageId` | Low —
typed `number`, but truncated for safety |
| `database-queue-messages-archive-mutation.ts` | `messageId` | Low —
same as above |
## Fix
- Escape string literals with the standard PostgreSQL approach (doubling
single quotes `'` → `''`) before interpolation
- Wrap numeric `messageId` values with `Math.trunc()` to prevent
floating-point edge cases
- `queueName` was already validated via `isQueueNameValid` regex
(alphanumeric/underscore/hyphen only) — no change needed
Fixes#44375
## Test plan
- [x] Open Queue Messages panel in Studio
- [x] Send a message with a payload containing single quotes (e.g.
`{"key": "it's a value"}`) — verify it sends without error
- [x] Verify pagination still works correctly after fix
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved safety of queue operations by ensuring message IDs, payloads,
timestamps, and queue names are handled securely to prevent injection
and formatting issues.
* Normalized numeric message fields (IDs/delays) for consistent
processing.
* Increased stability and correctness of archive, delete, query, and
send operations; no public APIs were changed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Context
For database extensions, previously dashboard would fire a separate call
just to retrieve the "default schema" for an extension via
`useDatabaseExtensionDefaultSchemaQuery` from the
`pg_available_extension_versions` table (the `schema` from this table
implies where the extension will be installed in)
## Changes involved
Am updating the `useDatabaseExtensionsQuery` to use a custom studio SQL
that will fetch this data in one request via a `LEFT JOIN`, so dashboard
no longer needs to fire a request to `pg_available_extension_versions`
each time we open the `EnableExtensionModal` since all the info we need
is loaded up front.
Have also validated that the cost of the custom studio SQL is low (6.8,
via explain analyze) so performance wise on the project's DB should be
okay.
This will then also allow us to correctly render the "default schema" of
the extensions in the new Install Integration Sheet now that we have
that information up front.
## Misc fix
Also fixed a small issue on the database extensions page whereby if you
searched for an extension that's hidden (e.g pg_tle), there's no "No
results" UI state showing up
<img width="1112" height="319" alt="image"
src="https://github.com/user-attachments/assets/eb488117-2a24-4317-ad73-1d636f9b1bc8"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Per-extension default schema detection surfaced across install flows;
default schema options added to selectors when applicable.
* **Bug Fixes**
* Hidden extensions filtered out earlier so they no longer appear in
lists.
* Install button now correctly disables when required extensions are
missing.
* **Refactor**
* Consolidated extensions metadata retrieval and simplified schema
selection/validation logic; UI text formatting standardized.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The Fly login/auth endpoints were removed from the management API
(supabase/platform#30987). This cleans up the associated studio code and
regenerates the API types.
Note: existing Fly projects are still running, so all `cloud_provider`
guards and Fly-specific UI (disk management, billing, pg_cron warnings,
etc.) are intentionally kept in place.
**Removed:**
- `sign-in-fly-tos.tsx` page
- `organization-by-fly-organization-id-mutation.ts`
- `project-by-fly-extension-id-mutation.ts`
**Other:**
- Regenerated API types to reflect removed endpoints
- Removed stale Fly-related comments in `InstanceConfiguration`,
`ObservabilityMenu`, `ReportsMenu`
- Fixed unrelated optional chaining bug in `SSOConfig.tsx`
## To test
- Check project creation flow still works
- Verify `/sign-in-fly-tos` no longer resolves
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
`useOrgSSOConfigQuery` had an internal plan-based gate
(`canSetupSSOConfig`) that permanently disabled the query for
non-team/enterprise orgs.
The fix removes the redundant plan gate from the query hook, plan-based
access is already controlled upstream via the entitlement check in the
component.
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Bug fix
## What is the current behavior?
The `getNextPageParam` function in
`database-queue-messages-infinite-query.ts` uses `<=` instead of `>=`,
which means pagination never stops. Since the result length is always
less than or equal to the page size, `hasNextPage` is always `true`,
causing infinite API requests when viewing queue messages in Studio.
Resolves#44291
## What is the new behavior?
Uses `>=` to correctly detect when there are more pages, consistent with
every other infinite query in the codebase:
- `database-cron-jobs-infinite-query.ts` uses `>=`
- `users-infinite-query.ts` uses `>=`
- `database-cron-jobs-runs-infinite-query.ts` uses `< PAGE_SIZE` to
return `undefined` (equivalent logic)
## Additional context
One character change: `<=` to `>=` on line 112.
## Context
Resolves https://github.com/supabase/supabase/issues/43548
There's currently an issue with the Table Editor where if you have, for
example, a nullable `text` column with a default value, inserting a new
row and selecting "Set to NULL" doesn't do anything, and saving will
insert the row with the default value
<img width="700" height="258" alt="image"
src="https://github.com/user-attachments/assets/6a284ebb-c346-40a6-9a30-793118844084"
/>
This stems from a legacy logic in the Table Editor whereby we treat
`null` values as "no input" - which is incorrect as `null` values are
also valid values. So the PR here changes a few things to resolve this
properly:
## Changes involved
Main fix:
- `undefined` will be the "no input" value instead, and it'll be the
default value when generating the row object for inserting a new row
- `NULL` or even empty string like `''` will be treated as they are
(valid inputs)
Secondary adjustments:
- (Queue operations) Queueing an insert with no value but default value
is NULL, will show the placeholder as `DEFAULT` instead of `NULL` for
better accuracy in representation
<img width="892" height="96" alt="image"
src="https://github.com/user-attachments/assets/02cf86bf-c17b-4e25-9a8f-17960b1d2575"
/>
- Added a `Set to Default` CTA here, but will only show up if adding a
new row or updating a queued insert row operation, which will set the
value of the input field back to `undefined` for PG to handle it as the
default value
<img width="734" height="208" alt="image"
src="https://github.com/user-attachments/assets/23887c0c-533e-4494-acbe-61309ff5d7c5"
/>
## To test
Verify within the Table Editor (along with queue operation feature
preview)
- For inserting a new row, setting value to NULL and setting value to
Default works
- For updating a row, setting value to NULL works
## Summary
The `connectSection` A/B experiment concluded as a true null (no effect
on activation or any downstream metric after 13 days at 50/50, ~153K
mature orgs). Saxon decided to ship the Connect section as the permanent
experience. This PR removes the Getting Started control variant, the old
Connect modal, all experiment flag gating, and related telemetry types.
## Changes
- Delete `GettingStarted/` directory (5 files: section component, types,
utils, progress hook)
- Delete old `Connect.tsx` dialog modal (replaced by ConnectSheet)
- Remove `connectSection` PostHog flag reads from `Home.tsx` and
`LayoutHeader.tsx`
- Remove `getSectionVisibility()` experiment logic and
`ConnectSectionVariant` type
- Remove `getting-started` from `DEFAULT_SECTION_ORDER`
- Always render `<ConnectSheet />` in header (no more conditional with
old `<Connect />` modal)
- Remove `variant` prop from `ConnectSection` component
- Remove 4 getting-started telemetry event interfaces from
`telemetry-constants.ts`
- Update `mergeSectionOrder` tests to reflect new section order
## Testing
Tested on Vercel preview:
- [x] Project homepage shows Connect section for new projects (< 10 days
old)
- [x] Connect section hidden for mature projects (> 10 days old)
- [x] Header Connect button opens ConnectSheet (not old modal)
- [x] Connect tiles open ConnectSheet with correct tab
- [x] Section drag-and-drop still works without getting-started in the
order
- [x] Existing users with `getting-started` in localStorage order don't
break (mergeSectionOrder strips it)
## Linear
- fixes GROWTH-730
---------
Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
## Context
Related to marketplace related work, just moves the Queues integration
to the new UI (Changes are feature flagged)
<img width="1145" height="584" alt="image"
src="https://github.com/user-attachments/assets/d3245889-597d-44e2-9850-f20907e42056"
/>
Installation is now in a side panel with the intention that it'll just
be a single click to install integrations that involve multiple parts
<img width="400" height="955" alt="image"
src="https://github.com/user-attachments/assets/71903b61-6bd2-486c-903e-b48ae2133887"
/>
## To test
- Verify that you can install the integration and everything else should
be status quo
- Verify that everything should be status quo if the flag is off
## Context
Shifts all remaining dashboard queries into pg-meta so that we
centralize all manually written queries in one place
Having them in packages/pg-meta also allows us to write tests for them
## To test
Just needs a smoke test on
- Role Impersonation
- Lints
- Data API
- Database
- Enumerated Types
- Integrations
- Foreign Data Wrappers
- Vault
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
This is a prototype for private apps UI. There are no endpoints at the
minute, just wanted to see what a potential flow could look like.
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
show the "enable" button if the `GET /auth/v1/admin/custom-providers`
returns 404 (without a json body). this is temporary as I want to enable
the rollout of this feature now, and there could be projects which
didn't get the latest auth server release(should be completed by next
week).
## What is the current behavior?
We only show a generic error message.
## What is the new behavior?
Show custom provider specific message and add CTA to enable the custom
providers (simply trigger a PATCH config request to trigger auth config
updates)
## Additional context
<img width="1454" height="390" alt="image-IPleA6ze@2x"
src="https://github.com/user-attachments/assets/b0cb4df8-2499-4749-900c-b78543a72800"
/>
This error is shown after 2 retries of the `GET
/auth/v1/admin/custom-providers`, would be nice to have if we show this
error message without retries.