fix(rls): members_update WITH CHECK mirrors USING (D8)
UPDATE policy was USING-only: a privileged caller could mutate a member row into a space they don't administer (no post-image re-check). Migration 043 adds the mirrored WITH CHECK. Self column escalation (space_id/role/status) remains blocked by the trigger (D9). Schema + DB maps updated.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
-- =============================================================================
|
||||
-- 043: space_members UPDATE — add WITH CHECK (defense-in-depth)
|
||||
-- =============================================================================
|
||||
-- members_update had only a USING clause: a privileged caller could mutate a
|
||||
-- member row into a space where they hold no role (cross-space move) because
|
||||
-- the post-image was never re-checked. Add a WITH CHECK mirroring the USING
|
||||
-- so the resulting row must still satisfy the same predicate. (Self column
|
||||
-- escalation -- space_id/role/status -- is separately blocked by the
|
||||
-- prevent_member_self_role_change trigger; see scripts/044.)
|
||||
--
|
||||
-- Idempotent: DROP POLICY IF EXISTS then CREATE.
|
||||
-- =============================================================================
|
||||
|
||||
DROP POLICY IF EXISTS members_update ON public.space_members;
|
||||
CREATE POLICY members_update ON public.space_members FOR UPDATE
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin','board','treasurer'])
|
||||
)
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
OR public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin','board','treasurer'])
|
||||
);
|
||||
@@ -477,6 +477,10 @@ CREATE POLICY members_update ON public.space_members FOR UPDATE
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin','board','treasurer'])
|
||||
)
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
OR public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin','board','treasurer'])
|
||||
);
|
||||
CREATE POLICY members_delete ON public.space_members FOR DELETE
|
||||
USING (public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin']));
|
||||
|
||||
Reference in New Issue
Block a user