import { ident, safeSql } from '@supabase/pg-meta/src/pg-format' import { useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' import { ScrollArea } from 'ui' import { ConfirmationModal } from 'ui-patterns/Dialogs/ConfirmationModal' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { SimpleCodeBlock } from 'ui-patterns/SimpleCodeBlock' import { useViewDefinitionQuery } from '@/data/database/view-definition-query' import { lintKeys } from '@/data/lint/keys' import { useExecuteSqlMutation } from '@/data/sql/execute-sql-mutation' import { Entity, isViewLike } from '@/data/table-editor/table-editor-types' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' interface ViewEntityAutofixSecurityModalProps { table: Entity isAutofixViewSecurityModalOpen: boolean setIsAutofixViewSecurityModalOpen: (isAutofixViewSecurityModalOpen: boolean) => void } export const ViewEntityAutofixSecurityModal = ({ table, isAutofixViewSecurityModalOpen, setIsAutofixViewSecurityModalOpen, }: ViewEntityAutofixSecurityModalProps) => { const { data: project } = useSelectedProjectQuery() const queryClient = useQueryClient() const { isSuccess, isPending: isLoading, data, } = useViewDefinitionQuery( { id: table?.id, projectRef: project?.ref, connectionString: project?.connectionString, }, { enabled: isAutofixViewSecurityModalOpen && isViewLike(table), } ) const { mutate: execute } = useExecuteSqlMutation({ onSuccess: async () => { toast.success('View security changed successfully') setIsAutofixViewSecurityModalOpen(false) await queryClient.invalidateQueries({ queryKey: lintKeys.lint(project?.ref) }) }, onError: (error) => { toast.error(`Failed to autofix view security: ${error.message}`) }, }) function handleConfirm() { const sql = safeSql`ALTER VIEW ${ident(table.schema)}.${ident(table.name)} SET (security_invoker = on);` execute({ projectRef: project?.ref, connectionString: project?.connectionString, sql, }) } if (!isViewLike(table)) { return null } return ( setIsAutofixViewSecurityModalOpen(false)} onConfirm={() => handleConfirm()} >

Setting security_invoker=on ensures the View runs with the permissions of the querying user, reducing the risk of unintended data exposure.

Existing query
{isLoading && } {isSuccess && ( {`create view ${table.schema}.${table.name} as\n ${data}`} )}
Updated query
{isLoading && } {isSuccess && ( {`create view ${table.schema}.${table.name} with (security_invoker = on) as\n ${data}`} )}
) }