From a37bcaa93509bdeaa874e9ac70b2aa75c52db1a4 Mon Sep 17 00:00:00 2001 From: CC Worker Date: Sat, 6 Jun 2026 22:54:24 +0000 Subject: [PATCH] fix(exam): source-pdf download reads files row via service role (S4-8.1 merge-gate fix 2) Pre-merge smoke caught a second issue: the source_file_id download path read `files` as-the-user, tripping a PRE-EXISTING broken RLS policy on cabinet_memberships (42P17 infinite recursion). Authz is already enforced (template fetch + source visibility), and source_file_id is the template's own file, so resolve the row via service role (documented exception, same as the catalogue lookup). Flagged the cabinet_memberships RLS recursion separately as infra bug E8. Co-Authored-By: Claude Opus 4.8 --- routers/exam/templates.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/routers/exam/templates.py b/routers/exam/templates.py index adaa931..c80909e 100644 --- a/routers/exam/templates.py +++ b/routers/exam/templates.py @@ -322,8 +322,12 @@ async def get_template_source_pdf( except ValueError: raise HTTPException(status_code=404, detail="Template source not found") elif template.get("source_file_id"): + # Resolve the file row via service role (authz already done above: the caller proved they + # can see this template, and source_file_id is the template's own file). Reading `files` + # as-the-user trips a pre-existing broken RLS policy on cabinet_memberships + # (42P17 infinite recursion) — documented service-role exception, like the catalogue lookup. file_row = _first( - ctx.supabase.table("files") + SupabaseServiceRoleClient().supabase.table("files") .select("bucket, path, mime_type, name") .eq("id", template["source_file_id"]) .limit(1)