112 lines
4.8 KiB
PL/PgSQL
112 lines
4.8 KiB
PL/PgSQL
-- Origin Graph — Row-Level Security Policies
|
|
-- Migration: 003
|
|
-- All tables are workspace-scoped. A user may only read or write rows in
|
|
-- workspaces where they have a team_members record. The Clerk JWT is verified
|
|
-- server-side; auth.uid() maps to the Clerk user_id column.
|
|
|
|
-- Enable RLS on every table
|
|
ALTER TABLE workspaces ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE artboards ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE origins ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE intent_diffs ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE agent_sessions ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE design_language_files ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE team_members ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- ── Helper: is the current user a member of the given workspace? ──────────────
|
|
|
|
CREATE OR REPLACE FUNCTION is_workspace_member(ws_id UUID)
|
|
RETURNS BOOLEAN LANGUAGE sql SECURITY DEFINER AS $$
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM team_members
|
|
WHERE workspace_id = ws_id
|
|
AND user_id = auth.uid()::TEXT
|
|
);
|
|
$$;
|
|
|
|
-- ── workspaces ────────────────────────────────────────────────────────────────
|
|
|
|
CREATE POLICY workspaces_select ON workspaces
|
|
FOR SELECT USING (is_workspace_member(id));
|
|
|
|
CREATE POLICY workspaces_insert ON workspaces
|
|
FOR INSERT WITH CHECK (owner_id = auth.uid()::TEXT);
|
|
|
|
CREATE POLICY workspaces_update ON workspaces
|
|
FOR UPDATE USING (owner_id = auth.uid()::TEXT);
|
|
|
|
-- ── artboards ─────────────────────────────────────────────────────────────────
|
|
|
|
CREATE POLICY artboards_select ON artboards
|
|
FOR SELECT USING (is_workspace_member(workspace_id));
|
|
|
|
CREATE POLICY artboards_insert ON artboards
|
|
FOR INSERT WITH CHECK (is_workspace_member(workspace_id));
|
|
|
|
CREATE POLICY artboards_update ON artboards
|
|
FOR UPDATE USING (is_workspace_member(workspace_id));
|
|
|
|
CREATE POLICY artboards_delete ON artboards
|
|
FOR DELETE USING (is_workspace_member(workspace_id));
|
|
|
|
-- ── intent_diffs ──────────────────────────────────────────────────────────────
|
|
-- Derived from artboard's workspace membership
|
|
CREATE POLICY intent_diffs_select ON intent_diffs
|
|
FOR SELECT USING (
|
|
is_workspace_member((SELECT workspace_id FROM artboards WHERE id = artboard_id))
|
|
);
|
|
|
|
CREATE POLICY intent_diffs_insert ON intent_diffs
|
|
FOR INSERT WITH CHECK (
|
|
is_workspace_member((SELECT workspace_id FROM artboards WHERE id = artboard_id))
|
|
);
|
|
|
|
CREATE POLICY intent_diffs_update ON intent_diffs
|
|
FOR UPDATE USING (
|
|
is_workspace_member((SELECT workspace_id FROM artboards WHERE id = artboard_id))
|
|
);
|
|
|
|
-- ── agent_sessions ────────────────────────────────────────────────────────────
|
|
|
|
CREATE POLICY agent_sessions_select ON agent_sessions
|
|
FOR SELECT USING (
|
|
is_workspace_member((SELECT workspace_id FROM artboards WHERE id = artboard_id))
|
|
);
|
|
|
|
CREATE POLICY agent_sessions_insert ON agent_sessions
|
|
FOR INSERT WITH CHECK (
|
|
is_workspace_member((SELECT workspace_id FROM artboards WHERE id = artboard_id))
|
|
);
|
|
|
|
CREATE POLICY agent_sessions_update ON agent_sessions
|
|
FOR UPDATE USING (
|
|
is_workspace_member((SELECT workspace_id FROM artboards WHERE id = artboard_id))
|
|
);
|
|
|
|
-- ── design_language_files ─────────────────────────────────────────────────────
|
|
|
|
CREATE POLICY dlf_select ON design_language_files
|
|
FOR SELECT USING (is_workspace_member(workspace_id));
|
|
|
|
CREATE POLICY dlf_insert ON design_language_files
|
|
FOR INSERT WITH CHECK (is_workspace_member(workspace_id));
|
|
|
|
CREATE POLICY dlf_update ON design_language_files
|
|
FOR UPDATE USING (is_workspace_member(workspace_id));
|
|
|
|
-- ── team_members ──────────────────────────────────────────────────────────────
|
|
|
|
CREATE POLICY team_members_select ON team_members
|
|
FOR SELECT USING (is_workspace_member(workspace_id));
|
|
|
|
-- Only workspace owners can add/remove members
|
|
CREATE POLICY team_members_insert ON team_members
|
|
FOR INSERT WITH CHECK (
|
|
EXISTS (SELECT 1 FROM workspaces WHERE id = workspace_id AND owner_id = auth.uid()::TEXT)
|
|
);
|
|
|
|
CREATE POLICY team_members_delete ON team_members
|
|
FOR DELETE USING (
|
|
EXISTS (SELECT 1 FROM workspaces WHERE id = workspace_id AND owner_id = auth.uid()::TEXT)
|
|
);
|