Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/cli-go/internal/db/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ func initRealtimeJob(host, jwks string) utils.DockerJob {
"DB_PORT=5432",
"DB_USER=" + utils.SUPERUSER_ROLE,
"DB_PASSWORD=" + utils.Config.Db.Password,
"DB_USER_REALTIME=supabase_realtime_admin",
"DB_PASS_REALTIME=" + utils.Config.Db.Password,
"DB_NAME=postgres",
"DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime",
"DB_ENC_KEY=" + utils.Config.Realtime.EncryptionKey,
Expand Down
12 changes: 12 additions & 0 deletions apps/cli-go/internal/db/start/templates/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,17 @@ ALTER USER supabase_storage_admin WITH PASSWORD :'pgpass';
ALTER USER supabase_replication_admin WITH PASSWORD :'pgpass';
ALTER USER supabase_read_only_user WITH PASSWORD :'pgpass';

-- supabase_realtime_admin is created by realtime's own tenant migrations on first
-- boot, so it does not exist in the base image. Create it up front (idempotently)
-- so realtime can authenticate as a least-privileged user from the start.
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_realtime_admin') THEN
CREATE ROLE supabase_realtime_admin WITH NOINHERIT CREATEROLE LOGIN REPLICATION;
END IF;
Comment on lines +21 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Promote existing realtime admin roles before using them

On existing local volumes that have already run Realtime's 202404 tenant migration, supabase_realtime_admin already exists but was created as NOLOGIN NOREPLICATION; this IF NOT EXISTS path skips the new LOGIN/REPLICATION attributes and only changes the password. After the startup env switches runtime connections to that role, upgraded stacks fail to authenticate as supabase_realtime_admin, so alter the role attributes even when it already exists and mirror that in the stack init copies.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mentioned "202404 tenant migration" is https://github.com/supabase/realtime/blob/main/lib/realtime/tenants/repo/migrations/20240401105812_create_realtime_admin_and_move_ownership.ex but that role is being updated by a later migration https://github.com/supabase/realtime/blob/main/lib/realtime/tenants/repo/migrations/20260606120000_setup_supabase_realtime_admin.ex which does ALTER ROLE supabase_realtime_admin WITH NOINHERIT CREATEROLE LOGIN REPLICATION

That migration is currently gated behind a feature flag in Realtime while we rollout the new permission schema but it's safe to create to CREATE ROLE supabase_realtime_admin WITH NOINHERIT CREATEROLE LOGIN REPLICATION here.

END
$$;
ALTER USER supabase_realtime_admin WITH PASSWORD :'pgpass';

create schema if not exists _realtime;
alter schema _realtime owner to postgres;
2 changes: 2 additions & 0 deletions apps/cli-go/internal/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,8 @@ EOF
fmt.Sprintf("DB_PORT=%d", dbConfig.Port),
"DB_USER=" + utils.SUPERUSER_ROLE,
"DB_PASSWORD=" + dbConfig.Password,
"DB_USER_REALTIME=supabase_realtime_admin",
"DB_PASS_REALTIME=" + dbConfig.Password,
Comment on lines +861 to +862

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Point Realtime at the least-privilege user

For the v2.109.1 Realtime image bumped in this change, the runtime connection username is still taken from DB_USER in config/runtime.exs; adding DB_USER_REALTIME here does not change the Repo credentials while DB_USER remains postgres. In those local stacks Realtime continues running all runtime DB traffic as the superuser, so the least-privilege change is ineffective unless the consumed DB user/password settings are switched or the image actually reads these new variables.

Useful? React with 👍 / 👎.

Comment on lines +861 to +862

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Install realtime grants before switching tenant connections

When this env is present, Realtime v2.109.1 seeds db_user_realtime and all non-migration tenant DB connections prefer supabase_realtime_admin; however the upstream migration that grants this role access to the realtime schema is gated behind the use_supabase_realtime_admin feature flag, which defaults off, and the role created in this change only has LOGIN/REPLICATION/CREATEROLE. In the default local stack, the first tenant connection/subscription then tries to read realtime.schema_migrations as a role with no schema/table grants and fails with permission denied, so either run/enable the setup grants before setting this env or leave it unset here and in the stack service until those grants are installed.

Useful? React with 👍 / 👎.

Comment on lines +861 to +862

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate realtime admin usage by Postgres version

When users keep a supported db.major_version of 14 or the CLI's default PG15 image (supabase/postgres:15.8.1.085), Realtime v2.109's compatibility matrix still requires the superuser path because those Postgres images lack the policy-grant/log-parameter delegation needed by supabase_realtime_admin. Setting DB_USER_REALTIME unconditionally makes the seeded tenant use the least-privilege role for runtime DB connections on those older supported stacks, so subscriptions can fail even after the role exists; only set these env vars for PG17/PG15.14.1.018+ images, or leave Realtime on the existing superuser credentials for older versions.

Useful? React with 👍 / 👎.

"DB_NAME=" + dbConfig.Database,
"DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime",
"DB_ENC_KEY=" + utils.Config.Realtime.EncryptionKey,
Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/pkg/config/templates/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ FROM supabase/edge-runtime:v1.74.1 AS edgeruntime
FROM timberio/vector:0.53.0-alpine AS vector
FROM supabase/supavisor:2.9.7 AS supavisor
FROM supabase/gotrue:v2.190.0 AS gotrue
FROM supabase/realtime:v2.108.0 AS realtime
FROM supabase/realtime:v2.109.1 AS realtime
FROM supabase/storage-api:v1.60.22 AS storage
FROM supabase/logflare:1.44.3 AS logflare
# Append to JobImages when adding new dependencies below
Expand Down
5 changes: 3 additions & 2 deletions packages/stack/src/StackBuilder.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,9 @@ describe("StackBuilder", () => {
});

const realtimeDef = graph.startOrder.find((service) => service.name === "realtime");
expect(realtimeDef?.args).toContain("supabase/realtime:v2.78.10");
expect(realtimeDef?.args).not.toContain("public.ecr.aws/supabase/realtime:v2.78.10");
const realtimeTag = `supabase/realtime:v${DEFAULT_VERSIONS.realtime}`;
expect(realtimeDef?.args).toContain(realtimeTag);
expect(realtimeDef?.args).not.toContain(`public.ecr.aws/${realtimeTag}`);
}).pipe(Effect.provide(layer));
});
});
8 changes: 7 additions & 1 deletion packages/stack/src/services/postgres-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,15 @@ EOSQL
${psql} -U supabase_admin -d postgres -c "
DO \\$\\$
DECLARE
roles text[] := ARRAY['authenticator','supabase_auth_admin','supabase_storage_admin','supabase_functions_admin','supabase_replication_admin','supabase_read_only_user','postgres'];
roles text[] := ARRAY['authenticator','supabase_auth_admin','supabase_storage_admin','supabase_functions_admin','supabase_replication_admin','supabase_read_only_user','supabase_realtime_admin','postgres'];
r text;
BEGIN
-- supabase_realtime_admin is created later by realtime's own tenant migrations,
-- so it is missing from the base image. Create it up front so the password loop
-- below can set its credentials and realtime can connect as a least-privileged user.
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'supabase_realtime_admin') THEN
CREATE ROLE supabase_realtime_admin WITH NOINHERIT CREATEROLE LOGIN REPLICATION;
END IF;
FOREACH r IN ARRAY roles LOOP
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = r) THEN
EXECUTE format('ALTER ROLE %I WITH PASSWORD ''postgres''', r);
Expand Down
8 changes: 8 additions & 0 deletions packages/stack/src/services/postgres.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ ALTER USER supabase_auth_admin WITH PASSWORD :'pgpass';
ALTER USER supabase_storage_admin WITH PASSWORD :'pgpass';
ALTER USER supabase_replication_admin WITH PASSWORD :'pgpass';
ALTER USER supabase_read_only_user WITH PASSWORD :'pgpass';
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_realtime_admin') THEN
CREATE ROLE supabase_realtime_admin WITH NOINHERIT CREATEROLE LOGIN REPLICATION;
END IF;
END
$$;
ALTER USER supabase_realtime_admin WITH PASSWORD :'pgpass';
create schema if not exists _realtime;
alter schema _realtime owner to postgres;
SELECT 'CREATE DATABASE _supabase WITH OWNER postgres'
Expand Down
2 changes: 2 additions & 0 deletions packages/stack/src/services/realtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export const makeRealtimeServiceDocker = (opts: DockerRealtimeOptions): ServiceD
DB_PORT: String(opts.dbPort),
DB_USER: "postgres",
DB_PASSWORD: "postgres",
DB_USER_REALTIME: "supabase_realtime_admin",
DB_PASS_REALTIME: "postgres",
DB_NAME: "postgres",
DB_AFTER_CONNECT_QUERY: "SET search_path TO _realtime",
DB_ENC_KEY: opts.encryptionKey,
Expand Down
2 changes: 1 addition & 1 deletion packages/stack/src/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const DEFAULT_VERSIONS: VersionManifest = {
postgrest: "14.5",
auth: "2.188.0-rc.15",
"edge-runtime": "1.73.13",
realtime: "2.78.10",
realtime: "2.109.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the stale realtime image assertion

Changing DEFAULT_VERSIONS.realtime here also changes the image selected by StackBuilder.unit.test.ts because that test passes DEFAULT_VERSIONS.realtime, but its fallback-registry assertions are still hard-coded to supabase/realtime:v2.78.10. In CI with dependencies installed, the stack unit suite will now fail even though the builder chooses the new v2.109.1 image; update those expected image strings with the version bump.

Useful? React with 👍 / 👎.

storage: "1.41.8",
imgproxy: "v3.8.0",
mailpit: "v1.22.3",
Expand Down
Loading