mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Fixes #40799 Now, the correct error will be shown for materialized views accessible to `anon` and `authenticated` roles via Data API, instead of the unrelated "Security Definer view" error. For convenience, users can immediately fix the issue by running the correct SQL query to revoke select from `anon` and `authenticated`, just by clicking on "confirm" on the confirmation modal I just created. https://github.com/user-attachments/assets/f3ce9353-4ad0-4063-bf33-0b403f5fa87a Before <img width="958" height="440" alt="materialized" src="https://github.com/user-attachments/assets/89047c91-da35-4b9f-b7e3-82e877bcf2c6" /> Edit: Thanks to the review by @saltcod, I now realise that revoking access from `anon` and `authenticated` users might not be the optimal solution since it would break many projects relying on the access to materialized views. After pondering on the possible solutions, I figured there isn't an easy one, so I did away with the autofix button, and instead created a dialog explaining three possible options for the user, with a sample query under each one for convenience. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added clearer warnings when materialized views are accessible through the API. * Added a dialog explaining how to review and revoke API access for materialized views. * Added guidance and code examples for restricting access to API roles. * Added a link to the Security Advisor for additional information. * **Improvements** * Updated materialized view tooltips to accurately describe API accessibility. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
import {
|
|
Button,
|
|
Dialog,
|
|
DialogContent,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogSection,
|
|
DialogSectionSeparator,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from 'ui'
|
|
import { SimpleCodeBlock } from 'ui-patterns/SimpleCodeBlock'
|
|
|
|
import { Entity } from '@/data/table-editor/table-editor-types'
|
|
|
|
interface ExposedMaterializedViewDialogProps {
|
|
table: Entity
|
|
isExposedMaterializedViewDialogOpen: boolean
|
|
setIsExposedMaterializedViewDialogOpen: (isExposedMaterializedViewDialogOpen: boolean) => void
|
|
}
|
|
|
|
export function ExposedMaterializedViewDialog({
|
|
table,
|
|
isExposedMaterializedViewDialogOpen,
|
|
setIsExposedMaterializedViewDialogOpen,
|
|
}: ExposedMaterializedViewDialogProps) {
|
|
return (
|
|
<Dialog
|
|
open={isExposedMaterializedViewDialogOpen}
|
|
onOpenChange={setIsExposedMaterializedViewDialogOpen}
|
|
>
|
|
<DialogTrigger asChild>
|
|
<Button
|
|
variant="secondary"
|
|
size="tiny"
|
|
onClick={() => setIsExposedMaterializedViewDialogOpen(true)}
|
|
>
|
|
Check possible options
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>Materialized view exposed via Data API</DialogTitle>
|
|
</DialogHeader>
|
|
<DialogSectionSeparator />
|
|
<DialogSection className="text-sm text-foreground-light space-y-2 prose">
|
|
<p>
|
|
Revoking <code>select</code> access from API roles <code>anon</code> and{' '}
|
|
<code>authenticated</code> mitigates the risk of exposing sensitive data to all users.
|
|
</p>
|
|
<SimpleCodeBlock>
|
|
{`REVOKE SELECT on "${table.schema}"."${table.name}"
|
|
FROM public, anon, authenticated;`}
|
|
</SimpleCodeBlock>
|
|
<p>
|
|
Note that this is a breaking change if you have code that depends on accessing the
|
|
materialized view using the Data API. To reexpose the materialized view in a safe way,
|
|
you can put a function in front of it and apply a security rule equivalent to RLS:
|
|
</p>
|
|
<SimpleCodeBlock>
|
|
{`CREATE OR REPLACE FUNCTION get_${table.name}_secure()
|
|
RETURNS SETOF "${table.schema}"."${table.name}"
|
|
LANGUAGE sql
|
|
SECURITY DEFINER
|
|
SET search_path = ''
|
|
AS $$
|
|
SELECT * FROM "${table.schema}"."${table.name}"
|
|
WHERE user_id = (SELECT auth.uid());
|
|
$$;`}
|
|
</SimpleCodeBlock>
|
|
</DialogSection>
|
|
|
|
<DialogFooter>
|
|
<div className="flex items-center justify-end space-x-2">
|
|
<Button variant="default" onClick={() => setIsExposedMaterializedViewDialogOpen(false)}>
|
|
Understood
|
|
</Button>
|
|
</div>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|