RLSTesterResults.utils.test.ts192 lines · main
1import type { SafeSqlFragment } from '@supabase/pg-meta'
2import { describe, expect, it } from 'vitest'
3
4import type { Policy } from '@/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils'
5import type { ParseQueryResults } from '@/components/interfaces/Auth/RLSTester/RLSTester.types'
6import { deriveRLSTestState } from '@/components/interfaces/Auth/RLSTester/RLSTesterResults.utils'
7
8const sql = (s: string) => s as unknown as SafeSqlFragment
9
10const makePolicy = (definition: string | null = null): Policy =>
11 ({ definition: definition !== null ? sql(definition) : null }) as Policy
12
13const makeTable = (
14 overrides?: Partial<ParseQueryResults['tables'][number]>
15): ParseQueryResults['tables'][number] => ({
16 schema: 'public',
17 table: 'items',
18 isRLSEnabled: true,
19 tablePolicies: [],
20 ...overrides,
21})
22
23const makeResults = (overrides?: Partial<ParseQueryResults>): ParseQueryResults => ({
24 tables: [],
25 operation: 'SELECT',
26 role: 'anon',
27 ...overrides,
28})
29
30describe('deriveRLSTestState', () => {
31 describe('isServiceRole', () => {
32 it('is true when parseQueryResults is undefined', () => {
33 const { isServiceRole } = deriveRLSTestState(undefined)
34 expect(isServiceRole).toBe(true)
35 })
36
37 it('is true when role is undefined (postgres / service role)', () => {
38 const { isServiceRole } = deriveRLSTestState(makeResults({ role: undefined }))
39 expect(isServiceRole).toBe(true)
40 })
41
42 it('is false when role is anon', () => {
43 const { isServiceRole } = deriveRLSTestState(makeResults({ role: 'anon' }))
44 expect(isServiceRole).toBe(false)
45 })
46
47 it('is false when role is authenticated', () => {
48 const { isServiceRole } = deriveRLSTestState(makeResults({ role: 'authenticated' }))
49 expect(isServiceRole).toBe(false)
50 })
51 })
52
53 describe('noAccessToData', () => {
54 it('is false when parseQueryResults is undefined', () => {
55 const { noAccessToData } = deriveRLSTestState(undefined)
56 expect(noAccessToData).toBe(false)
57 })
58
59 it('is false for service role even when tables have no policies', () => {
60 const { noAccessToData } = deriveRLSTestState(
61 makeResults({ role: undefined, tables: [makeTable()] })
62 )
63 expect(noAccessToData).toBe(false)
64 })
65
66 it('is false when RLS is disabled on table', () => {
67 const { noAccessToData } = deriveRLSTestState(
68 makeResults({ tables: [makeTable({ isRLSEnabled: false, tablePolicies: [] })] })
69 )
70 expect(noAccessToData).toBe(false)
71 })
72
73 it('is true when RLS is enabled and table has no policies', () => {
74 const { noAccessToData } = deriveRLSTestState(
75 makeResults({ tables: [makeTable({ isRLSEnabled: true, tablePolicies: [] })] })
76 )
77 expect(noAccessToData).toBe(true)
78 })
79
80 it('is true when RLS is enabled and a policy definition is false', () => {
81 const { noAccessToData } = deriveRLSTestState(
82 makeResults({
83 tables: [makeTable({ tablePolicies: [makePolicy('false')] })],
84 })
85 )
86 expect(noAccessToData).toBe(true)
87 })
88
89 it('is false when RLS is enabled and policies are valid (not false)', () => {
90 const { noAccessToData } = deriveRLSTestState(
91 makeResults({
92 tables: [makeTable({ tablePolicies: [makePolicy('auth.uid() = user_id')] })],
93 })
94 )
95 expect(noAccessToData).toBe(false)
96 })
97
98 it('is false when all tables have RLS disabled regardless of policy state', () => {
99 const { noAccessToData } = deriveRLSTestState(
100 makeResults({
101 tables: [
102 makeTable({ isRLSEnabled: false, tablePolicies: [] }),
103 makeTable({
104 table: 'other',
105 isRLSEnabled: false,
106 tablePolicies: [makePolicy('false')],
107 }),
108 ],
109 })
110 )
111 expect(noAccessToData).toBe(false)
112 })
113 })
114
115 describe('tableWithRLSEnabledButNoPolicies', () => {
116 it('is undefined when no tables', () => {
117 const { tableWithRLSEnabledButNoPolicies } = deriveRLSTestState(makeResults({ tables: [] }))
118 expect(tableWithRLSEnabledButNoPolicies).toBeUndefined()
119 })
120
121 it('is undefined when RLS disabled', () => {
122 const { tableWithRLSEnabledButNoPolicies } = deriveRLSTestState(
123 makeResults({ tables: [makeTable({ isRLSEnabled: false })] })
124 )
125 expect(tableWithRLSEnabledButNoPolicies).toBeUndefined()
126 })
127
128 it('is undefined when table has policies', () => {
129 const { tableWithRLSEnabledButNoPolicies } = deriveRLSTestState(
130 makeResults({ tables: [makeTable({ tablePolicies: [makePolicy('true')] })] })
131 )
132 expect(tableWithRLSEnabledButNoPolicies).toBeUndefined()
133 })
134
135 it('returns the matching table when RLS enabled with no policies', () => {
136 const table = makeTable({ table: 'profiles', tablePolicies: [] })
137 const { tableWithRLSEnabledButNoPolicies } = deriveRLSTestState(
138 makeResults({ tables: [table] })
139 )
140 expect(tableWithRLSEnabledButNoPolicies).toEqual(table)
141 })
142
143 it('returns the first matching table among multiple', () => {
144 const first = makeTable({ table: 'profiles', tablePolicies: [] })
145 const second = makeTable({ table: 'posts', tablePolicies: [] })
146 const { tableWithRLSEnabledButNoPolicies } = deriveRLSTestState(
147 makeResults({ tables: [first, second] })
148 )
149 expect(tableWithRLSEnabledButNoPolicies).toEqual(first)
150 })
151 })
152
153 describe('tableWithRLSEnabledWithPolicyFalse', () => {
154 it('is undefined when no tables', () => {
155 const { tableWithRLSEnabledWithPolicyFalse } = deriveRLSTestState(makeResults({ tables: [] }))
156 expect(tableWithRLSEnabledWithPolicyFalse).toBeUndefined()
157 })
158
159 it('is undefined when RLS disabled even with false policy', () => {
160 const { tableWithRLSEnabledWithPolicyFalse } = deriveRLSTestState(
161 makeResults({
162 tables: [makeTable({ isRLSEnabled: false, tablePolicies: [makePolicy('false')] })],
163 })
164 )
165 expect(tableWithRLSEnabledWithPolicyFalse).toBeUndefined()
166 })
167
168 it('is undefined when no policy has definition of false', () => {
169 const { tableWithRLSEnabledWithPolicyFalse } = deriveRLSTestState(
170 makeResults({
171 tables: [makeTable({ tablePolicies: [makePolicy('auth.uid() = user_id')] })],
172 })
173 )
174 expect(tableWithRLSEnabledWithPolicyFalse).toBeUndefined()
175 })
176
177 it('returns the table when a policy definition is exactly "false"', () => {
178 const table = makeTable({ table: 'secrets', tablePolicies: [makePolicy('false')] })
179 const { tableWithRLSEnabledWithPolicyFalse } = deriveRLSTestState(
180 makeResults({ tables: [table] })
181 )
182 expect(tableWithRLSEnabledWithPolicyFalse).toEqual(table)
183 })
184
185 it('is undefined when policy definition is null (no definition)', () => {
186 const { tableWithRLSEnabledWithPolicyFalse } = deriveRLSTestState(
187 makeResults({ tables: [makeTable({ tablePolicies: [makePolicy(null)] })] })
188 )
189 expect(tableWithRLSEnabledWithPolicyFalse).toBeUndefined()
190 })
191 })
192})