@selvajs/supabase-provider 0.20.0-beta.3 → 0.20.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/auth/SupabaseAuthProvider.d.ts.map +1 -1
- package/dist/auth/SupabaseAuthProvider.js +2 -8
- package/dist/auth/SupabaseAuthProvider.js.map +1 -1
- package/dist/data/SupabaseAuditQuery.js +1 -1
- package/dist/data/SupabaseAuditQuery.js.map +1 -1
- package/dist/data/SupabaseComputeServerStore.d.ts +5 -4
- package/dist/data/SupabaseComputeServerStore.d.ts.map +1 -1
- package/dist/data/SupabaseComputeServerStore.js +53 -77
- package/dist/data/SupabaseComputeServerStore.js.map +1 -1
- package/dist/data/SupabaseDefinitionStore.js +7 -6
- package/dist/data/SupabaseDefinitionStore.js.map +1 -1
- package/dist/data/SupabaseInviteStore.d.ts +1 -1
- package/dist/data/SupabaseInviteStore.d.ts.map +1 -1
- package/dist/data/SupabaseInviteStore.js +3 -2
- package/dist/data/SupabaseInviteStore.js.map +1 -1
- package/dist/data/SupabaseOrgStore.d.ts.map +1 -1
- package/dist/data/SupabaseOrgStore.js +10 -34
- package/dist/data/SupabaseOrgStore.js.map +1 -1
- package/dist/data/SupabaseProjectStore.d.ts.map +1 -1
- package/dist/data/SupabaseProjectStore.js +15 -12
- package/dist/data/SupabaseProjectStore.js.map +1 -1
- package/dist/data/SupabaseShareLinkStore.d.ts.map +1 -1
- package/dist/data/SupabaseShareLinkStore.js +34 -29
- package/dist/data/SupabaseShareLinkStore.js.map +1 -1
- package/dist/data/SupabaseSolveMetricSink.d.ts +11 -3
- package/dist/data/SupabaseSolveMetricSink.d.ts.map +1 -1
- package/dist/data/SupabaseSolveMetricSink.js +38 -14
- package/dist/data/SupabaseSolveMetricSink.js.map +1 -1
- package/dist/data/errors.d.ts.map +1 -1
- package/dist/data/errors.js +3 -0
- package/dist/data/errors.js.map +1 -1
- package/dist/data/migrationHead.d.ts +1 -1
- package/dist/data/migrationHead.js +1 -1
- package/dist/data/pagination.d.ts +2 -3
- package/dist/data/pagination.d.ts.map +1 -1
- package/dist/data/pagination.js +6 -15
- package/dist/data/pagination.js.map +1 -1
- package/dist/permissions/SupabasePlatformPermissionStore.d.ts +2 -2
- package/dist/permissions/SupabasePlatformPermissionStore.d.ts.map +1 -1
- package/dist/permissions/SupabasePlatformPermissionStore.js +10 -49
- package/dist/permissions/SupabasePlatformPermissionStore.js.map +1 -1
- package/dist/storage/SupabaseStorageProvider.d.ts +3 -2
- package/dist/storage/SupabaseStorageProvider.d.ts.map +1 -1
- package/dist/storage/SupabaseStorageProvider.js +30 -19
- package/dist/storage/SupabaseStorageProvider.js.map +1 -1
- package/dist/userProfile/SupabaseUserProfileProvider.d.ts +7 -0
- package/dist/userProfile/SupabaseUserProfileProvider.d.ts.map +1 -1
- package/dist/userProfile/SupabaseUserProfileProvider.js +9 -19
- package/dist/userProfile/SupabaseUserProfileProvider.js.map +1 -1
- package/package.json +8 -7
- package/supabase/migrations/20261101152228_selva_revoke_privileged_functions.sql +44 -0
- package/supabase/migrations/20261101160000_selva_rls_is_the_boundary.sql +527 -0
- package/supabase/migrations/20261101170000_selva_compute_api_key_private.sql +14 -0
- package/supabase/migrations/20261101180000_selva_erasure_keeps_tenant_data.sql +28 -0
- package/supabase/migrations/20261101190000_selva_atomic_compute_save.sql +136 -0
- package/supabase/migrations/20261101200000_selva_last_admin_lock_order.sql +62 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- A compute save lands whole or not at all
|
|
3
|
+
--
|
|
4
|
+
-- Security invoker, so the existing policies still decide who may write. Rows
|
|
5
|
+
-- that stay are updated rather than deleted and reinserted: deleting clears
|
|
6
|
+
-- `compute_server_org_defaults` through its FK. The update comes before an
|
|
7
|
+
-- `on conflict do nothing` insert because reading `excluded.api_key` would need
|
|
8
|
+
-- the SELECT that sessions no longer have on that column.
|
|
9
|
+
-- ============================================================================
|
|
10
|
+
|
|
11
|
+
create or replace function selva.save_platform_compute_servers(
|
|
12
|
+
servers jsonb,
|
|
13
|
+
shares jsonb,
|
|
14
|
+
default_server uuid
|
|
15
|
+
)
|
|
16
|
+
returns void
|
|
17
|
+
language plpgsql set search_path = public
|
|
18
|
+
as $$
|
|
19
|
+
declare
|
|
20
|
+
submitted integer := jsonb_array_length(servers);
|
|
21
|
+
saved integer;
|
|
22
|
+
added integer;
|
|
23
|
+
begin
|
|
24
|
+
delete from selva.compute_servers c
|
|
25
|
+
where c.scope = 'platform'
|
|
26
|
+
and c.id not in (select (s ->> 'id')::uuid from jsonb_array_elements(servers) s);
|
|
27
|
+
|
|
28
|
+
update selva.compute_servers c
|
|
29
|
+
set label = x.label, server_url = x.server_url, api_key = x.api_key,
|
|
30
|
+
timeout_ms = x.timeout_ms, retry_count = x.retry_count,
|
|
31
|
+
shared_with_all = x.shared_with_all
|
|
32
|
+
from jsonb_to_recordset(servers) as x(
|
|
33
|
+
id uuid, label text, server_url text, api_key text,
|
|
34
|
+
timeout_ms integer, retry_count integer, shared_with_all boolean
|
|
35
|
+
)
|
|
36
|
+
where c.id = x.id and c.scope = 'platform';
|
|
37
|
+
get diagnostics saved = row_count;
|
|
38
|
+
|
|
39
|
+
insert into selva.compute_servers
|
|
40
|
+
(id, scope, label, server_url, api_key, timeout_ms, retry_count, shared_with_all)
|
|
41
|
+
select x.id, 'platform', x.label, x.server_url, x.api_key, x.timeout_ms, x.retry_count,
|
|
42
|
+
x.shared_with_all
|
|
43
|
+
from jsonb_to_recordset(servers) as x(
|
|
44
|
+
id uuid, label text, server_url text, api_key text,
|
|
45
|
+
timeout_ms integer, retry_count integer, shared_with_all boolean
|
|
46
|
+
)
|
|
47
|
+
on conflict (id) do nothing;
|
|
48
|
+
get diagnostics added = row_count;
|
|
49
|
+
|
|
50
|
+
-- The insert skips what the update handled, so the two only fall short on a
|
|
51
|
+
-- collision.
|
|
52
|
+
if saved + added < submitted then
|
|
53
|
+
raise exception 'A compute server id is already in use' using errcode = '23505';
|
|
54
|
+
end if;
|
|
55
|
+
|
|
56
|
+
delete from selva.compute_server_shares cs
|
|
57
|
+
using selva.compute_servers c
|
|
58
|
+
where c.id = cs.server_id and c.scope = 'platform';
|
|
59
|
+
|
|
60
|
+
insert into selva.compute_server_shares (server_id, org_id)
|
|
61
|
+
select x.server_id, x.org_id
|
|
62
|
+
from jsonb_to_recordset(shares) as x(server_id uuid, org_id uuid);
|
|
63
|
+
|
|
64
|
+
update selva.compute_server_platform_default
|
|
65
|
+
set default_server_id = default_server
|
|
66
|
+
where singleton;
|
|
67
|
+
end;
|
|
68
|
+
$$;
|
|
69
|
+
|
|
70
|
+
-- `set_default` is false to leave the org's default as it stands, whatever
|
|
71
|
+
-- `default_server` holds; with it true, a null `default_server` clears it.
|
|
72
|
+
create or replace function selva.save_org_compute_servers(
|
|
73
|
+
o uuid,
|
|
74
|
+
servers jsonb,
|
|
75
|
+
set_default boolean,
|
|
76
|
+
default_server uuid
|
|
77
|
+
)
|
|
78
|
+
returns void
|
|
79
|
+
language plpgsql set search_path = public
|
|
80
|
+
as $$
|
|
81
|
+
declare
|
|
82
|
+
submitted integer := jsonb_array_length(servers);
|
|
83
|
+
saved integer;
|
|
84
|
+
added integer;
|
|
85
|
+
begin
|
|
86
|
+
delete from selva.compute_servers c
|
|
87
|
+
where c.scope = 'org' and c.owner_org_id = o
|
|
88
|
+
and c.id not in (select (s ->> 'id')::uuid from jsonb_array_elements(servers) s);
|
|
89
|
+
|
|
90
|
+
update selva.compute_servers c
|
|
91
|
+
set label = x.label, server_url = x.server_url, api_key = x.api_key,
|
|
92
|
+
timeout_ms = x.timeout_ms, retry_count = x.retry_count
|
|
93
|
+
from jsonb_to_recordset(servers) as x(
|
|
94
|
+
id uuid, label text, server_url text, api_key text,
|
|
95
|
+
timeout_ms integer, retry_count integer
|
|
96
|
+
)
|
|
97
|
+
where c.id = x.id and c.scope = 'org' and c.owner_org_id = o;
|
|
98
|
+
get diagnostics saved = row_count;
|
|
99
|
+
|
|
100
|
+
insert into selva.compute_servers
|
|
101
|
+
(id, scope, owner_org_id, label, server_url, api_key, timeout_ms, retry_count)
|
|
102
|
+
select x.id, 'org', o, x.label, x.server_url, x.api_key, x.timeout_ms, x.retry_count
|
|
103
|
+
from jsonb_to_recordset(servers) as x(
|
|
104
|
+
id uuid, label text, server_url text, api_key text,
|
|
105
|
+
timeout_ms integer, retry_count integer
|
|
106
|
+
)
|
|
107
|
+
on conflict (id) do nothing;
|
|
108
|
+
get diagnostics added = row_count;
|
|
109
|
+
|
|
110
|
+
-- A colliding id belongs to another org or the platform, and this says no more
|
|
111
|
+
-- than that: the session may not be able to see the row.
|
|
112
|
+
if saved + added < submitted then
|
|
113
|
+
raise exception 'A compute server id is already in use' using errcode = '23505';
|
|
114
|
+
end if;
|
|
115
|
+
|
|
116
|
+
if set_default then
|
|
117
|
+
if default_server is null then
|
|
118
|
+
delete from selva.compute_server_org_defaults where org_id = o;
|
|
119
|
+
else
|
|
120
|
+
insert into selva.compute_server_org_defaults (org_id, default_server_id)
|
|
121
|
+
values (o, default_server)
|
|
122
|
+
on conflict (org_id) do update set default_server_id = excluded.default_server_id;
|
|
123
|
+
end if;
|
|
124
|
+
end if;
|
|
125
|
+
end;
|
|
126
|
+
$$;
|
|
127
|
+
|
|
128
|
+
revoke all on function
|
|
129
|
+
selva.save_platform_compute_servers(jsonb, jsonb, uuid),
|
|
130
|
+
selva.save_org_compute_servers(uuid, jsonb, boolean, uuid)
|
|
131
|
+
from public, anon;
|
|
132
|
+
|
|
133
|
+
grant execute on function
|
|
134
|
+
selva.save_platform_compute_servers(jsonb, jsonb, uuid),
|
|
135
|
+
selva.save_org_compute_servers(uuid, jsonb, boolean, uuid)
|
|
136
|
+
to authenticated, service_role;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- Concurrent permission writes queue instead of deadlocking
|
|
3
|
+
--
|
|
4
|
+
-- Each call locks its target, then the surviving admins, so two admins demoting
|
|
5
|
+
-- each other hold what the other wants. Postgres kills one and that caller gets
|
|
6
|
+
-- a 40P01 rather than `last_admin`. The advisory lock lets one call run at a
|
|
7
|
+
-- time, which is cheap: permission writes are rare.
|
|
8
|
+
-- ============================================================================
|
|
9
|
+
|
|
10
|
+
create or replace function selva.set_platform_permissions(
|
|
11
|
+
p_user_id uuid,
|
|
12
|
+
p_permissions text[]
|
|
13
|
+
)
|
|
14
|
+
returns integer
|
|
15
|
+
language plpgsql security definer set search_path = public
|
|
16
|
+
as $$
|
|
17
|
+
declare
|
|
18
|
+
v_is_demotion boolean;
|
|
19
|
+
v_others integer;
|
|
20
|
+
v_updated integer;
|
|
21
|
+
begin
|
|
22
|
+
perform pg_advisory_xact_lock(hashtext('selva.set_platform_permissions'));
|
|
23
|
+
|
|
24
|
+
select 'instance_admin' = any(platform_permissions)
|
|
25
|
+
and not ('instance_admin' = any(p_permissions))
|
|
26
|
+
into v_is_demotion
|
|
27
|
+
from selva.user_profiles
|
|
28
|
+
where user_id = p_user_id
|
|
29
|
+
for update;
|
|
30
|
+
|
|
31
|
+
if not found then
|
|
32
|
+
return 0;
|
|
33
|
+
end if;
|
|
34
|
+
|
|
35
|
+
if v_is_demotion then
|
|
36
|
+
-- Row locks still guard against `disabled` changing underneath the count.
|
|
37
|
+
perform 1
|
|
38
|
+
from selva.user_profiles
|
|
39
|
+
where user_id <> p_user_id
|
|
40
|
+
and disabled = false
|
|
41
|
+
and 'instance_admin' = any(platform_permissions)
|
|
42
|
+
for update;
|
|
43
|
+
|
|
44
|
+
select count(*) into v_others
|
|
45
|
+
from selva.user_profiles
|
|
46
|
+
where user_id <> p_user_id
|
|
47
|
+
and disabled = false
|
|
48
|
+
and 'instance_admin' = any(platform_permissions);
|
|
49
|
+
|
|
50
|
+
if v_others = 0 then
|
|
51
|
+
return 0;
|
|
52
|
+
end if;
|
|
53
|
+
end if;
|
|
54
|
+
|
|
55
|
+
update selva.user_profiles
|
|
56
|
+
set platform_permissions = p_permissions
|
|
57
|
+
where user_id = p_user_id;
|
|
58
|
+
|
|
59
|
+
get diagnostics v_updated = row_count;
|
|
60
|
+
return v_updated;
|
|
61
|
+
end;
|
|
62
|
+
$$;
|