ProjectNeedsSecuring.utils.ts72 lines · main
1import { type ProjectSecurityTable } from './ProjectNeedsSecuring.types'
2import { parseDbSchemaString } from '@/data/config/project-postgrest-config-query'
3
4const DEFAULT_EXPOSED_SCHEMA = 'public'
5
6export const getTableKey = ({ schema, name }: { schema: string; name: string }) =>
7 `${schema}.${name}`
8
9export const getTablePoliciesHref = (
10 projectRef: string | undefined,
11 schema: string | undefined,
12 name: string | undefined
13): string => {
14 return `/project/${projectRef ?? ''}/auth/policies?schema=${encodeURIComponent(
15 schema ?? ''
16 )}&search=${encodeURIComponent(name ?? '')}`
17}
18
19export const getExposedSchemas = (dbSchema: string | null | undefined) => {
20 const schemas = dbSchema ? parseDbSchemaString(dbSchema) : []
21 return schemas.length > 0 ? schemas : [DEFAULT_EXPOSED_SCHEMA]
22}
23
24export const formatRlsDescription = (count: number) => {
25 const isSingular = count === 1
26 const noun = isSingular ? 'table' : 'tables'
27 const verb = isSingular ? 'has' : 'have'
28 const pronoun = isSingular ? 'its' : 'their'
29
30 return `${count} ${noun} ${verb} RLS disabled which means anyone can access ${pronoun} data via the Data API.`
31}
32
33export const buildSecurityPromptMarkdown = (issueCount: number, tables: ProjectSecurityTable[]) => {
34 const header = [
35 '## Project security review',
36 '',
37 formatRlsDescription(issueCount),
38 '',
39 '### Tables',
40 '',
41 '| Table | Schema | Accessible via Data API | RLS |',
42 '| --- | --- | --- | --- |',
43 ]
44
45 const rows = tables.map(
46 (table) =>
47 `| ${table.name} | ${table.schema} | ${table.dataApiAccessible ? 'Yes' : 'No'} | ${table.rlsEnabled ? 'Enabled' : 'Disabled'} |`
48 )
49
50 const footer = [
51 '',
52 '### Next step',
53 '',
54 'Help me enable RLS on these tables and suggest the minimum policies I should create.',
55 ]
56
57 return [...header, ...rows, ...footer].join('\n')
58}
59
60export const sortTables = (tables: ProjectSecurityTable[]) => {
61 return [...tables].sort((a, b) => {
62 const aPriority = a.hasRlsIssue ? 0 : a.rlsEnabled ? 2 : 1
63 const bPriority = b.hasRlsIssue ? 0 : b.rlsEnabled ? 2 : 1
64
65 if (aPriority !== bPriority) return aPriority - bPriority
66
67 const schemaComparison = a.schema.localeCompare(b.schema)
68 if (schemaComparison !== 0) return schemaComparison
69
70 return a.name.localeCompare(b.name)
71 })
72}