mirror of
https://github.com/supabase/supabase.git
synced 2026-05-09 10:19:50 -04:00
3b756e4d9f
<img width="2652" height="830" alt="image" src="https://github.com/user-attachments/assets/3c3921e7-c255-4e59-a9c3-c5f97da87788" /> Adds a full screen alert behind a feature flag `projectNeedsSecuring` that prompts for fixing RLS issues. Adjusts a few other small styles to add more prominence to critical advisor issues. To test: - Enable the flag - Make sure you have a table with RLS disabled - Open project home and note the fade in of full page review - Click "copy prompt" or "fix" and note the prompt - Click skip to home and refresh the page, note it doesn't appear anymore <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Project-level security gate on project home with AI assistant prompts, table details, per-project dismissible notice, and a new telemetry event for CTA interactions. * **Improvements** * Stronger visual treatment for critical advisor items and advisor CTA when critical issues exist. * Assistant dropdown supports a copy-prompt callback; added local-storage key and utilities/types to support project security workflows. * **Tests** * Added tests covering gate behavior, navigation, and dismissal logic. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
import { type ProjectSecurityTable } from './ProjectNeedsSecuring.types'
|
|
import { parseDbSchemaString } from '@/data/config/project-postgrest-config-query'
|
|
|
|
const DEFAULT_EXPOSED_SCHEMA = 'public'
|
|
|
|
export const getTableKey = ({ schema, name }: { schema: string; name: string }) =>
|
|
`${schema}.${name}`
|
|
|
|
export const getExposedSchemas = (dbSchema: string | null | undefined) => {
|
|
const schemas = dbSchema ? parseDbSchemaString(dbSchema) : []
|
|
return schemas.length > 0 ? schemas : [DEFAULT_EXPOSED_SCHEMA]
|
|
}
|
|
|
|
export const formatRlsDescription = (count: number) => {
|
|
const isSingular = count === 1
|
|
const noun = isSingular ? 'table' : 'tables'
|
|
const verb = isSingular ? 'has' : 'have'
|
|
const pronoun = isSingular ? 'its' : 'their'
|
|
|
|
return `${count} ${noun} ${verb} RLS disabled which means anyone can access ${pronoun} data via the Data API.`
|
|
}
|
|
|
|
export const buildSecurityPromptMarkdown = (issueCount: number, tables: ProjectSecurityTable[]) => {
|
|
const header = [
|
|
'## Project security review',
|
|
'',
|
|
formatRlsDescription(issueCount),
|
|
'',
|
|
'### Tables',
|
|
'',
|
|
'| Table | Schema | Accessible via Data API | RLS |',
|
|
'| --- | --- | --- | --- |',
|
|
]
|
|
|
|
const rows = tables.map(
|
|
(table) =>
|
|
`| ${table.name} | ${table.schema} | ${table.dataApiAccessible ? 'Yes' : 'No'} | ${table.rlsEnabled ? 'Enabled' : 'Disabled'} |`
|
|
)
|
|
|
|
const footer = [
|
|
'',
|
|
'### Next step',
|
|
'',
|
|
'Help me enable RLS on these tables and suggest the minimum policies I should create.',
|
|
]
|
|
|
|
return [...header, ...rows, ...footer].join('\n')
|
|
}
|
|
|
|
export const sortTables = (tables: ProjectSecurityTable[]) => {
|
|
return [...tables].sort((a, b) => {
|
|
const aPriority = a.hasRlsIssue ? 0 : a.rlsEnabled ? 2 : 1
|
|
const bPriority = b.hasRlsIssue ? 0 : b.rlsEnabled ? 2 : 1
|
|
|
|
if (aPriority !== bPriority) return aPriority - bPriority
|
|
|
|
const schemaComparison = a.schema.localeCompare(b.schema)
|
|
if (schemaComparison !== 0) return schemaComparison
|
|
|
|
return a.name.localeCompare(b.name)
|
|
})
|
|
}
|