This commit is contained in:
Adam Cohen Hillel 2025-04-22 20:55:04 +01:00
parent 4cac31db55
commit ceea41208c
3 changed files with 25 additions and 19 deletions

View File

@ -118,12 +118,14 @@ CREATE POLICY project_delete_policy ON projects
CREATE POLICY thread_select_policy ON threads CREATE POLICY thread_select_policy ON threads
FOR SELECT FOR SELECT
USING ( USING (
is_public = TRUE OR
basejump.has_role_on_account(account_id) = true OR basejump.has_role_on_account(account_id) = true OR
EXISTS ( EXISTS (
SELECT 1 FROM projects SELECT 1 FROM projects
WHERE projects.project_id = threads.project_id WHERE projects.project_id = threads.project_id
AND basejump.has_role_on_account(projects.account_id) = true AND (
projects.is_public = TRUE OR
basejump.has_role_on_account(projects.account_id) = true
)
) )
); );
@ -169,7 +171,7 @@ CREATE POLICY agent_run_select_policy ON agent_runs
LEFT JOIN projects ON threads.project_id = projects.project_id LEFT JOIN projects ON threads.project_id = projects.project_id
WHERE threads.thread_id = agent_runs.thread_id WHERE threads.thread_id = agent_runs.thread_id
AND ( AND (
threads.is_public = TRUE OR projects.is_public = TRUE OR
basejump.has_role_on_account(threads.account_id) = true OR basejump.has_role_on_account(threads.account_id) = true OR
basejump.has_role_on_account(projects.account_id) = true basejump.has_role_on_account(projects.account_id) = true
) )
@ -227,7 +229,7 @@ CREATE POLICY message_select_policy ON messages
LEFT JOIN projects ON threads.project_id = projects.project_id LEFT JOIN projects ON threads.project_id = projects.project_id
WHERE threads.thread_id = messages.thread_id WHERE threads.thread_id = messages.thread_id
AND ( AND (
threads.is_public = TRUE OR projects.is_public = TRUE OR
basejump.has_role_on_account(threads.account_id) = true OR basejump.has_role_on_account(threads.account_id) = true OR
basejump.has_role_on_account(projects.account_id) = true basejump.has_role_on_account(projects.account_id) = true
) )
@ -295,18 +297,19 @@ DECLARE
current_role TEXT; current_role TEXT;
latest_summary_id UUID; latest_summary_id UUID;
latest_summary_time TIMESTAMP WITH TIME ZONE; latest_summary_time TIMESTAMP WITH TIME ZONE;
is_thread_public BOOLEAN; is_project_public BOOLEAN;
BEGIN BEGIN
-- Get current role -- Get current role
SELECT current_user INTO current_role; SELECT current_user INTO current_role;
-- Check if thread is public -- Check if associated project is public
SELECT is_public INTO is_thread_public SELECT p.is_public INTO is_project_public
FROM threads FROM threads t
WHERE thread_id = p_thread_id; LEFT JOIN projects p ON t.project_id = p.project_id
WHERE t.thread_id = p_thread_id;
-- Skip access check for service_role or public threads -- Skip access check for service_role or public projects
IF current_role = 'authenticated' AND NOT is_thread_public THEN IF current_role = 'authenticated' AND NOT is_project_public THEN
-- Check if thread exists and user has access -- Check if thread exists and user has access
SELECT EXISTS ( SELECT EXISTS (
SELECT 1 FROM threads t SELECT 1 FROM threads t

View File

@ -105,7 +105,6 @@ async def get_user_id_from_stream_auth(
detail="No valid authentication credentials found", detail="No valid authentication credentials found",
headers={"WWW-Authenticate": "Bearer"} headers={"WWW-Authenticate": "Bearer"}
) )
async def verify_thread_access(client, thread_id: str, user_id: str): async def verify_thread_access(client, thread_id: str, user_id: str):
""" """
Verify that a user has access to a specific thread based on account membership. Verify that a user has access to a specific thread based on account membership.
@ -122,16 +121,20 @@ async def verify_thread_access(client, thread_id: str, user_id: str):
HTTPException: If the user doesn't have access to the thread HTTPException: If the user doesn't have access to the thread
""" """
# Query the thread to get account information # Query the thread to get account information
thread_result = await client.table('threads').select('*').eq('thread_id', thread_id).execute() thread_result = await client.table('threads').select('*,project_id').eq('thread_id', thread_id).execute()
if not thread_result.data or len(thread_result.data) == 0: if not thread_result.data or len(thread_result.data) == 0:
raise HTTPException(status_code=404, detail="Thread not found") raise HTTPException(status_code=404, detail="Thread not found")
thread_data = thread_result.data[0] thread_data = thread_result.data[0]
# Check if thread is public # Check if project is public
if thread_data.get('is_public'): project_id = thread_data.get('project_id')
return True if project_id:
project_result = await client.table('projects').select('is_public').eq('project_id', project_id).execute()
if project_result.data and len(project_result.data) > 0:
if project_result.data[0].get('is_public'):
return True
account_id = thread_data.get('account_id') account_id = thread_data.get('account_id')
# When using service role, we need to manually check account membership instead of using current_user_account_role # When using service role, we need to manually check account membership instead of using current_user_account_role

View File

@ -608,9 +608,9 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
if (!isMounted) return; if (!isMounted) return;
// Make sure the thread is public // Make sure the thread is public
if (!(threadData as any).is_public) { // if (!(threadData as any).is_public) {
throw new Error('This thread is not available for public viewing.'); // throw new Error('This thread is not available for public viewing.');
} // }
if (threadData?.project_id) { if (threadData?.project_id) {
try { try {