mirror of
https://github.com/supabase/supabase.git
synced 2026-06-16 02:26:42 +08:00
## 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 / security improvement ## What is the current behavior? SQL fragments across Studio are built from plain `string` values with no type-level distinction between developer-authored SQL, DB-sourced identifiers, and user-typed or externally-influenced content. ## What is the new behavior? Extends the safe SQL model to additional Studio interfaces, using `SafeSqlFragment`, `safeSql`, `ident()`, `literal()`, `untrustedSql()`, and `acceptUntrustedSql()` from `@supabase/pg-meta/src/pg-format`: - **Policy editor**: template constants typed as `SafeSqlFragment` via `safeSql` tagged literals; Monaco editor `onInputChange` emits `untrustedSql()`; `acceptUntrustedSql()` called only at the Save gesture; roles selector emits a composed `SafeSqlFragment` via `ident()` + `joinSqlFragments()` - **Auth hooks**: grant/revoke SQL statements use `ident()` for schema and function names - **Docs description editor**: `COMMENT ON` queries use `ident()` and `literal()` for table/column/function names and values - **Cron jobs**: `cron.schedule()` call and HTTP request builder use `literal()` for all user-provided values - **GraphQL linter CTA**: `REVOKE` statement uses `ident()` for schema, table, and role - **Storage public bucket warning**: `DROP POLICY` uses `ident()` for policy name - **View security autofix modal**: `ALTER VIEW` uses `ident()` for schema and view name - **API settings**: `CREATE SCHEMA` mutation uses `safeSql` tagged literal - **Database event trigger delete**: `DROP EVENT TRIGGER` uses `ident()` for trigger name - **Database queues query**: queue list query uses `safeSql` tagged literal - **Role impersonation**: function invocation SQL uses `ident()` and `literal()` ## Manual testing checklist - Authentication > Policies - Authentication > Hooks - Integrations > Queues - Database > Event Triggers - Integrations > Cron Jobs - Table Editor > View entity security autofix - API Settings > expose schema - Linter > GraphQL exposure CTA - Docs > table/column description editor - Role impersonation (user impersonation panel) ## Additional context <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Replaced ad-hoc SQL string building with a safer, fragment-based SQL construction across auth, policies, integrations, storage, and DB operations to improve SQL safety while preserving behavior. * **Bug Fixes / UX** * Policy editor and code editor now propagate role and input changes more reliably, improving editor responsiveness and policy handling without UI changes. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import { ident, safeSql, type SafeSqlFragment } from '@supabase/pg-meta/src/pg-format'
|
|
|
|
import { Hook } from './hooks.constants'
|
|
|
|
export const extractMethod = (
|
|
uri: string,
|
|
secret?: string
|
|
):
|
|
| { type: 'postgres'; schema: string; functionName: string }
|
|
| { type: 'https'; url: string; secret: string } => {
|
|
if (uri.startsWith('https')) {
|
|
return { type: 'https', url: uri, secret: secret || '' }
|
|
} else {
|
|
const [_proto, _x, _db, schema, functionName] = (uri || '').split('/')
|
|
|
|
return {
|
|
type: 'postgres',
|
|
schema: schema || '',
|
|
functionName: functionName || '',
|
|
}
|
|
}
|
|
}
|
|
|
|
export const isValidHook = (h: Hook) => {
|
|
return (
|
|
(h.method.type === 'postgres' &&
|
|
h.method.schema.length > 0 &&
|
|
h.method.functionName.length > 0) ||
|
|
(h.method.type === 'https' && h.method.url.startsWith('https') && h.method.secret.length > 0)
|
|
)
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param schema the schema that the function belongs to
|
|
* @param functionName the function name associated with the hook
|
|
* @returns an array of SQL statements to restore the original permissions to the function
|
|
*/
|
|
export const getRevokePermissionStatements = (
|
|
schema: string,
|
|
functionName: string
|
|
): Array<SafeSqlFragment> => {
|
|
return [
|
|
safeSql`-- Revoke access to function from supabase_auth_admin
|
|
revoke execute on function ${ident(schema)}.${ident(functionName)} from supabase_auth_admin;`,
|
|
safeSql`-- Revoke access to schema from supabase_auth_admin
|
|
revoke usage on schema ${ident(schema)} from supabase_auth_admin;`,
|
|
safeSql`-- Restore function permissions to authenticated, anon and public
|
|
grant execute on function ${ident(schema)}.${ident(functionName)} to authenticated, anon, public;`,
|
|
]
|
|
}
|