-- Row-Level Security (RLS) for Multi-Tenant Isolation -- This migration enables RLS on all tenant-scoped tables and creates policies -- to ensure users can only access data within their authorized workspaces. -- ============================================================================= -- ENABLE RLS ON TENANT-SCOPED TABLES -- ============================================================================= ALTER TABLE workspaces ENABLE ROW LEVEL SECURITY; ALTER TABLE workspace_members ENABLE ROW LEVEL SECURITY; ALTER TABLE teams ENABLE ROW LEVEL SECURITY; ALTER TABLE team_members ENABLE ROW LEVEL SECURITY; ALTER TABLE tasks ENABLE ROW LEVEL SECURITY; ALTER TABLE events ENABLE ROW LEVEL SECURITY; ALTER TABLE projects ENABLE ROW LEVEL SECURITY; ALTER TABLE activity_logs ENABLE ROW LEVEL SECURITY; ALTER TABLE memory_embeddings ENABLE ROW LEVEL SECURITY; ALTER TABLE domains ENABLE ROW LEVEL SECURITY; ALTER TABLE ideas ENABLE ROW LEVEL SECURITY; ALTER TABLE relationships ENABLE ROW LEVEL SECURITY; ALTER TABLE agents ENABLE ROW LEVEL SECURITY; ALTER TABLE agent_sessions ENABLE ROW LEVEL SECURITY; ALTER TABLE user_layouts ENABLE ROW LEVEL SECURITY; ALTER TABLE knowledge_entries ENABLE ROW LEVEL SECURITY; ALTER TABLE knowledge_tags ENABLE ROW LEVEL SECURITY; ALTER TABLE knowledge_entry_tags ENABLE ROW LEVEL SECURITY; ALTER TABLE knowledge_links ENABLE ROW LEVEL SECURITY; ALTER TABLE knowledge_embeddings ENABLE ROW LEVEL SECURITY; ALTER TABLE knowledge_entry_versions ENABLE ROW LEVEL SECURITY; -- ============================================================================= -- HELPER FUNCTION: Check if user is workspace member -- ============================================================================= CREATE OR REPLACE FUNCTION is_workspace_member(workspace_uuid UUID, user_uuid UUID) RETURNS BOOLEAN AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM workspace_members WHERE workspace_id = workspace_uuid AND user_id = user_uuid ); END; $$ LANGUAGE plpgsql STABLE SECURITY DEFINER; -- ============================================================================= -- HELPER FUNCTION: Check if user is workspace owner/admin -- ============================================================================= CREATE OR REPLACE FUNCTION is_workspace_admin(workspace_uuid UUID, user_uuid UUID) RETURNS BOOLEAN AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM workspace_members WHERE workspace_id = workspace_uuid AND user_id = user_uuid AND role IN ('OWNER', 'ADMIN') ); END; $$ LANGUAGE plpgsql STABLE SECURITY DEFINER; -- ============================================================================= -- HELPER FUNCTION: Get current user ID from session variable -- ============================================================================= -- Usage in API: SET LOCAL app.current_user_id = 'user-uuid'; CREATE OR REPLACE FUNCTION current_user_id() RETURNS UUID AS $$ BEGIN RETURN NULLIF(current_setting('app.current_user_id', TRUE), '')::UUID; EXCEPTION WHEN OTHERS THEN RETURN NULL; END; $$ LANGUAGE plpgsql STABLE; -- ============================================================================= -- WORKSPACES: Users can only see workspaces they're members of -- ============================================================================= CREATE POLICY workspace_member_access ON workspaces FOR ALL USING ( id IN ( SELECT workspace_id FROM workspace_members WHERE user_id = current_user_id() ) ); -- ============================================================================= -- WORKSPACE_MEMBERS: Users can see members of their workspaces -- ============================================================================= CREATE POLICY workspace_members_access ON workspace_members FOR ALL USING ( workspace_id IN ( SELECT workspace_id FROM workspace_members WHERE user_id = current_user_id() ) ); -- ============================================================================= -- TEAMS: Users can see teams in their workspaces -- ============================================================================= CREATE POLICY teams_workspace_access ON teams FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- TEAM_MEMBERS: Users can see team members in their workspaces -- ============================================================================= CREATE POLICY team_members_access ON team_members FOR ALL USING ( team_id IN ( SELECT id FROM teams WHERE is_workspace_member(workspace_id, current_user_id()) ) ); -- ============================================================================= -- TASKS: Users can only see tasks in their workspaces -- ============================================================================= CREATE POLICY tasks_workspace_access ON tasks FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- EVENTS: Users can only see events in their workspaces -- ============================================================================= CREATE POLICY events_workspace_access ON events FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- PROJECTS: Users can only see projects in their workspaces -- ============================================================================= CREATE POLICY projects_workspace_access ON projects FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- ACTIVITY_LOGS: Users can only see activity in their workspaces -- ============================================================================= CREATE POLICY activity_logs_workspace_access ON activity_logs FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- MEMORY_EMBEDDINGS: Users can only see embeddings in their workspaces -- ============================================================================= CREATE POLICY memory_embeddings_workspace_access ON memory_embeddings FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- DOMAINS: Users can only see domains in their workspaces -- ============================================================================= CREATE POLICY domains_workspace_access ON domains FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- IDEAS: Users can only see ideas in their workspaces -- ============================================================================= CREATE POLICY ideas_workspace_access ON ideas FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- RELATIONSHIPS: Users can only see relationships in their workspaces -- ============================================================================= CREATE POLICY relationships_workspace_access ON relationships FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- AGENTS: Users can only see agents in their workspaces -- ============================================================================= CREATE POLICY agents_workspace_access ON agents FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- AGENT_SESSIONS: Users can only see agent sessions in their workspaces -- ============================================================================= CREATE POLICY agent_sessions_workspace_access ON agent_sessions FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- USER_LAYOUTS: Users can only see their own layouts in their workspaces -- ============================================================================= CREATE POLICY user_layouts_workspace_access ON user_layouts FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) AND user_id = current_user_id() ); -- ============================================================================= -- KNOWLEDGE_ENTRIES: Users can only see entries in their workspaces -- ============================================================================= CREATE POLICY knowledge_entries_workspace_access ON knowledge_entries FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- KNOWLEDGE_TAGS: Users can only see tags in their workspaces -- ============================================================================= CREATE POLICY knowledge_tags_workspace_access ON knowledge_tags FOR ALL USING ( is_workspace_member(workspace_id, current_user_id()) ); -- ============================================================================= -- KNOWLEDGE_ENTRY_TAGS: Users can see tags for entries in their workspaces -- ============================================================================= CREATE POLICY knowledge_entry_tags_access ON knowledge_entry_tags FOR ALL USING ( entry_id IN ( SELECT id FROM knowledge_entries WHERE is_workspace_member(workspace_id, current_user_id()) ) ); -- ============================================================================= -- KNOWLEDGE_LINKS: Users can see links between entries in their workspaces -- ============================================================================= CREATE POLICY knowledge_links_access ON knowledge_links FOR ALL USING ( source_id IN ( SELECT id FROM knowledge_entries WHERE is_workspace_member(workspace_id, current_user_id()) ) ); -- ============================================================================= -- KNOWLEDGE_EMBEDDINGS: Users can see embeddings for entries in their workspaces -- ============================================================================= CREATE POLICY knowledge_embeddings_access ON knowledge_embeddings FOR ALL USING ( entry_id IN ( SELECT id FROM knowledge_entries WHERE is_workspace_member(workspace_id, current_user_id()) ) ); -- ============================================================================= -- KNOWLEDGE_ENTRY_VERSIONS: Users can see versions for entries in their workspaces -- ============================================================================= CREATE POLICY knowledge_entry_versions_access ON knowledge_entry_versions FOR ALL USING ( entry_id IN ( SELECT id FROM knowledge_entries WHERE is_workspace_member(workspace_id, current_user_id()) ) ); -- ============================================================================= -- GRANT USAGE TO APPLICATION ROLE -- ============================================================================= -- The application should connect with a role that has appropriate permissions. -- By default, we assume the owner of the database has full access. -- In production, create a dedicated role with limited permissions. -- Example (uncomment and customize for production): -- GRANT USAGE ON SCHEMA public TO mosaic_app; -- GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO mosaic_app; -- GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO mosaic_app;