Skip to content

Commit c7b29c4

Browse files
itigges22claude
andcommitted
fix: add SECURITY DEFINER RLS functions for client portal
The initial RLS policies caused infinite recursion because client policies on projects/assignments/updates joined through tables that had their own RLS policies creating circular references. Fixed by using SECURITY DEFINER helper functions that bypass RLS internally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0fc3929 commit c7b29c4

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

supabase/migrations/20260324100000_client_portal_schema_fixes.sql

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,59 @@ CREATE POLICY "Client users can insert project issues"
117117
WHERE p.id = project_id AND up.id = auth.uid()
118118
)
119119
);
120+
121+
-- ============================================================
122+
-- 4. SECURITY DEFINER helper functions for client RLS (avoids recursion)
123+
-- ============================================================
124+
125+
CREATE OR REPLACE FUNCTION user_is_client_for_account(check_account_id uuid)
126+
RETURNS boolean
127+
LANGUAGE sql
128+
SECURITY DEFINER
129+
STABLE
130+
AS $$
131+
SELECT EXISTS (
132+
SELECT 1 FROM public.user_profiles
133+
WHERE id = auth.uid()
134+
AND is_client = true
135+
AND client_account_id = check_account_id
136+
);
137+
$$;
138+
139+
CREATE OR REPLACE FUNCTION user_is_client_for_project(check_project_id uuid)
140+
RETURNS boolean
141+
LANGUAGE sql
142+
SECURITY DEFINER
143+
STABLE
144+
AS $$
145+
SELECT EXISTS (
146+
SELECT 1 FROM public.projects p
147+
JOIN public.user_profiles up ON up.client_account_id = p.account_id
148+
WHERE p.id = check_project_id
149+
AND up.id = auth.uid()
150+
AND up.is_client = true
151+
);
152+
$$;
153+
154+
-- 5. Client SELECT policies (using SECURITY DEFINER to avoid recursion)
155+
156+
CREATE POLICY client_portal_projects_select ON projects FOR SELECT
157+
USING (user_is_client_for_account(account_id));
158+
159+
CREATE POLICY client_portal_updates_select ON project_updates FOR SELECT
160+
USING (user_is_client_for_project(project_id));
161+
162+
CREATE POLICY client_portal_assignments_select ON project_assignments FOR SELECT
163+
USING (user_is_client_for_project(project_id));
164+
165+
CREATE POLICY client_portal_workflow_instances_select ON workflow_instances FOR SELECT
166+
USING (user_is_client_for_project(project_id));
167+
168+
CREATE POLICY client_portal_workflow_history_select ON workflow_history FOR SELECT
169+
USING (
170+
EXISTS (
171+
SELECT 1 FROM public.workflow_instances wi
172+
WHERE wi.id = workflow_history.workflow_instance_id
173+
AND user_is_client_for_project(wi.project_id)
174+
)
175+
);

0 commit comments

Comments
 (0)