Skip to content

Commit 7bd9685

Browse files
authored
feat: add is_local() function to detect Supabase CLI environment (#502)
# Add `pgflow.is_local()` function to detect local development environment This PR adds a new SQL function `pgflow.is_local()` that detects whether the application is running in a local Supabase CLI environment by checking if the JWT secret matches the known hardcoded local value. The function: - Returns `true` only when the JWT secret exactly matches the Supabase CLI's default value - Returns `false` in all other cases (production environments, custom JWT secrets) - Is designed to be production-safe with a default of `false` - Uses `coalesce` to handle missing configuration values Added comprehensive tests to verify the function works correctly in different scenarios: - When JWT secret matches the local Supabase value - When JWT secret is empty/missing (simulates hosted environments) - When JWT secret has a different custom value This utility will help implement environment-specific behaviors without requiring explicit configuration.
1 parent 98289a7 commit 7bd9685

5 files changed

Lines changed: 57 additions & 1 deletion

File tree

‎pkgs/core/schemas/0030_utilities.sql‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
-- Utility functions that don't depend on other entities
22

3+
-- Detects if running in local Supabase CLI environment
4+
-- by checking if JWT secret matches the known hardcoded local value.
5+
-- Returns true only for exact match; defaults to false (production-safe).
6+
create or replace function pgflow.is_local()
7+
returns boolean
8+
language sql
9+
stable
10+
parallel safe
11+
set search_path = ''
12+
as $$
13+
select coalesce(
14+
current_setting('app.settings.jwt_secret', true)
15+
= 'super-secret-jwt-token-with-at-least-32-characters-long',
16+
false
17+
)
18+
$$;
19+
320
create or replace function pgflow.is_valid_slug(
421
slug text
522
)

‎pkgs/core/src/database-types.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ export type Database = {
483483
}
484484
}
485485
get_run_with_states: { Args: { run_id: string }; Returns: Json }
486+
is_local: { Args: never; Returns: boolean }
486487
is_valid_slug: { Args: { slug: string }; Returns: boolean }
487488
maybe_complete_run: { Args: { run_id: string }; Returns: undefined }
488489
poll_for_tasks: {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Create "is_local" function
2+
CREATE FUNCTION "pgflow"."is_local" () RETURNS boolean LANGUAGE sql STABLE PARALLEL SAFE SET "search_path" = '' AS $$
3+
select coalesce(
4+
current_setting('app.settings.jwt_secret', true)
5+
= 'super-secret-jwt-token-with-at-least-32-characters-long',
6+
false
7+
)
8+
$$;

‎pkgs/core/supabase/migrations/atlas.sum‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
h1:zJB8nH4leuvGPgSDItehBjrRGuE1kgEV5ucwUlzAknE=
1+
h1:+t6j1CJcFBfV6SRbAz/7/mVgZeS9vmzWWC+b1/Mp3GA=
22
20250429164909_pgflow_initial.sql h1:I3n/tQIg5Q5nLg7RDoU3BzqHvFVjmumQxVNbXTPG15s=
33
20250517072017_pgflow_fix_poll_for_tasks_to_use_separate_statement_for_polling.sql h1:wTuXuwMxVniCr3ONCpodpVWJcHktoQZIbqMZ3sUHKMY=
44
20250609105135_pgflow_add_start_tasks_and_started_status.sql h1:ggGanW4Wyt8Kv6TWjnZ00/qVb3sm+/eFVDjGfT8qyPg=
@@ -12,3 +12,4 @@ h1:zJB8nH4leuvGPgSDItehBjrRGuE1kgEV5ucwUlzAknE=
1212
20251103222045_pgflow_fix_broadcast_order_and_timestamp_handling.sql h1:K/XnZpOmxfelsaNoJbR5HxhBrs/oW4aYja222h5cps4=
1313
20251104080523_pgflow_upgrade_pgmq_1_5_1.sql h1:Fw7zpMWnjhAHQ0qBJAprAvGl7dJMd8ExNHg8aKvkzTg=
1414
20251130000000_pgflow_auto_compilation.sql h1:qs+3qq1Vsyo0ETzbxDnmkVtSUa6XHkd/K9wF/3W46jM=
15+
20251204115929_pgflow_temp_is_local.sql h1:arP+PC2OYI9ktAFx0+G9/w8zsaq/AbFWjLgK6YDujvQ=
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
begin;
2+
select plan(3);
3+
select pgflow_tests.reset_db();
4+
5+
-- TEST: Returns true when jwt_secret matches known local Supabase value
6+
-- The local Supabase CLI always uses this exact hardcoded JWT secret
7+
select set_config('app.settings.jwt_secret', 'super-secret-jwt-token-with-at-least-32-characters-long', true);
8+
select ok(
9+
pgflow.is_local(),
10+
'is_local() returns true when jwt_secret matches local Supabase value'
11+
);
12+
13+
-- TEST: Returns false when jwt_secret is empty/missing (simulates hosted Supabase after Nov 2024)
14+
-- Note: set_config with NULL is ignored, so we use empty string to simulate missing value
15+
select set_config('app.settings.jwt_secret', '', true);
16+
select ok(
17+
not pgflow.is_local(),
18+
'is_local() returns false when jwt_secret is empty/missing'
19+
);
20+
21+
-- TEST: Returns false when jwt_secret is a different value (self-hosted or custom)
22+
select set_config('app.settings.jwt_secret', 'some-other-custom-jwt-secret-value', true);
23+
select ok(
24+
not pgflow.is_local(),
25+
'is_local() returns false when jwt_secret is a different value'
26+
);
27+
28+
select finish();
29+
rollback;

0 commit comments

Comments
 (0)