mirror of
https://github.com/supabase/supabase.git
synced 2026-09-22 13:37:53 +08:00
bb4eaef0df
## Context This is one chonky boy of a PR, but it's just re-organizing files and folders to clean things up Storage Policies have been using the old Database policy UI (the one with the Dialog), so it makes most sense to shift those files under the `Storage` folder instead of keeping them under `Database`, so it's clearer which files are being consumed by whom, and easier to clean things up as well As part of this clean up, also tore out all the RLS generation logic from the Table Editor which are no longer used as they were affected by the change in files. Deprecated + deleted any unused code too <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Enhanced the policy editor with a centralized set of reusable templates, including general table templates plus predefined Realtime and queue access templates. * Updated the table creation flow so it no longer auto-generates additional RLS policy drafts. * **Bug Fixes** * Improved the policy table header badge layout for clearer RLS/API/lock indicators. * Simplified policy preview/save behavior so only meaningful edits are reflected in the applied SQL. * Streamlined the table-creation success messaging to remove conditional failure details. * **Tests** * Updated/removal of policy and table-creation test coverage to match the new behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
342 lines
13 KiB
TypeScript
342 lines
13 KiB
TypeScript
import { safeSql } from '@supabase/pg-meta/src/pg-format'
|
|
import type { SafeSqlFragment } from '@supabase/pg-meta/src/pg-format'
|
|
|
|
export interface PolicyTemplate {
|
|
id: string
|
|
preview: boolean
|
|
templateName: string
|
|
description: string
|
|
name: string
|
|
statement: string
|
|
definition: SafeSqlFragment
|
|
check: SafeSqlFragment
|
|
command: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE' | 'ALL'
|
|
roles: Array<string>
|
|
}
|
|
|
|
/**
|
|
* ----------------------------------------------------------------
|
|
* PostgreSQL policy templates for the auth policies page
|
|
* ----------------------------------------------------------------
|
|
* id: Unique identifier for the monaco editor to dynamically refresh
|
|
* templateName: As a display for a more descriptive title for the policy
|
|
* description: Additional details about the template and how to make it yours
|
|
* statement: SQL statement template for the policy
|
|
*
|
|
* name: Actual policy name that will be used in the editor
|
|
* definition: Actual policy using expression that will be used in the editor
|
|
* check: Actual policy with check expression that will be used in the editor
|
|
* command: Operation to create policy for
|
|
*/
|
|
|
|
export const getGeneralPolicyTemplates = (schema: string, table: string): PolicyTemplate[] => [
|
|
{
|
|
id: 'policy-1',
|
|
preview: false,
|
|
templateName: 'Enable read access to everyone',
|
|
description:
|
|
'This policy gives read access to your table for all users via the SELECT operation.',
|
|
statement: `
|
|
create policy "Enable read access for all users"
|
|
on "${schema}"."${table}"
|
|
for select using (true);`.trim(),
|
|
name: 'Enable read access for all users',
|
|
definition: safeSql`true`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-2',
|
|
preview: false,
|
|
templateName: 'Enable insert access for authenticated users only',
|
|
description: 'This policy gives insert access to your table for all authenticated users only.',
|
|
statement: `
|
|
create policy "Enable insert for authenticated users only"
|
|
on "${schema}"."${table}"
|
|
for insert to authenticated
|
|
with check (true);`.trim(),
|
|
name: 'Enable insert for authenticated users only',
|
|
definition: safeSql``,
|
|
check: safeSql`true`,
|
|
command: 'INSERT',
|
|
roles: ['authenticated'],
|
|
},
|
|
{
|
|
id: 'policy-3',
|
|
preview: false,
|
|
templateName: 'Enable delete access for users based on their user ID *',
|
|
description:
|
|
'This policy assumes that your table has a column "user_id", and allows users to delete rows which the "user_id" column matches their ID',
|
|
statement: `
|
|
create policy "Enable delete for users based on user_id"
|
|
on "${schema}"."${table}"
|
|
for delete using (
|
|
(select auth.uid()) = user_id
|
|
);`.trim(),
|
|
name: 'Enable delete for users based on user_id',
|
|
definition: safeSql`(select auth.uid()) = user_id`,
|
|
check: safeSql``,
|
|
command: 'DELETE',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-4',
|
|
preview: false,
|
|
templateName: 'Enable insert access for users based on their user ID *',
|
|
description:
|
|
'This policy assumes that your table has a column "user_id", and allows users to insert rows which the "user_id" column matches their ID',
|
|
statement: `
|
|
create policy "Enable insert for users based on user_id"
|
|
on "${schema}"."${table}"
|
|
for insert with check (
|
|
(select auth.uid()) = user_id
|
|
);`.trim(),
|
|
name: 'Enable insert for users based on user_id',
|
|
definition: safeSql``,
|
|
check: safeSql`(select auth.uid()) = user_id`,
|
|
command: 'INSERT',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-5',
|
|
preview: true,
|
|
name: 'Policy with table joins',
|
|
templateName: 'Policy with table joins',
|
|
description: `
|
|
Query across tables to build more advanced RLS rules
|
|
|
|
Assuming 2 tables called \`teams\` and \`members\`, you can query both tables in the policy to control access to the members table.`,
|
|
statement: `
|
|
create policy "Members can update team details if they belong to the team"
|
|
on teams for update using (
|
|
(select auth.uid()) in (
|
|
select user_id from members where team_id = id
|
|
)
|
|
);
|
|
`.trim(),
|
|
definition: safeSql`(select auth.uid()) in (select user_id from members where team_id = id)`,
|
|
check: safeSql``,
|
|
command: 'UPDATE',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-6',
|
|
preview: true,
|
|
templateName: 'Policy with security definer functions',
|
|
description: `
|
|
Useful in a many-to-many relationship where you want to restrict access to the linking table.
|
|
|
|
Assuming 2 tables called \`teams\` and \`members\`, you can use a security definer function in combination with a policy to control access to the members table.`.trim(),
|
|
statement: `
|
|
create or replace function get_teams_for_user(user_id uuid)
|
|
returns setof bigint as $$
|
|
select team_id from members where user_id = $1
|
|
$$ stable language sql security definer;
|
|
|
|
create policy "Team members can update team members if they belong to the team"
|
|
on members
|
|
for all using (
|
|
team_id in (select get_teams_for_user(auth.uid()))
|
|
);
|
|
`.trim(),
|
|
name: 'Policy with security definer functions',
|
|
definition: safeSql`team_id in (select get_teams_for_user(auth.uid()))`,
|
|
check: safeSql``,
|
|
command: 'ALL',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-7',
|
|
preview: true,
|
|
name: 'Policy to implement Time To Live (TTL)',
|
|
templateName: 'Policy to implement Time To Live (TTL)',
|
|
description: `
|
|
Implement a TTL-like feature that you see in Instagram stories or Snapchat where messages expire after a day.
|
|
|
|
Rows under the table are available only if they have been created within the last 24 hours.`,
|
|
statement: `
|
|
create policy "Stories are live for a day"
|
|
on "${schema}"."${table}"
|
|
for select using (
|
|
created_at > (current_timestamp - interval '1 day')
|
|
);
|
|
`.trim(),
|
|
definition: safeSql`created_at > (current_timestamp - interval '1 day')`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-8',
|
|
preview: false,
|
|
templateName: 'Allow users to only view their own data',
|
|
description: 'Restrict users to reading only their own data.',
|
|
statement: `
|
|
create policy "Enable users to view their own data only"
|
|
on "${schema}"."${table}"
|
|
for select
|
|
to authenticated
|
|
using (
|
|
(select auth.uid()) = user_id
|
|
);`.trim(),
|
|
name: 'Enable users to view their own data only',
|
|
definition: safeSql`(select auth.uid()) = user_id`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: ['authenticated'],
|
|
},
|
|
]
|
|
|
|
export const getRealtimePolicyTemplates = (): PolicyTemplate[] => {
|
|
const results = [
|
|
{
|
|
id: 'policy-broadcast-1',
|
|
preview: false,
|
|
templateName: 'Allow listening for broadcasts for authenticated users only',
|
|
description: 'This policy allows listening for broadcasts for authenticated users only.',
|
|
statement: `
|
|
create policy "Allow listening for broadcasts for authenticated users only"
|
|
on realtime.messages for select
|
|
to authenticated
|
|
using ( realtime.messages.extension = 'broadcast' );`.trim(),
|
|
name: 'Allow listening for broadcasts for authenticated users only',
|
|
definition: safeSql`realtime.messages.extension = 'broadcast'`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: ['authenticated'],
|
|
},
|
|
{
|
|
id: 'policy-broadcast-2',
|
|
preview: false,
|
|
templateName: 'Allow pushing broadcasts for authenticated users only',
|
|
description: 'This policy allows pushing broadcasts for authenticated users only.',
|
|
statement: `
|
|
create policy "Allow pushing broadcasts for authenticated users only"
|
|
ON realtime.messages for insert
|
|
TO authenticated
|
|
with check ( realtime.messages.extension = 'broadcast' );`.trim(),
|
|
name: 'Allow pushing broadcasts for authenticated users only',
|
|
definition: safeSql`realtime.messages.extension = 'broadcast'`,
|
|
check: safeSql`realtime.messages.extension = 'broadcast'`,
|
|
command: 'INSERT',
|
|
roles: ['authenticated'],
|
|
},
|
|
{
|
|
id: 'policy-broadcast-3',
|
|
preview: false,
|
|
templateName: 'Allow listening for broadcasts from a specific channel',
|
|
description: 'This policy allows listening for broadcasts from a specific channel.',
|
|
statement: `
|
|
create policy "Allow listening for broadcasts from a specific channel"
|
|
on realtime.messages for select
|
|
using ( realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name' );`.trim(),
|
|
name: 'Allow listening for broadcasts from a specific channel',
|
|
definition: safeSql`realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name'`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-broadcast-4',
|
|
preview: false,
|
|
templateName: 'Allow pushing broadcasts to specific channel',
|
|
description: 'This policy allow pushing broadcasts to specific channel.',
|
|
statement: `
|
|
create policy "Allow pushing broadcasts to specific channel"
|
|
ON realtime.messages for insert
|
|
with check ( realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name' );`.trim(),
|
|
name: 'Allow pushing broadcasts to specific channel',
|
|
definition: safeSql`realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name'`,
|
|
check: safeSql`realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name'`,
|
|
command: 'INSERT',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-presences-1',
|
|
preview: false,
|
|
templateName: 'Allow listening for presences on all channels for authenticated users only',
|
|
description:
|
|
'This policy enables listening for presences on all channels for all authenticated users only.',
|
|
statement: `
|
|
create policy "Allow listening for presences on all channels for authenticated users only"
|
|
on realtime.messages for select
|
|
to authenticated
|
|
using ( realtime.messages.extension = 'presence' );`.trim(),
|
|
name: 'Allow listening for presences on all channels for authenticated users only',
|
|
definition: safeSql`realtime.messages.extension = 'presence'`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: ['authenticated'],
|
|
},
|
|
{
|
|
id: 'policy-presences-2',
|
|
preview: false,
|
|
templateName: 'Allow broadcasting presences on all channels for authenticated users only',
|
|
description:
|
|
'This policy enables broadcasting presences on all channels for all authenticated users only.',
|
|
statement: `
|
|
create policy "Allow broadcasting presences on all channels for authenticated users only"
|
|
ON realtime.messages for insert
|
|
TO authenticated
|
|
with check ( realtime.messages.extension = 'presence' );
|
|
;`.trim(),
|
|
name: 'Allow broadcasting presences on all channels for authenticated users only',
|
|
definition: safeSql`realtime.messages.extension = 'presence'`,
|
|
check: safeSql`realtime.messages.extension = 'presence'`,
|
|
command: 'INSERT',
|
|
roles: ['authenticated'],
|
|
},
|
|
{
|
|
id: 'policy-presences-3',
|
|
preview: false,
|
|
templateName: 'Allow listening for presences from a specific channel',
|
|
description: 'This policy enables listening for presences from a specific channel.',
|
|
statement: `
|
|
create policy "Allow listening for presences from a specific channel"
|
|
on realtime.messages for select
|
|
using ( realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name' );`.trim(),
|
|
name: 'Allow listening for presences from a specific channel',
|
|
definition: safeSql`realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name'`,
|
|
check: safeSql``,
|
|
command: 'SELECT',
|
|
roles: [],
|
|
},
|
|
{
|
|
id: 'policy-presences-4',
|
|
preview: false,
|
|
templateName: 'Publish presence to a specific channel',
|
|
description: 'This policy allows publishing presence to a specific channel.',
|
|
statement: `
|
|
create policy "Publish presence to a specific channel"
|
|
ON realtime.messages for insert
|
|
with check ( realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name' );
|
|
;`.trim(),
|
|
name: 'Publish presence to a specific channel',
|
|
definition: safeSql`realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name'`,
|
|
check: safeSql`realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name'`,
|
|
command: 'INSERT',
|
|
roles: [],
|
|
},
|
|
] as PolicyTemplate[]
|
|
return results
|
|
}
|
|
|
|
export const getQueuePolicyTemplates = (): PolicyTemplate[] => {
|
|
return [
|
|
{
|
|
id: 'policy-queues-1',
|
|
preview: false,
|
|
templateName: 'Allow access to queue',
|
|
statement: ``.trim(),
|
|
name: 'Allow anon and authenticated to access messages from queue',
|
|
description:
|
|
'Base policy to ensure that anon and authenticated can only access appropriate rows. USING and CHECK statements will need to be adjusted accordingly',
|
|
definition: safeSql`true`,
|
|
check: safeSql`true`,
|
|
command: 'ALL',
|
|
roles: ['anon', 'authenticated'],
|
|
},
|
|
]
|
|
}
|