145 Commits
Author SHA1 Message Date
Joshen Lim 9aae037dff Joshenlim/fe 4475 fdw update sql to run proper alter statements instead of (#50988)
## Context

Currently for FDWs under integrations, editing an FDW involves tearing
it down then re-creating it - which while conveniently works has a lot
of problems like:
- Blast radius is way bigger than the edit
  - Everything is recreated, including vault secrets
- Silent drops grants/comments/ownership
- Cascades on dependent objects
- Views or functions built on top of foreign tables would get dropped
along with it

Changes in this PR hence updates `getUpdateFDWSql` to diff the current
wrapper state against the form state and generate targeted `ALTER`
statements for only what actually changed

## To test
- [ ] Verify that updating an existing wrapper still works as expected

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Wrapper changes can be saved in place, including server options,
encrypted values, foreign tables, and column definitions.
* Input fields can display placeholder text, and missing server-option
values display their defaults.

* **Improvements**
* Saving is unavailable until encrypted values are ready; a waiting
message appears while they load.
* The edit panel closes after a successful save. Confirmation text
explains that table or column changes may affect dependent
functionality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-29 19:47:57 +08:00
Jordi Enric f0952fdef8 fix(studio): delete only the selected foreign server FE-4462 (#50785)
## Problem

The dashboard lists one row per foreign server, but deleting a row
dropped its foreign data wrapper with CASCADE. When multiple servers
shared a wrapper, deleting one removed all of them.

## Fix

Drop the selected server and its foreign tables. Remove the underlying
wrapper and Vault secret only when no servers still use it. Edits to a
shared wrapper now stop before making changes because the existing edit
flow recreates the underlying wrapper.

## How to test

1. Configure two BigQuery foreign servers that use the same foreign data
wrapper. Delete one from the dashboard.
2. Confirm the other server and its foreign tables still exist and work.
3. Delete the remaining server. Confirm the foreign data wrapper and its
Vault secret are removed.
4. Attempt to edit one of two servers sharing a wrapper. Confirm the
edit fails without removing either server.

Focused pg-meta tests and typecheck pass.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Shared connections are identified in the integrations list, with
guidance for editing them in the SQL Editor. Editing is disabled when a
wrapper is shared, with an explanation shown.
* Deleting a connection removes its foreign tables and removes the
wrapper and Vault secret only when no other connection uses them.
* **Bug Fixes**
* Connection deletion verifies that the selected server still belongs to
the wrapper and reports failures using connection-focused wording.
* Attempts to edit a wrapper used by another connection are blocked with
a clear explanation.
* Connection deletion and confirmation messages now consistently refer
to deleting a connection.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-25 16:49:01 +02:00
Joshen Lim b1a9e072ec Update table editor ilike related comparators to implicitly wrap filter string with % if not provided (#50394)
### Context

For table editor - the `ilike` related comparators expect users to input
a `%` in the filter string, which for non-developers might not be
intuitive.

Hence opting to implicitly wrap the filter string with `%` in the query
when filtering if non provided
<img width="1182" height="755" alt="image"
src="https://github.com/user-attachments/assets/819c39f5-fcbf-4213-95b3-3ad1ee901f47"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved pattern-match filters so bare text values perform contains
matching by automatically wrapping them with wildcards.
* Preserved explicit wildcard patterns using `%` or `_` without adding
additional wildcards.
* Improved handling of empty values for non-text filters while retaining
existing numeric filter validation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-16 14:32:19 +08:00
VaibhavandAndrew Valleteau c427615234 fix(pg-meta): pair composite foreign key columns correctly (#41080)
## TL;DR

Correctly pairs composite foreign key columns when loading table
metadata.

## What's hurting?

The tables introspection query matched every source column in a
composite foreign key with every target column. For `(user_id,
tenant_id) → (id, tenant_id)`, it returned four relationships instead of
the correct two, causing incorrect relationship metadata in the Table
Editor...

## Now fixed

Source and target columns are paired by ordinal position using a lateral
multi-array `unnest`.
Regression coverage now verifies adversarial column ordering, and the
existing performance guard exercises thousands of composite foreign
keys...

PS: local stress test found no performance regression or unexpected
sequential scans.

## Ref

- Closes #41068

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Corrected foreign-key relationship detection for composite keys,
ensuring source and target columns are paired accurately.
* Improved catalog relationship queries to remain within performance
limits for composite-key tables.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
2026-09-10 19:35:52 +02:00
Joshen Lim db0e6b761b Joshenlim/fe 4304 bring database connections out of feature preview (#50107)
## Context

As per PR title - we're bringing Database Connections out of feature
preview and it'll live on the dashboard by default 🙂
Also deprecating the existing Ongoing queries panel which Database
Connections now supercedes.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Database Connections is now available without feature-preview
activation.
* The SQL editor’s “View running queries” option now links directly to
Database Connections.

* **Bug Fixes**
* Query cancellation and session termination now refresh database
activity data.

* **Removed**
* Removed the in-editor ongoing queries panel and its termination
controls.
* Removed the Database Connections promotional banner, preview
messaging, settings, and related telemetry.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-08 17:26:24 +08:00
CharisandJoshen Lim 2ac052752a fix(pg-meta): fix invalid SQL when setting column default to NULL (#50097)
## Summary

- Fixes invalid SQL generation when setting a column's default value to
NULL through Studio's Table Editor
- The bug occurred because raw `null` values bypassed literal
serialization in the SQL builder
- Added special case handling in both `create()` and `update()`
functions to use `literal(null)` regardless of format

## Details

Setting a column's default to NULL via the "Set as NULL" suggestion in
Studio generated invalid SQL: `ALTER TABLE ... ALTER COLUMN ... SET
DEFAULT ;` (missing the NULL keyword). This was caused by
`default_value` being JS `null` and bypassing the literal()
serialization function when `default_value_format === 'expression'`.

The fix ensures that when `default_value === null`, we always use
`literal(null)` to produce the correct `SET DEFAULT NULL` clause.

## Test plan

- New regression test in `packages/pg-meta/test/columns.test.ts`
("update column default value to NULL via expression format") verifies
the fix by:
  - Creating a text column with a literal default
- Updating it using `default_value_format: 'expression', default_value:
null` (exact payload from Studio)
  - Asserting the column's default value is null
- All 58 tests in `packages/pg-meta/test/columns.test.ts` pass
- TypeScript check (`tsc --noEmit`) passes

Fixes FE-4343

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Fixed column creation and updates so explicitly setting a default
value to `NULL` correctly preserves the `DEFAULT NULL` clause.
- Ensured setting a column default to `NULL` through expression-based
editing is reflected accurately when column details are retrieved.

- **Style**
- Improved the column editor’s suggestion menu layout and spacing for
clearer readability.

- **Tests**
  - Added coverage for updating a column default to `NULL`.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-08 16:08:24 +08:00
Joshen Lim 75b90c5de1 Check the session's backend_start for cancelling or terminating sessions (#48929)
## Context

Related to database connections - specifically for cancelling queries or
terminating sessions

PIDs can be re-used, so a more accurate check is to use both PID and
`backend_start` to uniquely identify the session to cancel or terminate

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved query cancellation and session termination reliability by
verifying the active database session before taking action.
* Prevented actions from affecting a different session that reused the
same process ID.
* Added clearer guidance to refresh when a session has changed or is no
longer available.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-12 10:14:59 +07:00
Joshen Lim cdfb5b310f Add cancel query action for database connections (#48922)
## Context

Related to Database Connections
- Adds a "cancel query" action for "active" sessions using
`pg_cancel_backend`
- Gentler alternative as the connection stays alive, unlike terminating
the session
- Not applicable for queries idle in transaction as there's no query
running (Disabled in this case)
- Rename "Terminate" to "Terminate session"
- Rename "Abort query" to "Terminate session"

For active queries:
<img width="220" height="135" alt="image"
src="https://github.com/user-attachments/assets/d6ca790d-bb6a-4582-8554-24431388483a"
/>

For idle in txn queries:
<img width="433" height="135" alt="image"
src="https://github.com/user-attachments/assets/615d0651-9f5b-4efc-a5cf-72f93727aa91"
/>

Also updating confirmation modal for terminating session CTA:

For active queries:
<img width="407" height="301" alt="image"
src="https://github.com/user-attachments/assets/e5f56764-11b9-4c10-ba01-d7547aaec872"
/>

All other queries:
<img width="410" height="212" alt="image"
src="https://github.com/user-attachments/assets/8631633f-5d4a-40a7-b089-6980a5180219"
/>



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## New Features
- Added a separate **Cancel query** action for active database queries.
- Added **Terminate session** to close connections and roll back active
transactions.
- Added safeguards based on query activity and permissions.
- Added confirmation guidance for active queries, including cancellation
options.
- Added loading, success, and error feedback for query cancellation and
session termination.
- Added telemetry for query-cancellation actions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-12 09:56:49 +07:00
Charis ec64135f9d perf(pg-meta): scope column privileges query to a single table (#48553)
## 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?

Performance improvement

## What is the current behavior?

The column privileges page in Studio only ever renders one table, but
the underlying query still `aclexplode`s every column in the whole
schema and filters the result client-side.

## What is the new behavior?

Adds a scoped SQL path that prunes `pg_class`/`pg_namespace` to the
requested schema+table before exploding ACLs, gated behind the
`pgMetaScopedIntrospection` flag, with a plan-guard test asserting
`pg_class`/`pg_attribute` stay index-driven. Studio's query hook and
cache keys now thread the selected table through so column-privilege
invalidation and cold-load races are scoped correctly, and the page
fetches per-table instead of per-schema.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Column privileges are now scoped to the selected schema and table for
more accurate results.
* Changing schemas automatically updates the table selection and
refreshes the displayed privileges.
* Privilege updates now refresh only the relevant schema, table, and
column data.
* Loading states are handled more accurately when no table is selected.

* **Bug Fixes**
* Improved consistency between scoped and unscoped column privilege
results, including table-, column-, and grant-option privileges.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-31 15:26:37 -04:00
Alaister YoungandAlaister Young a06eb5f26f [FE-3724] feat(studio): add enable cleanup button to cron jobs page (#48200)
Adds a standalone **Enable cleanup** button to the Cron Jobs page header
so users can schedule the daily `delete-job-run-details` cleanup job
proactively — previously this was only reachable inside the conditional
"table too big" overflow dialog. Addresses
[FE-3724](https://linear.app/supabase/issue/FE-3724/enable-pg-cron-cleanup-job-from-ui-and-api)
(the UI half; the Management API half needs platform-side work).

**Added:**
- `Enable cleanup` button in the cron jobs header (left of Refresh),
hidden while the existence check loads and whenever a
`delete-job-run-details` job already exists
- Confirmation dialog with a retention-period select (defaults to 7
days), live SQL preview, and telemetry
(`cron_job_cleanup_enable_button_clicked` with `origin` +
`retentionInterval`)
- Component tests (MSW) for visibility gating and the schedule/cancel
flows
- E2E regression test for the full schedule → delete → button-reappears
cycle

**Fixed:**
- Name-based `useCronJobQuery` lookup: the `queryFn` dropped the `name`
param, and a not-found job returned `undefined` (rejected by react-query
v5) — now passes `name` through and returns `CronJob | null`
- Cache invalidation gaps: create/delete now invalidate the whole
cron-jobs prefix (list, count, job details), so the footer count updates
after create/delete and the button reappears after the cleanup job is
deleted. The schedule mutation deliberately invalidates only the
existence check + count (see inline comment)
- Pre-existing e2e leak: the cleanup-workflow test left
`delete-job-run-details` scheduled; it now cleans up after itself

## Screenshots

| Header button | Dialog |
| --- | --- |
| <img width="890" height="325" alt="Screenshot 2026-07-22 at 9 44
40 PM"
src="https://github.com/user-attachments/assets/966cd640-d8a6-4c8f-92e7-73151bf4de9c"
/> | <img width="512" height="461" alt="fe3724-dialog"
src="https://github.com/user-attachments/assets/6be1785f-cc7e-4048-a648-9ef260b0949f"
/> |

## To test

- Go to a project's Integrations → Cron → Jobs with pg_cron enabled and
no `delete-job-run-details` job → the `Enable cleanup` button shows next
to Refresh
- Open the dialog, switch retention intervals → the SQL preview updates;
confirm → success toast, the job appears in the grid (`0 12 * * *`), and
the button disappears without a reload
- Delete the `delete-job-run-details` job from the grid → the button
reappears without a reload
- Create then delete any other job → the footer `Total: N jobs` count
updates both ways without a reload
- Regression: with the high-query-cost banner forced (or via the e2e),
the overflow dialog's "Schedule cleanup job" step still shows its
success state — the dialog must not close mid-flow

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **New Features**
* Added an **Enable cleanup** action to the Cron Jobs tab header,
including a retention selector and SQL preview.
* Enabling schedules the daily cleanup, shows a success toast, updates
the grid, and hides the enable button; **Cancel** closes the dialog
without scheduling.

* **Bug Fixes**
  * Improved cron job lookup to work by name when needed.
* Refreshed related cron job data more reliably after scheduling and
deletion.

* **Telemetry**
  * Added an event for cleanup enable button clicks.

* **Tests**
* Added component and Playwright coverage for
enable/cancel/schedule/delete and cleanup banner flows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-07-24 16:43:00 +08:00
Andrew ValleteauandClaude Fable 5 6c6a721cb7 fix(pg-meta): scope remaining O(catalog) introspection queries behind pgMetaScopedIntrospection (#48148)
## 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 (performance), follow-up to #47894, plus regression-guard tests.

## What is the current behavior?

#47894 scoped the Table Editor and entity-definition introspection
queries, but four more `@supabase/pg-meta` query families still do
O(catalog) work per request. On a production project with a very large
catalog (hundreds of schemas, ~465K `pg_constraint` rows) they run 5 to
55 seconds each, trip the 58s `statement_timeout`, and spill sorts to
temp files. During a recent "DB CPU > 85%" incident on such a project,
24 of 27 active backends were running these queries concurrently.

1. **`tables.retrieve()` (single-table lookup by name+schema or id)**:
the `tables`/`columns` CTEs scan the whole catalog (`pg_class`,
`pg_constraint`, `pg_index`, all of `pg_attribute`, per-table sizes) and
the one-table predicate is applied only on the outer select. Same bug
class #47894 fixed for the OID-based table editor query; this sibling
path never got the treatment. It accounted for 94 of the 96
statement-timeout cancellations in the incident.
2. **Types listing**: the `t_enums` and `t_attributes` subqueries
aggregate the entire `pg_enum` and every composite relation before the
wrapper's schema filter applies.
3. **Table privileges**: `aclexplode` + double `pg_roles` join + GROUP
BY over every relation in the database; schema/OID filters applied only
after aggregation, in both `list()` and `retrieve()`.
4. **Row counts**: `getTableRowsCountSql` treats `reltuples = -1`
(never-analyzed table) as "small table, run exact count(*)". A freshly
bulk-loaded multi-million-row table times out on every Table Editor
pagination render.

Two Studio-side amplifiers turned one slow query into a sustained load
storm:

- `useTableQuery` (behind `tables.retrieve()`) mounts once per visible
foreign-key grid cell via `ForeignKeyFormatter`, so a single Table
Editor view fires ~20 concurrent copies against the FK target table. A
timed-out query caches nothing, and TanStack retries errored no-data
queries on every observer mount by default, so scrolling kept re-issuing
the 58s scan.
- `useTableApiAccessQuery` fetched table privileges for the entire
database and filtered down to one schema client-side.

## What is the new behavior?

**pg-meta (all behind the existing `pgMetaScopedIntrospection` flag,
same rollout mechanism as #47894; `scoped: false` keeps serving the
current SQL):**

- `tables.retrieve()`: the identifier is resolved to a scalar
`targetOid` init-plan and pushed into the base scan, primary-key,
relationships (both FK directions kept: `conrelid` or `confrelid`) and
columns CTEs. A materialized `target` CTE was deliberately avoided: it
acts as an optimization barrier and forces the very seq scans being
removed.
- Types: filter `pg_type`/`pg_namespace` first, then compute
enums/attributes per surviving row via correlated index-scan subqueries
(`pg_enum(enumtypid, enumsortorder)`, `pg_attribute(attrelid, attnum)`).
- Table privileges: schema/OID predicates injected into the base WHERE
before `aclexplode`/GROUP BY for `list()` and `retrieve()`.
- Row counts: `reltuples = -1` is treated as "unknown" and gated on
physical size via `pg_relation_size` (a cheap stat call; `relpages` is
equally stale pre-vacuum). At or below `THRESHOLD_ESTIMATE_BYTES`
(~10MB, derived from `THRESHOLD_COUNT` at a conservative ~200 bytes/row)
the exact count runs as before: fast by construction, and it avoids
bogus estimates since Postgres floors never-vacuumed heaps at 10 pages,
so an empty table would otherwise report ~2K estimated rows. Above the
gate the count routes through the EXPLAIN-based
`pg_temp.count_estimate`, or returns `-1`/`is_estimate = true` in
read-only contexts where the temp function cannot be created. The scoped
branch embeds the estimated select via `literal()` instead of legacy's
apostrophe-only escaping, so it stays correct under
`standard_conforming_strings = off`. `enforceExactCount` unchanged.

**Studio:**

- The flag decision is contained in the data layer instead of
prop-drilled: a small imperative accessor
(`apps/studio/data/scoped-introspection.ts`) is hydrated from `useFlag`
via a one-line `useSyncScopedIntrospection()` call in `DefaultLayout`,
and the query functions read it internally when building the pg-meta
SQL. `DefaultLayout` is shared by both the Next and TanStack router
trees; hydrating from `_app.tsx` alone would leave TanStack-served pages
permanently unscoped since `routes/__root.tsx` mounts its own flag
provider. Cold loads cannot race the flag: the query functions await a
readiness promise that resolves only after the sync hook has hydrated
the accessor with a loaded flag store (immediately on self-hosted where
flags are disabled; a 5s safety net armed lazily on the first `ready()`
call - not at module import, which would let the timer expire before a
project page ever mounts - bounds genuine ConfigCat outages). No
component threading, no query-key changes (remaining tradeoff,
documented in the module: a mid-session flag flip can serve stale-keyed
caches until refetch, fine for a session-stable rollout flag). #47894's
existing threading is left as-is and gets deleted together with the flag
in the cleanup PR. Also fixes the previously-missing `scoped`
pass-through in `getTableRowsCount`.
- Flag-independent hardening: `useTableQuery` now sets `retryOnMount:
false`, `refetchOnWindowFocus: false` and `staleTime: 5min`. Errored
(timed-out) queries no longer refire on every grid cell remount, while
stale successful metadata still revalidates on mount after `staleTime`.
- `useTableApiAccessQuery` now passes `includedSchemas: [schemaName]`;
the client-side filter stays as a safety net.
- The rows-count query is `enabled`-gated on the permission check
settling, so a transiently-false `canSQLAdminWrite` can no longer cache
a read-only `-1` count for a writable user (read replicas short-circuit
synchronously as before).

**Regression guards (extending the #47894 infrastructure):**

- Execution-based scoped-vs-legacy equivalence tests for all four
queries: both variants run against the test database and are compared
with raw `toEqual` - no normalization, ids included (types across 6
option combos, privileges incl. multi-grantee + PUBLIC,
`tables.retrieve` for both identifier branches, row counts for every
case where the two paths must agree). Two documented exceptions where
only the LEGACY side is sorted, because a de-normalized diagnostic run
proved legacy emits genuinely plan-dependent order there (an
adversarial-FK fixture shows it is neither oid, name, nor creation
order): the `types.list` outer row order (scoped adds `order by t.oid`;
legacy has no ORDER BY) and the `tables.retrieve` relationships array
(scoped orders by `constraint_name` + column-name tie-breakers - a
composite two-column FK expands to 4 entries sharing one
constraint_name). Everything else (privileges via `aclexplode` over the
same relacl, columns by `ordinal_position`, primary keys by `indkey`
order, enums by `enumsortorder`) is byte-identical between the two paths
with no test-side help. The one intentional value divergence,
never-analyzed tables above the size gate where legacy's exact count is
the timeout bug itself, is asserted explicitly as a divergence.
- Plan-guard budgets for every scoped query against the stress catalog
(extended with 200 enums + 200 composite types). Residual seq scans are
justified in-budget: `pg_constraint` max 2 (no index on `confrelid`),
`pg_attrdef` max 1, `pg_authid` max 2 (scales with role count, not
schema count).
- Legacy templates carry a FROZEN do-not-edit marker (they must keep
matching production behavior until the flag cleanup deletes them); the
ordinary test suite runs against the legacy default, so behavioral drift
there fails regular tests.

### Validation

- pg-meta: typecheck clean; the affected suites (types,
table-privileges, tables, rows-count, catalog-plan-guard) pass in full.
- Cross-version: the scoped-vs-legacy equivalence and rows-count
behavioral suites were validated on PostgreSQL 14, 15, and 17 (identical
results on all three). Two version-marginal planner choices surfaced on
17 (`pg_type` / `pg_class` seq scan vs full-index bitmap for per-schema
listings, both structurally unavoidable without an index leading on the
namespace column) and are carried as justified plan-guard budget
entries. A full 468-test suite run sequentially: 452 passed, 16 failures
verified environmental (13 timeouts in an untouched file that passes
27/27 in isolation on the marathon-run cluster, 3 cluster-global role
collisions from container reuse).
- Studio: `pnpm --filter studio typecheck` clean; 39/39 tests across the
touched data hooks; eslint clean on touched files.

### Rollout

Same staged ConfigCat rollout as #47894 via `pgMetaScopedIntrospection`
(user-email targeting first, then percentage, then 100%). The
`useTableQuery` hardening and the API-access schema scoping ship
unflagged (behavior-safe). Gate before percentage rollout: functionally
verify the FK popover/selector UX under the new
`staleTime`/`retryOnMount` settings (a just-edited FK target must not
look stale anywhere Studio does not already refetch on save). Once fully
rolled out, the legacy templates and flag get deleted together with
#47894's in one cleanup PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 08:07:08 +02:00
Vaibhav 2e12cdc2e1 fix: empty search_path (#48151)
## TL;DR
Restores handling for functions with `search_path` set to `''` editing
them in the UI was failing with a Postgres `zero-length delimited
identifier` error since the SafeSql refactor dropped the empty-string
sentinel conversion

## ref
- closes #48149


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Preserved empty `search_path` configuration values when updating
database functions.
* Prevented empty configuration values from being altered or lost during
function updates.

* **Tests**
* Added coverage verifying that function definitions can be updated
without changing an existing empty `search_path` setting.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-21 15:34:50 +00:00
Joshen Lim c7803b8b9b Chore/add sessions database connections (#48094)
## Context

Initial work for Top for Postgres - adds a "Sessions" section under a
new Observability segment "Database Connections"
NOTE: All the copywriting and naming might change - not sure what's an
ideal title for this
We'll also be iteratively building on top of this UI, adding more
actionable signals instead of just information
Changes are featured flagged, off for public

- This would essentially replace the "View ongoing queries" in the SQL
Editor by providing a dedicated UI
  - It checks against `pg_stat_activity` as per the ongoing queries UI
- We'll also subsequently deprecate the "Ongoing queries" UI in the SQL
editor
- Defaults into a "live mode" where the data is refreshed every 3
seconds via long-polling
<img width="983" height="474" alt="image"
src="https://github.com/user-attachments/assets/16402fe4-0b53-4f9e-9342-cdda26e3778a"
/>
- Supports filtering by state  
<img width="374" height="282" alt="image"
src="https://github.com/user-attachments/assets/562f8fbe-2dc6-48e7-8ec0-de7ffb8348d1"
/>
- Users can also terminate queries through here
<img width="247" height="164" alt="image"
src="https://github.com/user-attachments/assets/23a639dc-8f96-473a-a823-605b0bab02ee"
/>





<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

# Release Notes

* **New Features**
* Added an Observability **Database Connections** page with a live
**Sessions** activity table (state/roles filtering, blocked-by details,
session duration, and per-session termination with confirmation).
* Included a **Live/Pause** toggle to control automatic refresh (~3
seconds).

* **Enhancements**
* Improved Reports selection filtering: supports optional option
quantities, better popover styling, sorted apply behavior, and shows
quantity inline.
* Query performance duration formatting now supports configurable
decimal precision.
  * Tooltips can now render richer content (string or React node).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-21 16:52:03 +08:00
Ivan Vasilov 24ce0ba5f8 chore: migrate repo to pnpm v11 (#48033)
## 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?

Chore / dependency tooling update.

## What is the current behavior?

The repo is pinned to pnpm 10.24.0. Closes
https://linear.app/supabase/issue/FE-3673/migrate-the-repo-to-use-pnpm-v11.

## What is the new behavior?

The repo is pinned to pnpm 11.13.1, pnpm v11 workspace settings are
migrated to `allowBuilds`, and the Studio Dockerfile installs pnpm
11.13.1.

## Additional context

Validated with `CI=true mise exec node@22 -- pnpm install
--frozen-lockfile`, `mise exec node@22 -- pnpm run typecheck`, and `mise
exec node@22 -- pnpm run lint`; full Prettier check still fails on
existing generated docs/router files outside this migration.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Updated tooling requirements (pnpm **11.13.1**, Node **>=22.13**) and
aligned container build tooling accordingly.
* Adjusted package manager behavior (scoped registry override, update
notifications disabled) and workspace build/engine validation settings.

* **Maintenance**
* Updated `clean` scripts across apps/packages to remove only
build/cache artifacts (no longer delete installed dependencies).
* Reduced Turbo `clean` task output to **errors-only** for cleaner logs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-20 12:57:42 +02:00
Andrew ValleteauandClaude Fable 5 768ea1001b fix(studio): scope table editor introspection CTEs to target table OID (#47894)
## 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 (performance), plus a regression-guard test suite and docs.

## What is the current behavior?

Studio's introspection queries in `@supabase/pg-meta` do `O(catalog)`
work for per-table requests. On databases with very large catalogs
(hundreds of thousands of relations/constraints — real deployments reach
this) they take tens of seconds per dashboard interaction, trip
`statement_timeout`, and create heavy CPU/memory pressure when several
tabs open concurrently. Two instances of the same bug class:

**1. Table Editor query (`getTableEditorSql`)** — fetches metadata for
ONE table by OID, but five catalog scans are unscoped and only filtered
at the top-level join:

- `primary_keys` CTE — scans all of `pg_index` (`where i.indisprimary`)
- `index_cols` CTE — scans all unique indexes
- `relationships` CTE — scans every FK in `pg_constraint` (and is
scanned twice by the two subplans)
- `uniques` subquery (inside `columns`) — scans all single-column unique
constraints
- `check_constraints` subquery (inside `columns`) — scans all
single-column check constraints

The planner cannot push the outer join qual into grouped / `distinct on`
subqueries, so each is computed over the full catalog and thrown away.
`tables-paginated.ts` was previously rewritten to avoid exactly this
pattern; the single-table query never got the same treatment.

**2. Entity definitions (`getTableDefinitionSql` /
`getEntityDefinitionsSql`)** — the vendored `pg_get_tabledef` plpgsql
function scans the entire `information_schema.columns` view once **per
column** (plus `information_schema.tables` once per call) just to decide
whether a name needs double-quoting — a pure string property of a name
it already holds — and its per-index partial-index lookup casts
`relnamespace::regnamespace::text` across every `pg_class` row. On a
12K-table catalog this makes a single entity's DDL cost ~3.7s and a
default 100-entity definitions page ~6 minutes.

## What is the new behavior?

**Fix 1 — scope the Table Editor CTEs to the requested OID** (`id` is
validated non-null and interpolated via `literal()`, same as the
existing `base_table_info` filter):

- `primary_keys` / `index_cols`: `and i.indrelid = <id>`
- `relationships`: `and (c.conrelid = <id> or c.confrelid = <id>)`
- `uniques` / `check_constraints`: `and conrelid = <id>`

Semantics are unchanged: the top-level select already filtered every CTE
to the target table, so rows for other tables were computed and
discarded. The `pg_index`/`pg_constraint` lookups become index scans
returning a handful of rows. One residual scan is structural: PostgreSQL
has no index on `pg_constraint.confrelid`, so the incoming-FK half of
`relationships` is a single filtered seq scan of `pg_constraint` — still
one cheap pass instead of materializing every FK row twice.

**Fix 2 — remove the O(catalog) scans inside `pg_get_tabledef`**: the
information_schema uppercase checks are replaced with direct regex tests
on the name in hand (preserving the original's `quote_ident` behavior
for schemas that need quoting), and the partial-index lookup is scoped
by the already-resolved table OID. Original statements are kept as
comments, matching the vendored file's convention.

**Regression guard** — so this bug class stays out:

- `test/db/stress-catalog.ts` builds a synthetic catalog (default 2,000
tables with PKs, unique + check constraints, FK chains and an FK hub;
`PG_META_STRESS_TABLES` scales it to incident size).
- `test/db/plan-guard.ts` provides `EXPLAIN (ANALYZE, FORMAT
JSON)`-based budget assertions: a query's plan may only seq-scan a
scaling catalog if its budget entry carries a written structural
justification (e.g. no index on `pg_constraint.confrelid`; no index on
`pg_class.relnamespace` for per-schema listings), plus a per-query time
bound (the only guard available for opaque plpgsql internals like
`pg_get_tabledef`).
- `test/sql/studio/catalog-plan-guard.test.ts` applies budgets to the
hot-path studio queries: table editor, constraints, FK listing, entity
types, tables-paginated, columns, indexes, table/entity definitions,
views. Reverting either fix makes the suite fail immediately with the
offending scans listed.
- `test/sql/studio/table-editor.test.ts` (new — none existed) asserts
the Table Editor query's semantics: primary keys, unique indexes, both
FK directions, `is_unique`, check definitions, column comments.
- A new package `README.md` documents the plan-guard budget entry as a
requirement for any new introspection query.

### Validation (synthetic 12,000-table catalog, PostgreSQL 17.6)

- **Output equivalence, fix 1:** for 12 relation types (regular,
composite PK, partitioned parent + partition, view, materialized view,
constraint-free table, FK hub/chain/tail, and a fixture with
enums/domains/generated/identity columns and duplicate check
constraints), the `entity` jsonb from the old and new query is
byte-identical.
- **Output equivalence, fix 2:** byte-identical DDL across 13 fixture
combinations (serial/identity/generated/array columns, case-sensitive
and keyword names, mixed-case schemas, partitions, unlogged +
reloptions, partial/expression indexes, external PK/FK/comments/trigger
variants).
- **Performance, fix 1:** Table Editor query `EXPLAIN ANALYZE` ~1,630ms
→ ~30ms (~50×); the gap grows with catalog size since the old query is
O(catalog) per call.
- **Performance, fix 2:** single entity definition 3,672ms → 63ms; a
100-entity definitions page ~6min → 0.87s. The plan-guard bound for
`getEntityDefinitionsSql` tightens accordingly from 15s/25 entities to
3s/100 entities (330ms measured at default test scale).

Verified locally: `catalog-plan-guard` (12 tests), `table-editor`,
`tables-paginated` (16 tests) pass; `typecheck` clean.

### Rollout

Per review, the new behavior ships **dark** behind the
`pgMetaScopedIntrospection` ConfigCat flag (default off = legacy SQL,
kept as full duplicated templates in pg-meta and verified byte-identical
to the pre-PR queries). Studio reads the flag in the query hooks and
threads it through (flag state is part of the React Query keys). The
rollout is staged in the ConfigCat dashboard via user-email targeting
(like every other ConfigCat flag): target the reporting user's email
first, then a percentage rollout, then 100%. Server-side AI callers of
`getEntityDefinitionsSql` stay on the legacy path. Once fully rolled
out, delete the legacy templates + flag in a cleanup PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Closes: PGMETA-122

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Improved table editor SQL to correctly scope primary keys, indexes,
uniques, checks, and relationships to the selected table.
- Optimized table definition SQL to reduce unnecessary catalog scanning
for uppercase-name detection and partial-index detection.

- **Tests**
- Added SQL generator tests for table editor metadata (keys, indexes,
relationships, comments, and constraints).
- Added catalog query plan guard coverage with a stress catalog and
EXPLAIN-based scoping/performance budgets.

- **Documentation**
- Expanded documentation on catalog query plan safeguards and how to
keep new introspection queries properly scoped.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:16:11 +02:00
a3f2c4ffc1 chore(deps): upgrade to TypeScript 7 (native compiler) (#47757)
Upgrades the monorepo to TypeScript 7.0.2, released 2026-07-08. `tsc` is
now the native Go compiler
([announcement](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/))
— full turbo typecheck drops from ~56s to ~19s locally.

TS 7.0 ships **without a programmatic API** (it lands in 7.1), so this
uses Microsoft's recommended side-by-side setup: the `typescript` name
resolves to `@typescript/typescript6` (the 6.0 API republished) for API
consumers — typescript-eslint and Next.js build typechecking — while
`@typescript/native` (the real `typescript@7.0.2`) owns the `tsc` bin
that typecheck scripts run. Exactly one version of each is in the
lockfile; nothing imports the native package as a library. When 7.1 +
tool support lands we can collapse back to a single `typescript` dep in
the catalog.

**Changed:**
- `pnpm-workspace.yaml`: catalog aliases for `typescript` /
`@typescript/native`
- 17 package.json files: `@typescript/native` added beside each
`typescript` dep so every package's `tsc` is the native binary
- `apps/studio/tsconfig.json`: exclude `dist/` (gitignored build output)
from typechecking

**Fixed** (real type errors TS 6 under-reported):
- `packages/ui-patterns` CodeBlock: `borderLeft: null` → `undefined`
(`CSSProperties` doesn't accept null)
- `apps/www` CodeBlock: removed a JSX `@ts-ignore` comment that tsgo
doesn't honor and fixed what it masked (untyped `.js` theme objects,
possibly-undefined highlighter children)

⚠️ **Merge timing:** the new packages are inside pnpm's 3-day
`minimumReleaseAge` window until ~July 11. Installs from the committed
lockfile are unaffected (resolution is skipped), but anything that
forces a re-resolution before then will fail — hold off merging until
the window passes.

Note for editors: the compat package has no `lib/tsserver.js`, so VS
Code's "Use Workspace Version" won't work — use the bundled TS or the
TypeScript Native Preview extension.

## To test

- `pnpm install && pnpm typecheck` — all 15 tasks green, and
`./node_modules/.bin/tsc --version` prints 7.0.2
- `pnpm lint --filter=studio` — typescript-eslint still parses (resolves
the 6.0 API)
- `pnpm build --filter=design-system` (or any Next app) — Next's
tsconfig validation and build typecheck still work
- CodeBlock rendering on www (syntax highlighting, line highlights
with/without border) — the two fixes are behavior-neutral but worth an
eyeball

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements / New Features**
* Enhanced TypeScript tooling support across the workspace for smoother
development builds and checks.

* **Bug Fixes**
  * Code blocks render more reliably when content is empty or missing.
  * Highlighted code line styling applies more consistently.

* **Maintenance**
* Studio TypeScript builds now avoid including generated output (such as
`dist`) during compilation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-07-09 14:07:17 +02:00
Joshen Lim f34fdd6c8f Skip using count estimate function for retrieving row counts if in read only context (#47761)
## Context

Currently when retrieving row counts of a table in the Table Editor,
we're using a `COUNT_ESTIMATE` pg function
([ref](https://github.com/supabase/supabase/blob/master/packages/pg-meta/src/sql/studio/database/get-count-estimate.ts#L5))
to retrieve an estimate (instead of checking `pg_class` -> `reltuples`)
as that would theoretically provide a more accurate representation.

However, in a read only context, that function can't be used - users
will run into `cannot execute CREATE FUNCTION in a read-only
transaction`, so we need to fallback to just checking `pg_class` in this
scenario.

The logic's already set up as we were previously looking into allowing
users to use a read replica to power the dashboard, but we also need to
consider members with read-only roles within the organization, so this
PR updates the logic a little to factor that in.

## To test

- [ ] With a read-only role, open the table editor and verify that we're
not using the count estimate function to retrieve the table row counts

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Updated the invite member dialog to open in a larger size for better
usability.

* **Bug Fixes**
* Improved table row count behavior so it now respects read-only access
and permission limits more reliably.
* Count estimates should now be shown more consistently across different
database contexts.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-09 18:19:39 +08:00
Joshen Lim 4901f081e5 Migrate remaining requests to pg-meta API to use query endpoint (#47758)
## Context

Migrates the remaining API requests to the pg-meta endpoint to use the
query endpoint directly with the SQL from the pg-meta package. This
touches the following:
- policies
- publications
- triggers
- views
- materialized views
- types

## To test
Just need to verify that we're still fetching the data correctly on
these pages
- Database policies
- Database publications
- Database triggers
- Database tables (views + materialized views)
- Database types

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved and stabilized loading of database metadata (views, triggers,
RLS policies, publications, materialized views, and enum types),
including more reliable schema-scoped filtering.
* Updated policy loading behavior and related UI queries to consistently
use schema arrays, improving cache correctness and consistency.
* **Tests**
* Updated end-to-end test synchronization to wait for the correct
metadata responses using more specific request identifiers.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-09 17:09:03 +08:00
9af6e65df4 fix(studio): DOM-nesting hydration errors, ghost deleted-snippet nav, and migrations query 400s (#47667)
App-level fixes that reproduce on BOTH the Next and TanStack builds —
split out of #47657 (which stays TanStack-only) for reviewability. All
were found by a full-site click-through of the dashboard.

## Invalid HTML nesting (React 19 "will cause a hydration error" console
errors)

- **FormLayout description rendered in a `<p>`**
(`packages/ui-patterns`): consumers pass arbitrary JSX (the RowEditor's
`created_at` timezone note passes a `<div>` with `<p>`s) →
`<p>`-in-`<p>` / `<div>`-in-`<p>`. Container is now a `<div>` with
identical classes (Tailwind preflight makes them render the same).
- **Switch toggles nested inside Tooltip trigger buttons**
(button-in-button) in ColumnEditor ("Allow Nullable" + "Is Unique"),
ExtensionRow, and PublicationsTableItem → repo-standard `TooltipTrigger
asChild` + `<div>` wrapper.
- **Saved log queries rendered a `<div>` directly inside `<tbody>`**
(`/logs/explorer/saved`) → rows are now proper `<tr><td colSpan>`
wrappers; the component itself is untouched (it's valid in its sidebar
usage).
- **Nested anchors in observability metric cards**: a card-level
`<Link>` wrapped MetricCard's "More information" `<Link>` (identical
URLs) → the chevron affordance renders as a `<span>` when no `href` is
passed; clicks bubble to the card link, tooltips preserved.
Design-system standalone usage unaffected.
- **`objectFit="cover"` passed to modern `next/image`** on the featured
integration card (unknown-prop warning) — the className already had
`object-cover`; prop dropped.

## Ghost dead-snippet after deletion

Deleting the active SQL snippet left its id in `useDashboardHistory`
(`history.sql`), so the "SQL Editor" nav item navigated to
`/sql/<deleted-id>` — content fetch 404s, no editor pane renders, and a
phantom tab reappears. Fixed both ends: delete flows now purge dashboard
history (and the tabs store clears a stale `previewTabId`), and
`/sql/[id]` treats a snippet 404 as "clean up + `router.replace` to
`/sql/new` + toast" instead of rendering the dead state. Unit tests for
the store/history cleanup.

## `pg-meta` migrations query 400s on every project load

`ActivityStats` on project home runs the migrations list query, whose
SQL was a bare `select * from supabase_migrations.schema_migrations` —
that table only exists once a migration has run, so every other project
logged a failed `?key=migrations` request on every load (visible in
production consoles too). The SQL is now guarded with `to_regclass` +
`query_to_xml` (same pattern as the advisor lints' `storage.buckets`
guard), returning zero rows instead of erroring; legacy version-only
tables still work. Tested against real dockerized Postgres (absent
table, populated ordering, special chars, legacy schema) + MSW hook
tests.

Found and verified via /test-supabase-local (browser click-through +
console audit on both builds).

## To test

Console must stay free of React DOM-nesting errors ("cannot be a
descendant of" / "cannot contain a nested") on each surface:

1. Table editor → Insert row panel (`created_at` field renders its
timezone note) and Edit column panel ("Allow Nullable"/"Is Unique"
tooltips still hover).
2. `/database/extensions` and `/database/publications` → toggle switches
render, tooltips hover.
3. `/logs/explorer/saved` (with ≥1 saved query) → rows render full-width
inside the table, hover shows Actions.
4. `/observability` → no nested-anchor error on load; card body click
and the chevron both navigate; label help-icons still show tooltips.
5. `/integrations` → no `objectFit` unknown-prop warning; featured card
images still cover.
6. **Ghost snippet**: open a SQL snippet → delete it via the sidebar →
click the "SQL Editor" nav item → lands on `/sql/new` (no phantom tab,
no 404 content fetch). Direct-load `/sql/<random-uuid>` → toast +
redirect to `/sql/new`.
7. **Migrations 400**: load project home with a project that has never
run a migration → the `pg-meta/<ref>/query?key=migrations` request
returns **200** with `[]` (previously a 400 on every load). Database →
Migrations still lists real migrations when they exist.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **Bug Fixes**
* Deleted SQL snippets are fully removed from dashboard history and
stale editor/tab state; users are redirected with a toast.
  * Closing preview tabs no longer leaves stale references.
* Improved toggle/tooltip/dialog interactions to avoid broken UI,
including metric headers showing tooltips even without direct links.
* Migrations display safely when migration tables/relations are missing.

* **UI Improvements**
* Refreshed layout for saved queries, form descriptions, and integration
imagery.

* **Tests**
* Added coverage for snippet history cleanup, tab removal, migrations
SQL behavior, and query edge cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


---

### Review feedback: `query_to_xml` breaks on Multigres (Ivan)

The defensive migrations query (added here to stop the `?key=migrations`
400 when the table doesn't exist yet) originally guarded with
`query_to_xml`, which is forbidden through Multigres's pooler (MUL-736 /
PSQL-1318). Rewritten without `query_to_xml`/`xmltable` using the
splinter#170 pattern: a PL/pgSQL `do` block guarded by `to_regclass`
(PL/pgSQL defers planning, so a missing table never errors) stashes the
rows into a transaction-local GUC via `set_config`, and a trailing
`select` reads them back with `jsonb_array_elements`. Verified that
postgres-meta sends the whole SQL as one simple-query string → single
implicit transaction → the local GUC survives to the `select` and
doesn't leak into the pooled connection. 6/6 dockerized-Postgres tests
(absent table → `[]`, populated/ordered/special-chars, legacy
version-only table, full pg-meta-shaped multi-statement string, GUC
non-leakage).

Note (out of scope, pre-existing):
`packages/pg-meta/src/sql/studio/advisor/lints.ts` still uses
`query_to_xml` — a separate pre-existing Multigres risk that should get
its own splinter-pattern sync.

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Saxon Fletcher <saxonafletcher@gmail.com>
2026-07-08 12:32:11 +08:00
oniani1 99db104cf5 fix(pg-meta): escape unencrypted FDW server options via format() %L (#47014)
Closes #47012

## What kind of change does this PR introduce?

Bug fix.

## What is the current behavior?

Unencrypted FDW server option values are pre-escaped with
`literal(value).replace(/'/g, "''")` and embedded inside the outer
`create server` `E'...'` string built by `format()`. That nests the
value inside two `E'...'` literals, so backslashes are decoded twice. A
value like `domain\user` aborts wrapper creation with `invalid Unicode
escape`, and `p@ss\w0rd` is silently stored as `p@ssw0rd`.

## What is the new behavior?

Unencrypted option values are passed as `format()` `%L` arguments, the
same way the encrypted options already supply their secret id, so
Postgres escapes each value exactly once.

Before and after, on postgres:16:

| Value | Before | After |
| --- | --- | --- |
| `domain\user` | aborts (invalid Unicode escape) | stored `domain\user`
|
| `p@ss\w0rd` | stored `p@ssw0rd` | stored `p@ss\w0rd` |
| `a\b` | stored `a`+backspace | stored `a\b` |

## Additional context

Added a unit test in `packages/pg-meta/test/sql/studio/fdw.test.ts`
asserting unencrypted options use a `%L` placeholder with the value as a
`format()` argument, and that the old double-escaped form is gone. The
encrypted-option path is unchanged.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved handling of special characters in foreign data wrapper server
option values.

* **Tests**
* Added test coverage for foreign data wrapper configuration, including
edge cases with special characters.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-22 15:45:56 +08:00
Vaibhav c9b8768940 fix: cmdk search (#47035)
- closes https://github.com/supabase/supabase/issues/47033

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Table search now matches fully-qualified table names (e.g.,
`schema.table`) when no specific schema is selected, enabling searches
to work seamlessly across all schemas.

* **Tests**
* Added comprehensive test coverage validating schema-qualified table
name matching in search filters.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-17 06:50:45 -06:00
Joshen Lim 097f220c5c Add support for managing stored procedures under database functions (#46977)
## Context

Dashboard currently doesn't have any support for managing stored
procedures. In the event that the security advisor surfaces a warning
about a stored procedure, users hence run into a dead-end as there's
currently no way to self-remediate via the dashboard

## Changes involved

We're hence adding support for managing stored procedures within
Database Functions
<img width="1082" height="546" alt="image"
src="https://github.com/user-attachments/assets/2598a5fe-e58f-4e8a-ad2f-9cb6d0eb2f53"
/>

Creating a function now shows a dropdown to select the type
<img width="500" alt="image"
src="https://github.com/user-attachments/assets/acc9249d-7b25-4416-aae8-89c630e1c62b"
/>

In which if stored procedure is selected, the following fields will be
hidden since they're irrelevant for stored procedures
- Return type
- Behaviour (Under advanced settings)

Some other minor UI changes as well:
- Field inputs are re-ordered a little, opting to group "Schema" and
"Name" into one section, followed by "Type" and "Return type"
- Opting to show "Return type" when editing a function but disabled
- Add schema filter for fetching database functions to reduce
unnecessary load on the database

## To test
- [ ] Can create, update, delete, read stored procedures via database
functions page

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary

- **New Features**
- Added PostgreSQL **procedure** support alongside functions, including
a **Type** selector in the create/edit flow.
- Updated Functions UI with a new **Type** column and procedure-aware
return/argument details.

- **Improvements**
- Refreshed create/edit headers and language help text for clearer
context.
- Improved argument parsing/display, including better handling of
procedure argument modes.

- **Bug Fixes**
- Corrected routine-type handling during function/procedure delete and
update SQL operations.

- **Tests**
- Updated unit snapshots and end-to-end UI flows/labels for the new “New
function” control.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-17 19:15:54 +08:00
Joshen Lim aba4e147eb Joshen/fe 3613 database tables query should have schema filter wherever appropriate (#46935)
## Context

There's certain areas in the dashboard where we're calling
`useTablesQuery` without a schema filter, in which case the dashboard
then fires a query against the project's database to fetch _all_ tables
across _all_ schemas - this could easily be a heavy query if there's a
large number of relations in the project's database.

Am hence opting to either add a schema filter if appropriate, or
otherwise opt to use the infinite loading behaviour

## Changes involved
- Add schema filter to `useTablesQuery` in database triggers and
publications
- Use infinite loading for tables in Cmd K for "Run query on table" and
"Search database tables"

## To test
- [x] Verify that database triggers + publications still function as
expected
- [x] Verify that CMD K "Run query on table" and "Search database
tables" still function as expected (including search)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Implemented debounced infinite-scrolling table search in the command
menu and SQL editor command flow.
* Added a schema selector dropdown to publications management for easier
navigation.
* **Improvements**
  * Removed the “Schema” column from the publications tables UI.
* Updated search guidance and table-picker status (counts/loading)
during infinite browsing.
  * Trigger table listings now follow the selected schema context.
* Refined command menu list height and improved the database-tables
placeholder text.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-16 15:45:39 +08:00
Charis a4334a2cc7 feat(studio): paginate Schema Designer via useInfiniteTablesQuery (#46402)
## 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?

Performance improvement / feature

## What is the current behavior?

The Schema Designer fetches all tables in a single request via
`useTablesQuery`. For schemas with 400+ tables this blocks first paint
on a large payload.

## What is the new behavior?

`SchemaGraph` uses `useInfiniteTablesQuery` (pageSize: 100) so the first
100 tables paint immediately. A "Load more tables" button appears above
the legend whenever more pages remain, letting users load the rest on
demand.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a "Find table…" selector and keyboard shortcut to quickly locate
and focus tables; supports incremental loading and debounced name search
(with literal wildcard handling).
* Schema Graph shows a bottom "Load more tables" control with loading
state and preserves view after loading more.

* **Refactor**
* Table listing switched to infinite/paginated retrieval and improved
"no tables" logic; server-side name filtering supported.

* **Tests**
* E2E tests add a schema-visualizer wait helper and update flows to
support the paginated visualizer.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46402?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-29 15:12:22 -04:00
Charis 426b0183af feat(studio): add useInfiniteTablesQuery hook for paginated tables (#46285)
## 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?

Feature — adds a new data-layer hook. No callers are switched over in
this PR.

## What is the current behavior?

The Schema Designer and Database > Tables list both call
`useTablesQuery({ includeColumns: true })`, which fetches the full
schema (every table, with every column, every relationship) in one
round-trip. For customers with many tables this never loads. Towards
FE-3428.

## What is the new behavior?

Introduces `useInfiniteTablesQuery` — a cursor-paginated tables hook
ready to be consumed by the two pages above in follow-up PRs.

- `pg-meta`: new `getTablesPaginatedSql` SQL builder that picks a page
of table OIDs first (cheap `pg_class` index scan) and constrains every
enrichment CTE (primary keys, relationships, columns) to that set.
Pagination is by `c.oid > $afterOid` rather than `OFFSET`, so deep pages
stay O(limit). Relationships use a `UNION ALL` keyed by `table_id` so
the downstream join is a plain equi-join.
- `pg-meta`: `COLUMNS_SQL` is now produced by `getColumnsSql({ filter
})`, letting a paginating caller push a table-OID predicate into the
WHERE clause directly. The bare `COLUMNS_SQL` export is preserved for
the 5 existing callers (`pg-meta-columns`, `pg-meta-tables`,
`pg-meta-views`, `pg-meta-materialized-views`,
`pg-meta-foreign-tables`).
- `studio`: `useInfiniteTablesQuery` wires the new SQL into
`useInfiniteQuery` via `executeSql`. `initialPageParam: 0`,
`getNextPageParam` returns the last row's `id` or `undefined` on a short
last page.
- Tests: 12 new tests in `pg-meta` covering cursor invariants (no
overlap / no gap), schema filtering, primary-key / relationship / column
shape, and output parity against the existing `pgTableZod` schema.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Enabled infinite scrolling for table listings with cursor-based
pagination and optional page sizing.
* Added an option to include per-table column data in paginated results.
  * Made column queries filterable for more targeted metadata retrieval.

* **Tests**
* Added comprehensive tests validating pagination, schema scoping,
column inclusion, and relationship/PK shaping.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46285?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-26 14:55:13 -04:00
Charis 64143a5d90 fix(pg-meta): tighten pg-format keyword() against control-phrase injection (#46076)
## 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 (sanitization hardening).

## What is the current behavior?

`pg-format`'s `keyword()` helper validates with `/^[A-Za-z][A-Za-z0-9_
]*$/`, which allows any space-separated word sequence. Phrases like
`'DROP TABLE'` or `'DELETE FROM users'` pass validation and can be
interpolated into queries.

## What is the new behavior?

`keyword()` accepts either a single word matching
`[A-Za-z][A-Za-z0-9_]*` (no spaces) or a phrase from a small
case-insensitive allow-list (`'INSTEAD OF'`, `'BY DEFAULT'`) — which
covers every multi-word value real callers actually produce (trigger
activation, identity generation). Arbitrary multi-word phrases now
throw. Tests updated accordingly.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Reinforced SQL keyword validation with stricter security controls to
prevent unsafe keyword usage. The system now only permits single-word
identifiers or specific pre-approved multi-word keyword phrases.
Previously accepted multi-word inputs that don't match the curated
allowlist are now properly rejected with improved error messaging.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46076?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-19 16:13:06 -04:00
Charis e925385415 studio,pg-meta: SafeSql for functions/policies/triggers (3/7) (#45990)
## Summary

Third PR in the SafeSql migration stack. Flips the input/output types on
`pgMeta.functions/policies/triggers`'s `.create/.update/.remove` to use
`SafeSqlFragment`, and updates every Studio consumer atomically.

### pg-meta
- `pgMeta.functions/policies/triggers` `.create/.update/.remove` now
return `{ sql: SafeSqlFragment }` and accept branded input parameters
(`PGFunctionCreate`, `PGSavedFunction`, `PolicyCreate/UpdateParams`,
`PGTriggerCreate` with branded condition).
- `QueryModifier.toSql()` returns `SafeSqlFragment`.

### Studio consumers updated to the new branded API
- `data/database-functions/*` (query, create/update/delete mutations)
- `data/database-policies/*` (create, update mutations)
- `data/database-triggers/database-trigger-update-transaction-mutation`
- `components/Database/Triggers/TriggerSheet`
- `components/Database/Functions/CreateFunction`
- `components/Auth/Policies/PolicyEditorPanel`

These consumers land atomically with the pg-meta API change because the
input-type strictness flip (string → `SafeSqlFragment` for SQL fields)
forces every call site to update together.

## Stack

- 1/7: #45897 (merged)
- 2/7: #45903 (merged)
- 3/7: this PR
- 4/7–7/7: upcoming

## Test plan

- [x] `pnpm typecheck` passes
- [x] `pnpm --filter @supabase/pg-meta test` passes
- [x] Dev-server smoke test: function editor, policy editor, trigger
sheet

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Strengthened SQL safety across policy, function, and trigger workflows
by converting raw SQL strings to typed SQL fragments and safer
composition
* Updated editor behavior to handle policy conditions/checks as typed
SQL fragments with improved initialization and template handling
* Aligned query and modifier interfaces to return typed SQL fragments
for safer composition

* **Tests**
* Updated tests to use typed SQL fragments and synchronous builders
where applicable

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45990)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-15 12:08:20 -04:00
Charis d79a276824 studio: ColumnTypeRef cascade + FK type comparison fixes (2/7) (#45903)
## 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 + bug fixes (part of the SafeSql migration stack — PR 2 of 7,
stacks on top of #45897).

## What is the current behavior?

- `pgMeta.columns.create` and the table-editor SQL builder take column
type as a string with array suffix and schema baked in (e.g.
`'private.test_enum'`, `'int4[]'`).
- The studio table-editor SQL emits the legacy schema-embedded `format`
string for enums in non-public schemas, while the pg-meta columns SQL
already returns the new shape (bare `format` + separate
`format_schema`). The two queries disagree on how to represent the same
column, surfacing as a false-positive type mismatch in the FK selector
when both ends are an enum from a non-public schema.
- The FK selector compares column types by `format` alone — same-named
enums in different schemas appear equal, and arrays vs. scalars of the
same base type pass the family check.
- `displayColumnType` renders arrays as the raw `_typname` pg-meta emits
(e.g. `_int4` instead of `int4[]`).

## What is the new behavior?

**pg-meta**

- Introduce `ColumnTypeRef` (`{ schema?, name, isArray? }`) for column
type input, replacing the legacy string-with-array-suffix format.
`pgMeta.columns.create` and the table-editor SQL builder consume the new
shape.
- Add `format_schema` to the column zod schema; pg-meta SQL emits the
type's schema for the table editor's ColumnType dropdown.
- `pgMeta.columns.create` returns a `SafeSqlFragment`.
- Studio table-editor SQL now emits bare `format` + `format_schema`,
matching pg-meta's columns SQL.

**Studio**

- `SafePostgresColumn`/`SafePostgresTable` extend the new `PG*` types
(master dropped postgres-meta).
- Pipe `ColumnTypeRef` through `SidePanelEditor` → `ColumnEditor` →
`TableEditor`, along with the column-create mutation, table
retrieve/list queries, and the `TableList`/`ColumnList` surfaces.
- `displayColumnType` helper renders arrays as `type[]` (or
`schema.type[]`) and handles non-implicit schemas.
- FK selector now carries `sourceIsArray`/`targetIsArray` and compares
the full `(format, format_schema, isArray)` triple. Family checks for
numeric/text/uuid skip when either side is an array (FKs across array
boundaries are never compatible).
- Type-mismatch and type-notice alerts pass `isArray` to the display
helper.
- Bundle `Policies.utils` + `Policies.types` + `sql-policy-mutation`,
`PolicyEditorModal`, and `SchemaGraph` here because `SidePanelEditor`
consumes `acceptGeneratedPolicy`/`AcceptedGeneratedPolicy` — splitting
requires temporary overloads with no architectural payoff.

## Additional context

Part of the SafeSql migration stack. Stacks on top of #45897.

### Manual test checklist

Surfaces touched by this PR — please exercise each:

**Table editor**
- [x] Create a new table with a mix of column types (scalar, array,
enum, foreign key)
- [x] Add a column to an existing table; verify the type dropdown lists
scalars + arrays separately and shows schema-qualified names for
non-public enums
- [x] Edit an existing column's type (scalar ↔ array, switch between
enums in different schemas) and save
- [x] Verify enum types from a non-public schema (e.g.
`private.my_enum`) display as `private.my_enum` in the column list

**Foreign key selector**
- [x] Open the FK selector for a column and pick a target column with a
matching type — no mismatch warning
- [x] Pick a target column whose type differs only by schema (two
same-named enums in different schemas) — should show a type-mismatch
alert
- [x] Pick a target column where one side is an array and the other is a
scalar of the same base type — should show a type-mismatch alert (no
auto-cast across array boundary)
- [x] When FK target sets the column type, verify `format_schema` and
`isArray` are preserved on the source column
- [x] Type-mismatch and type-notice alert messages render array types as
`type[]` (not `_type`)

**Column list / table list**
- [x] Schema-qualified type names display correctly for columns whose
type lives in a non-public schema
- [x] Array columns display as `type[]` (or `schema.type[]`)

**Policies (bundled due to import dependency)**
- [x] Open the Policies page; create/edit/delete a row-level policy via
the modal
- [x] Generate a policy via the AI assistant and accept it through
`SidePanelEditor` — verify the accepted policy lands in the editor
correctly

**Schema visualizer**
- [x] Open the Schemas → Schema Visualizer page; verify it renders
without type errors and shows tables/relationships

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Support for column types in non-public schemas and richer column type
presentation (includes schema and array info).
* Stronger SQL safety around policies and constraints; draft policy SQL
is now promoted explicitly on save.
* Improved foreign-key type validation and compatibility checks using
enhanced type metadata.

* **Tests**
* Updated snapshots and tests to reflect new column metadata and SQL
fragment handling.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45903)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-14 15:12:08 -04:00
Charis d4079083fc chore(studio): drop @supabase/postgres-meta in favor of @supabase/pg-meta (#45844)
## 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 / dependency cleanup.

## What is the current behavior?

`apps/studio` lists both `@supabase/pg-meta` (workspace package) as a
runtime dep and `@supabase/postgres-meta` (external npm package,
`^0.64.4`) as a devDependency. The external package is used only for
type imports across 44 files — there is no runtime usage and no codegen
pipeline that needs it.

## What is the new behavior?

Every `Postgres*` type import (`PostgresTable`, `PostgresColumn`,
`PostgresPolicy`, `PostgresTrigger`, `PostgresView`,
`PostgresMaterializedView`, `PostgresForeignTable`, `PostgresSchema`,
`PostgresPublication`, `PostgresRelationship`, `PostgresPrimaryKey`) is
replaced with its `PG*` counterpart from `@supabase/pg-meta`, and the
external dep is removed from \`apps/studio/package.json\`. Top-level
type re-exports were added to \`packages/pg-meta/src/index.ts\` so
consumers can import directly from the package root.

Two latent issues surfaced by the stricter pg-meta types are also fixed:
- \`data/foreign-tables/foreign-tables-query.ts\` was casting
foreign-table results as \`PostgresView[]\`; corrected to
\`PGForeignTable[]\`.
- \`pg-meta\`'s \`PGTrigger\` Zod schema declared
\`orientation\`/\`activation\` as \`z.string()\`, inconsistent with
pg-meta's own \`getDatabaseTriggerUpdateSQL\` helper that requires the
narrow literal unions; tightened to \`z.enum\`.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated internal TypeScript type definitions across the codebase to
use the latest type system from `@supabase/pg-meta`.
  * Removed `@supabase/postgres-meta` dependency.
* Enhanced type validation for database triggers and schemas to enforce
stricter constraints.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45844)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-13 16:07:10 +00:00
Charis 116faefcda studio: convert more executeSql callers to SafeSqlFragment (#45645)
## Summary

- Converts ~27 `executeSql` call sites in `apps/studio/data/**` to build
SQL through `safeSql` / `ident` / `literal` / `keyword` /
`joinSqlFragments` instead of raw template-string interpolation.
- Tightens the `useDatabaseCronJobCreateMutation` and
`useDatabaseEventTriggerCreateMutation` `sql`/`query` parameter types
from `string` to `SafeSqlFragment` (callers already produce one).
- Updates `getDeleteEnumeratedTypeSQL` in `packages/pg-meta` to return
`SafeSqlFragment`.
- Fixes a bug noticed while testing where Queues integration does not
correctly handle queues with uppercase names.

## Pages to manually test

- Integrations > Cron Jobs
- Integrations > Queues
- Database > Triggers > Event Triggers
- Database > Indexes
- Reports > Query Performance
- Storage

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
  * Queue lookups now correctly handle case-insensitive queue names.
* Queue table references are now properly managed and consistently
applied throughout the queue management interface.
  * Improved queue name display normalization in the user interface.

* **Chores**
* Enhanced SQL query safety across the database layer through
parameterized query construction and safer templating approaches.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-06 12:21:48 -04:00
Charis 6119e35f78 pg-meta: convert last files to use SafeSqlFragment (#45552)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Enhanced safety of database query generation for publication and table
definition operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-04 15:06:43 -04:00
Charis 0433eeb5f5 feat(studio): mark sql provenance for safety (#45336)
Mark provenance of SQL via the branded types SafeSqlFragment and
UntrustedSqlFragment. Only SafeSqlFragment should be executed;
UntrustedSqlFragments require some kind of implicit user approval (show
on screen + user has to click something) before they are promoted to
SafeSqlFragment.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Editor and RLS tester show loading states for inferred/generated SQL
and include a dedicated user SQL editor for safer edits.

* **Refactor**
* Platform-wide SQL handling tightened: snippets and AI-generated SQL
are treated as untrusted/display-only until promoted, improving safety
and consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-04 13:08:06 -04:00
Akash SantraandCharis Lam 73cdf2ddd1 fix(pg-meta): include schema in pg_indexes join to avoid cross-schema index collisions (#45374)
## I have read the CONTRIBUTING.md file.

YES

## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

The query in `sql/indexes.ts` joins `pg_class` with `pg_indexes` using
only the index name:

```sql
JOIN pg_indexes ix ON c.relname = ix.indexname
```

This can lead to incorrect results when multiple schemas contain indexes
with the same name. PostgreSQL allows identical index names across
different schemas, so this join may return the wrong index_definition.

## What is the new behavior?

The join condition now includes the schema name:

```sql
JOIN pg_indexes ix 
  ON c.relname = ix.indexname 
  AND n.nspname = ix.schemaname
```

This ensures the correct index_definition is retrieved for each index,
even when duplicate index names exist across schemas.

## Additional context

- Added a test case to verify behavior when the same index name exists
in multiple schemas.
- This change prevents cross-schema collisions and ensures accurate
index metadata retrieval.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved index listing so indexes that share the same name in
different schemas are correctly distinguished and reported.

* **Tests**
* Added a regression test ensuring indexes with identical names in
separate schemas are both detected and contain expected schema-qualified
references.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
2026-05-04 11:52:40 -04:00
Charis f051c6a1c1 refactor(pg-meta): consolidate test scripts and support parallel test runs across worktrees (#45340)
## 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 of the pg-meta test setup scripts.

## What is the current behavior?

The test command runs multiple sequential npm-run-s scripts (`db:clean`,
`db:run`, `test:run`, `db:clean`) with a hardcoded port 5432, causing
container name and port collisions when running tests across multiple
git worktrees in parallel.

## What is the new behavior?

A single `test/run-tests.sh` wrapper script handles the full test
lifecycle: it finds an available port dynamically (scanning 5432–5531),
sets a unique Docker Compose project name based on a hash of the package
directory path, starts the DB, runs the test command, and tears down on
exit. This allows pg-meta tests to run in parallel across multiple
worktrees without conflicts.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Streamlined test execution to centralize setup and teardown for
reliable runs.
* Made the test database port configurable with automatic local port
discovery and fail-fast behavior.
* Created isolated test environments per workspace to avoid
container/name collisions and improve cleanup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-28 16:34:56 -04:00
Akash Santra a8de56aec2 fix(pg-meta): require replica_identity_index when replica_identity is INDEX (#45019)
## I have read the CONTRIBUTING.md file.

YES

## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

When updating a table with `replica_identity = 'INDEX'`, it is possible
to omit the `replica_identity_index`.
This results in invalid SQL being generated:

`REPLICA IDENTITY USING INDEX`

PostgreSQL requires an index name for this operation.

No existing issue found. This PR fixes a validation gap discovered
during development.

## What is the new behavior?

- Throws an error if `replica_identity` is set to `INDEX` without
providing `replica_identity_index`
- Ensures generated SQL is always valid

## Additional context

- Added validation in `pg-meta-tables.ts`
- Added test case to verify an error is thrown when the index name is
missing

This aligns pg-meta behavior with PostgreSQL requirements for `REPLICA
IDENTITY USING INDEX`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Enhanced validation for database replica identity configuration to
prevent incomplete or invalid configurations.

* **Tests**
  * Added test coverage for replica identity validation scenarios.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-28 15:13:47 -04:00
Joshen Lim 5f867e5f6c Feature Preview: RLS Tester (#45121)
## Context

Resolves FE-3077
Related discussion: https://github.com/orgs/supabase/discussions/45233

Verifying the correctness of your RLS policies set up has always been a
gap, as highlighted by a number of GitHub discussions like
[here](https://github.com/orgs/supabase/discussions/12269) and
[here](https://github.com/orgs/supabase/discussions/14401). As such,
we're piloting a dedicated UI for RLS testing (using role impersonation
as the base), in which you'll be able to
- Run a SQL query as a user (not logged in / logged in - this is the
role impersonation part)
- See which RLS policies are being evaluated as part of the query
- And hopefully be able to debug which policies are not set up correctly

Changes are currently set as a feature preview - and we'll iterate as we
get feedback from everyone 🙂 🙏

<img width="613" height="957" alt="image"
src="https://github.com/user-attachments/assets/83c37f8a-28fc-43b3-b0ff-e28571d8710c"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* RLS Tester: run queries as anon or authenticated users, view inferred
SQL, per-table policy summaries, and data previews of accessible rows.
* UI preview: new RLS Tester preview card and modal with opt-in toggle;
RLS Tester sheet with role/user selector and query editor.
  * SQLEditor: “Explain” tab is always visible.

* **Chores**
* Added supporting API endpoints, background checks for table RLS
status, and a local-storage flag to persist the preview opt-in.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-28 15:02:49 +08:00
67deabf67e fix: create etl publication as postgres (#45043)
## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

Creating a schema only branch fails because ETL publication is owned by
`supabase_etl_admin` which users have no access.

## What is the new behavior?

Since ETL supports user managed publications, create them through pgmeta
so it's owned by `postgres` role instead.

## Additional context

mirrors [upstream
etl](https://github.com/supabase/etl/blob/main/etl-api/src/db/publications.rs#L22-L51)
implementation


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Added guards to prevent creating publications when project or
connection info is missing, with clearer error logging.
* Ensure the project connection string is explicitly passed so
publications target the correct database.

* **Refactor**
* Publication creation now executes generated SQL directly against the
database, with correct handling of empty or selected table lists and
proper identifier quoting for reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
2026-04-27 19:45:26 +08:00
samroseandDanny White 4afbe9c2b2 feat: lint integration for pg_graphql introspection + SECURITY DEFINER functions (#45260)
## 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?

Feature — wires up three new advisor lints landed in splinter, and
updates the self-hosted SQL bundle for the existing
`pg_graphql_anon_table_exposed` lint to track splinter's correctness
fixes. Companion to `supabase/splinter` #160 (already merged) and #162
(test fix in flight).

## What is the current behavior?

Splinter's `main` now exposes four lints in the pg_graphql / SECURITY
DEFINER family:

- `pg_graphql_anon_table_exposed` (0026, existing) — wired into Studio
in #45253; SQL in `packages/pg-meta` is the original version that uses
`has_table_privilege` and the relkind set `('r','p','v','m')`.
- `pg_graphql_authenticated_table_exposed` (0027, new) — paired check
against the `authenticated` role. Studio renders any new finding without
a `lintInfoMap` entry as a row with no icon, no title mapping, and no
"Fix" CTA. Self-hosted users do not see the lint at all because
`packages/pg-meta` does not include it.
- `anon_security_definer_function_executable` (0028, new) — `SECURITY
DEFINER` function executable by `anon`. Same Studio + self-hosted gaps
as 0027.
- `authenticated_security_definer_function_executable` (0029, new) —
same against `authenticated`.

Splinter has also updated 0026 itself (PR #160) in two ways that need to
flow into the self-hosted SQL bundle:
1. **`relkind` filter:** `('r','p','v','m')` → `('r','v','m','f')`.
Drops partitioned table roots (pg_graphql does not expose them; their
leaf partitions are still covered as `'r'`) and adds foreign tables,
which pg_graphql does expose.
2. **Privilege predicate:** `has_table_privilege(role, oid, 'SELECT')` →
`EXISTS` over `pg_attribute` calling `has_column_privilege`. Catches
column-level grants such as `GRANT SELECT (col) ON t TO anon`, which
pg_graphql's introspection exposes but `has_table_privilege` missed.

Cloud projects auto-fetch `splinter.sql` via the platform mgmt-api's
`getLintSql` (1-hour cache TTL), so they pick up #160's lint and SQL
changes independently of this PR. This PR is about the Studio display
mapping and the self-hosted SQL bundle.

## What is the new behavior?

Two minimal additions, mirroring the integration shape of #45253.

### `apps/studio/components/interfaces/Linter/Linter.utils.tsx`

Three new entries appended to `lintInfoMap`:

- `pg_graphql_authenticated_table_exposed` — `Eye` icon (paired with the
existing `pg_graphql_anon_table_exposed` entry); link points to the
Table Editor scoped to `metadata.schema` + `metadata.name`; `linkText:
'View object'`; `category: 'security'`.
- `anon_security_definer_function_executable` — `Unlock` icon (signals
"this thing is callable when it shouldn't be"); link points to the
Database Functions browser scoped to `metadata.schema` +
`metadata.name`; `linkText: 'View function'`; `category: 'security'`.
- `authenticated_security_definer_function_executable` — same as 0028
against `authenticated`.

Each entry's `docsLink` points at the splinter-hosted lint doc.

### `packages/pg-meta/src/sql/studio/advisor/lints.ts`

The existing `pg_graphql_anon_table_exposed` SQL block is updated in
place to match the new splinter version: new `relkind` set, `case`
statement for `'f'`, and the `EXISTS` over `pg_attribute` privilege
check. Three new `union all` blocks are appended for 0027/0028/0029. The
function lints (0028/0029) include the `pgrst.db_schemas` filter
(mirroring lint `0023_sensitive_columns_exposed`) so findings are scoped
to schemas PostgREST actually exposes; the self-hosted query wrapper
already sets the GUC when `exposedSchemas` is passed
(`enrichLintsQuery`).

## Coverage of the four exposure paths

| Role | Tables/views/MVs/foreign tables | SECURITY DEFINER functions |
|------|---------|----------|
| `anon` | 0026 (existing, updated) | 0028 (new) |
| `authenticated` | 0027 (new) | 0029 (new) |

The 0026/0027 pair covers `pg_graphql` introspection visibility; the
0028/0029 pair covers RLS bypass via privileged function execution
through `/rest/v1/rpc` (and `/graphql/v1` for compatible return types).
Each lint's doc cross-references its sibling so an operator hitting one
is steered toward the others.

## Verification

- `cd packages/pg-meta && npx tsc --noEmit` — clean.
- `cd apps/studio && npx tsc --noEmit` — clean for the changed file.
(Other unrelated TS errors exist in the working tree but are
pre-existing and not introduced by this PR.)
- `cd apps/studio && npx eslint
components/interfaces/Linter/Linter.utils.tsx` — clean.

## Files

- `apps/studio/components/interfaces/Linter/Linter.utils.tsx` — adds
three `lintInfoMap` entries (0027, 0028, 0029).
- `packages/pg-meta/src/sql/studio/advisor/lints.ts` — updates the 0026
SQL block to match splinter's correctness fixes, appends 0027/0028/0029
SQL blocks.

## Related

- supabase/splinter#160 — adds 0027/0028/0029 and rewrites 0026
(merged).
- supabase/splinter#162 — fixes test setup for 0028/0029 (in flight;
does not affect the SQL shipped here).
- supabase/supabase#45253 — original 0026 Studio integration.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added security linting to detect authenticated-table exposure and
executable SECURITY DEFINER functions.
  * Added signed-in visibility checks alongside anonymous checks.

* **Bug Fixes / Improvements**
* Improved relation type handling for accurate table/foreign/partition
classification.
  * Switched to column-level privilege analysis for visibility.
* Improved entity naming shown in lints (includes function argument
display).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
2026-04-27 10:56:44 +08:00
samrose 801b912fc8 feat: lint for pg_graphql introspection fix (#45253)
## 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?
                  
Feature — wires up the new advisor lint `pg_graphql_anon_table_exposed`
so it renders properly in Studio and ships with
self-hosted Supabase. The lint itself was added to splinter in
supabase/splinter#158 (already merged).
## What is the current behavior?
   
Splinter's `main` exposes lint `0026_pg_graphql_anon_table_exposed`,
which detects tables, views, and materialized views
whose schema is visible through the public `/graphql/v1` introspection
endpoint when the `anon` role has `SELECT` on them.
The hosted advisor (mgmt-api) auto-fetches `splinter.sql` from
raw.githubusercontent.com, so the lint will start firing on
  cloud projects, but:

- Studio has no `lintInfoMap` entry for it, so the row renders without
an icon, title mapping, "Fix" CTA, or category
  classification.
- Self-hosted Supabase ships with a vendored copy of the lint SQL in
`packages/pg-meta`; without an update there, self-hosted
users never see the lint at all.
   
## What is the new behavior?
                  
  Two minimal additions:

- **`apps/studio/components/interfaces/Linter/Linter.utils.tsx`** — adds
a `lintInfoMap` entry for
`pg_graphql_anon_table_exposed`: title `"pg_graphql Anon Role Exposes
Objects in Introspection"`, `Eye` icon, `security`
category, `"View object"` CTA pointing at the table editor scoped by
`metadata.schema` and `metadata.name`, docs link to the
  splinter docs page.
- **`packages/pg-meta/src/sql/studio/advisor/lints.ts`** — vendors the
lint's SQL block into `getLintsSQL()` so self-hosted
deployments include it. Follows the file's documented copy-paste
convention from splinter: every backtick inside SQL string
literals is escaped (`` ` `` → `` \` ``), and the hardcoded docs URL is
replaced with `${literal(\`${docsUrl}/...\`)}`.
No changes to the OpenAPI surface, no changes to the `LINT_TYPES`
literal union (auto-generated; matches the precedent of how
lints 0023–0025 were added — Studio's `LintInfo.name` is typed as
`string`, not the strict enum).
  ## Additional context

- Splinter PR (merged): https://github.com/supabase/splinter/pull/158
- Splinter lint source:
https://github.com/supabase/splinter/blob/main/lints/0026_pg_graphql_anon_table_exposed.sql
- Splinter docs page:
https://github.com/supabase/splinter/blob/main/docs/0026_pg_graphql_anon_table_exposed.md
- The hosted advisor flow that fetches splinter.sql automatically lives
in the platform mgmt-api (`getLintSql` in
`advisors-utils.ts`), with a 1-hour cache TTL — cloud projects will pick
up the new lint independently of this PR; this PR is
   about the Studio display mapping and the self-hosted SQL bundle.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added a new security linter check that identifies tables and views
exposed to anonymous GraphQL access, with warnings and remediation
guidance to help resolve the issue.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-26 10:31:37 -04:00
Vaibhav 2e3ddc3a52 fix: csv seq sync (#45076)
## TL;DR
fixes csv imports with explicit id values leaving auto generated primary
keys out of sync
by resolving the primary key sequence correctly after import

## ex:

| Before | After |
| --- | --- |
| <img width="378" height="201" alt="Before: stale sequence after CSV
import"
src="https://github.com/user-attachments/assets/34c827f5-c69b-4c05-aa67-9fb6fd65a040"
/> | <img width="435" height="196" alt="After: sequence synced after CSV
import"
src="https://github.com/user-attachments/assets/bb84f286-1b3e-44a5-965b-5f2faa3f7622"
/> |

## ref:
- closes https://github.com/supabase/supabase/issues/45073


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Fixed identity sequence synchronization during CSV imports. After
spreadsheet data is inserted, the system now properly updates sequence
values, ensuring subsequent rows receive correct identifiers.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-21 07:59:20 -06:00
Charis e1bd0c791f convert migrations and privileges sql utils to use safesql (#45070)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Enhanced SQL query generation for database migrations and privilege
management with improved parameterization and type safety.
* Strengthened security and robustness of database operations through
modernized SQL building patterns.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-21 09:02:50 -04:00
Charis bff92df845 convert fdw sql utilities to safesql (#45069)
<!-- 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 -->
2026-04-20 15:06:49 -04:00
Charis 62d59d596b convert advisor and auth queries in pgmeta to safesql (#44998)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Improved SQL construction across the studio to make queries safer and
more consistent.
* Safer parameter handling for optional schema and remediation links to
prevent injection risks.
* Deterministic query header formatting and stable date/comments in
generated SQL.
* More robust user-count and paginated-user queries for accurate counts,
sorting and pagination.
  * Updated tests to align with the new safe query handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-20 11:34:00 -04:00
Vaibhav 8c4ae77ece fix: enum quotes (#45023)
## TL;DR

fixes enum create/update failures when names contain quotes
(also added a smol e2e)

## Ex:

<table>
  <tr>
    <td><strong>Before</strong></td>
    <td><strong>After</strong></td>
  </tr>
  <tr>
    <td>
<img width="424" height="178" alt="Before"
src="https://github.com/user-attachments/assets/d1815f4e-3879-4f8d-8d24-40d2c1f5563d"
/>
    </td>
    <td>
<img width="233" height="75" alt="After fix"
src="https://github.com/user-attachments/assets/f3f9b53c-b234-4e18-9b2d-db97ca4713d5"
/>
    </td>
  </tr>
</table>

## ref:

- closes https://github.com/supabase/supabase/issues/45022


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed enumerated type description handling to preserve special
characters (quotes and apostrophes) without unintended escaping.

* **Tests**
* Extended enumerated types test coverage to include creation, updates,
and deletion of types with special characters in names and descriptions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-20 09:07:36 -06:00
Matt Rossman 8f69a10cc9 fix(studio): reliable schema-aware SQL editor AI completions (#44730)
A variety of fixes and improvements to the Cmd+K AI completions endpoint
in the [SQL Editor](https://supabase.com/dashboard/project/_/sql/new):

- Pre-load table definitions for the public schema and any other schemas
referenced in the editor, so the model has real column names without
needing to fetch them dynamically
- Replace the generic tool suite with a single streamlined
`getSchemaDefinitions` tool the model can still call to look up
additional schemas on demand without behavior differences across
platform & self-hosted
- Swap generic chat system prompt for a purpose-built
`COMPLETION_PROMPT`; fix role (`assistant` → `user`) for consistency
with other endpoints
- Validate and type the request body with `zod`, which was previously
untyped (`any`)
- Improve Cmd+K behavior when nothing is selected — use the full editor
content as context, return the complete query rather than just the
changed fragment, and switch to a generation mode when the editor is
blank
- Escape single quotes in schema names when fetching entity definitions
in `pg-meta` to prevent schema names from breaking out of the SQL string
and injecting arbitrary content into the prompt

## Before

Before, the SQL Editor would often hallucinate tables / columns that
don't exist in the user's database making it less helpful if you don't
know the exact table/column names. Even with maximum Assistant opt-in
level on the org, it would often fail to call the necessary tools to
gather database context.

<img width="5062" height="1522" alt="image"
src="https://github.com/user-attachments/assets/fbe1130f-6b5a-41a8-99d7-7268880af188"
/>

<img width="2540" height="658" alt="image"
src="https://github.com/user-attachments/assets/a31c2967-7751-4fce-a9b7-60bd77660b1a"
/>

Sometimes it also silently fails and generates empty queries:

<img width="1352" height="398" alt="CleanShot 2026-04-09 at 17 46 06@2x"
src="https://github.com/user-attachments/assets/e17c103a-d47d-47e6-8c2e-101f0fae5651"
/>

Or echos back the user's prompt:

<img width="1368" height="282" alt="CleanShot 2026-04-09 at 23 04 56@2x"
src="https://github.com/user-attachments/assets/7dff6e64-f54e-45b5-8e86-5399e5a2fe41"
/>


## After

In this example, the completion correctly interpreted my request for
"completed" todos as a query on the `completed_foo` column in my
`public` schema, instead of assuming existence of a `completed` column.

<img width="1452" height="838" alt="CleanShot 2026-04-09 at 17 43 13@2x"
src="https://github.com/user-attachments/assets/7a575589-78b4-448d-810a-0330ff08ef8b"
/>

In this example, the completion was correctly aware of an `other` schema
because it was detected in my existing query. I didn't have to select
the text, it included the full query in context when unselected. Notice
how it correctly used the `is_done` column when I asked for "completed"
cakes:

<img width="1372" height="534" alt="CleanShot 2026-04-09 at 17 39 07@2x"
src="https://github.com/user-attachments/assets/e6b7eb6f-f3e8-4fa1-90a3-b5e34ddc14e4"
/>

Supersedes #44151

Closes AI-544
2026-04-20 11:01:52 -04:00
Charis b1531545fb security: migrate more files to safeSql (#44727)
<!-- 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 -->
2026-04-16 15:02:02 +00:00
Vaibhav fdf8732727 fix: Include security_invoker in definition (#44936)
## 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 -->
2026-04-16 07:03:54 -06:00
Alaister YoungandAlaister Young 1b1d05ff96 chore: upgrade vite to v8 and vitest to v4 (#44833)
Upgrade vite and vitest to their latest major versions across the
monorepo, along with related packages.

**Changed:**
- `vite` catalog: `^7.3.2` → `^8.0.8` (Rolldown replaces esbuild/Rollup)
- `vitest` catalog: `^3.2.0` → `^4.1.4`
- `@vitejs/plugin-react`: `^4.3.4` → `^6.0.1`
- `@vitest/coverage-v8`: `^3.2.0` → `^4.1.4`
- `@vitest/ui`: `^3.2.0` → `^4.1.4`
- `vite-tsconfig-paths`: `^4.3.2` / `^5.1.4` → `^6.1.1`

**Pinned to vite 7:**
- `apps/lite-studio` — `@react-router/dev` hasn't declared vite 8
support yet
- `blocks/vue` — Nuxt plugins (`vite-plugin-inspect`, `vite-dev-rpc`,
`vite-hot-client`, `vite-plugin-vue-tracer`) haven't declared vite 8
support yet

**Test fixes for vitest 4 breaking changes:**
- **`apps/studio/lib/api/snippets.utils.test.ts`** — Replaced
`vi.mock('fs/promises')` automock with an explicit factory. Vitest 4's
automocking doesn't create mock functions for getter-based exports on
Node built-ins, so `mockedFS.access.mockResolvedValue` etc. were
`undefined`.
- **`apps/studio/lib/api/self-hosted/functions/index.test.ts`** —
Changed `mockReturnValue` to `mockImplementation(function() { ... })`
for a constructor mock. Vitest 4 no longer allows `mockReturnValue` when
the mock is called with `new`.
- **`apps/studio/tests/pages/api/mcp/index.test.ts`** — Changed arrow
function to regular `function` in `mockImplementation` for
`StreamableHTTPServerTransport`. Arrow functions can't be constructors,
and vitest 4 now enforces this.
- **`packages/ui-patterns/vitest.setup.ts`** — Changed `ResizeObserver`
mock from arrow function to regular `function` for the same constructor
enforcement reason. This was crashing Radix popover rendering in jsdom.

## To test

- `pnpm test:studio` — all 226 test files should pass
- `pnpm --filter ui-patterns vitest run` — all 183 tests should pass
- `pnpm --filter www test -- --run` — all 19 tests should pass
- `pnpm --filter ui vitest run` — all tests should pass
- `pnpm --filter dev-tools vitest run` — all tests should pass
- `pnpm --filter ai-commands vitest run` — all tests should pass

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Standardized and updated development tooling versions and version
sources for consistent installs across the repo (Vite, Vitest,
vite-tsconfig-paths and related plugins/catalog entries).
* **Tests**
* Improved test mocks and typings (updated mock
factories/implementations and tightened spy/type assertions) to increase
test reliability and compatibility with updated tooling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-04-16 00:13:48 +09:00
83e5ee8c5c feat(studio): add advisor for public bucket rls (#44438)
## 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>
2026-04-14 16:40:18 +01:00
Charis 5d013cb2f6 refactor(pg-meta): expand safeSql usage (#44674)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Standardized SQL construction across the pg-meta package to use
parameter-safe SQL fragments instead of raw string assembly, improving
safety for dynamic values (filters, limits, offsets, identifiers) and
unifying how exported SQL constants and query helpers are produced. No
functional query behavior changes expected.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-09 14:32:02 -04:00