diff --git a/apps/server/src/api/v2/electric-shape/chats.ts b/apps/server/src/api/v2/electric-shape/chats.ts index a62e0fac7..fc38d148d 100644 --- a/apps/server/src/api/v2/electric-shape/chats.ts +++ b/apps/server/src/api/v2/electric-shape/chats.ts @@ -4,12 +4,10 @@ import { errorResponse } from '../../../utils/response'; import { extractParamFromWhere } from './_helpers'; export const chatsProxyRouter = async (url: URL, _userId: string, c: Context) => { - const matches = extractParamFromWhere(url, 'id'); - const chatId = matches?.[0]; + const chatId = extractParamFromWhere(url, 'id'); if (!chatId) { - errorResponse('Chat ID (id) is required', 403); - return; + throw errorResponse('Chat ID (id) is required', 403); } // User must have access to the chat @@ -19,8 +17,7 @@ export const chatsProxyRouter = async (url: URL, _userId: string, c: Context) => }); if (!userHasAccessToChat) { - errorResponse('You do not have access to this chat', 403); - return; + throw errorResponse('You do not have access to this chat', 403); } return url; diff --git a/apps/server/src/api/v2/electric-shape/index.ts b/apps/server/src/api/v2/electric-shape/index.ts index dd49932c9..9542349a6 100644 --- a/apps/server/src/api/v2/electric-shape/index.ts +++ b/apps/server/src/api/v2/electric-shape/index.ts @@ -46,8 +46,7 @@ const app = new Hono() return response; } catch (_error) { console.error('Error fetching data from Electric Shape', _error); - errorResponse('Error fetching data from Electric Shape', 500); - return; + throw errorResponse('Error fetching data from Electric Shape', 500); } }); diff --git a/apps/server/src/api/v2/electric-shape/messages.ts b/apps/server/src/api/v2/electric-shape/messages.ts index ef9b60b58..6c9afe40e 100644 --- a/apps/server/src/api/v2/electric-shape/messages.ts +++ b/apps/server/src/api/v2/electric-shape/messages.ts @@ -4,12 +4,10 @@ import { errorResponse } from '../../../utils/response'; import { extractParamFromWhere } from './_helpers'; export const messagesProxyRouter = async (url: URL, _userId: string, c: Context) => { - const matches = extractParamFromWhere(url, 'chat_id'); - const chatId = matches?.[0]; + const chatId = extractParamFromWhere(url, 'chat_id'); if (!chatId) { - errorResponse('Chat ID is required', 403); - return; + throw errorResponse('Chat ID is required', 403); } const userHasAccessToChat = await canUserAccessChat({ @@ -18,8 +16,7 @@ export const messagesProxyRouter = async (url: URL, _userId: string, c: Context) }); if (!userHasAccessToChat) { - errorResponse('You do not have access to this chat', 403); - return; + throw errorResponse('You do not have access to this chat', 403); } return url; diff --git a/packages/ai/src/utils/sql-permissions/permission-validator.ts b/packages/ai/src/utils/sql-permissions/permission-validator.ts index 2f30f8f5a..07fb56cf8 100644 --- a/packages/ai/src/utils/sql-permissions/permission-validator.ts +++ b/packages/ai/src/utils/sql-permissions/permission-validator.ts @@ -17,23 +17,16 @@ export async function validateSqlPermissions( dataSourceSyntax?: string ): Promise { try { - console.info('[validateSqlPermissions] Starting validation for userId:', userId); - console.info('[validateSqlPermissions] SQL query:', sql); - console.info('[validateSqlPermissions] Data source syntax:', dataSourceSyntax); - // Extract physical tables from SQL const tablesInQuery = extractPhysicalTables(sql, dataSourceSyntax); - console.info('[validateSqlPermissions] Tables extracted from SQL:', JSON.stringify(tablesInQuery, null, 2)); if (tablesInQuery.length === 0) { // No tables referenced (might be a function call or constant select) - console.info('[validateSqlPermissions] No tables found in query, allowing access'); return { isAuthorized: true, unauthorizedTables: [] }; } // Get user's permissioned datasets const permissionedDatasets = await getPermissionedDatasets(userId, 0, 1000); - console.info('[validateSqlPermissions] Found', permissionedDatasets.length, 'permissioned datasets for user'); // Extract all allowed tables from datasets const allowedTables: ParsedTable[] = []; @@ -41,15 +34,10 @@ export async function validateSqlPermissions( for (const dataset of permissionedDatasets) { if (dataset.ymlFile) { const tables = extractTablesFromYml(dataset.ymlFile); - console.info('[validateSqlPermissions] Extracted', tables.length, 'tables from dataset:', dataset.name || 'unnamed'); - console.info('[validateSqlPermissions] Tables from YML:', JSON.stringify(tables, null, 2)); allowedTables.push(...tables); } } - console.info('[validateSqlPermissions] Total allowed tables:', allowedTables.length); - console.info('[validateSqlPermissions] All allowed tables:', JSON.stringify(allowedTables, null, 2)); - // Check each table in query against permissions const unauthorizedTables: string[] = []; @@ -60,8 +48,6 @@ export async function validateSqlPermissions( for (const allowedTable of allowedTables) { const matches = tablesMatch(queryTable, allowedTable); if (matches) { - console.info('[validateSqlPermissions] Table match found:', - `Query: ${JSON.stringify(queryTable)} matches Allowed: ${JSON.stringify(allowedTable)}`); isAuthorized = true; break; } @@ -78,11 +64,9 @@ export async function validateSqlPermissions( unauthorizedTables }; - console.info('[validateSqlPermissions] Final result:', JSON.stringify(result, null, 2)); return result; } catch (error) { - console.error('[validateSqlPermissions] Error during validation:', error); return { isAuthorized: false, unauthorizedTables: [], diff --git a/packages/ai/src/utils/sql-permissions/sql-parser-helpers.ts b/packages/ai/src/utils/sql-permissions/sql-parser-helpers.ts index 3107c3ff7..490984a71 100644 --- a/packages/ai/src/utils/sql-permissions/sql-parser-helpers.ts +++ b/packages/ai/src/utils/sql-permissions/sql-parser-helpers.ts @@ -34,15 +34,11 @@ const DIALECT_MAPPING: Record = { function getParserDialect(dataSourceSyntax?: string): string { if (!dataSourceSyntax) { - console.warn('[getParserDialect] No data source syntax provided, defaulting to postgresql'); return 'postgresql'; } const dialect = DIALECT_MAPPING[dataSourceSyntax.toLowerCase()]; if (!dialect) { - console.warn( - `[getParserDialect] Unknown data source syntax: ${dataSourceSyntax}, defaulting to postgresql` - ); return 'postgresql'; } @@ -55,19 +51,14 @@ function getParserDialect(dataSourceSyntax?: string): string { */ export function extractPhysicalTables(sql: string, dataSourceSyntax?: string): ParsedTable[] { const dialect = getParserDialect(dataSourceSyntax); - console.info('[extractPhysicalTables] Using dialect:', dialect, 'for syntax:', dataSourceSyntax); - const parser = new Parser(); try { - console.info('[extractPhysicalTables] Parsing SQL:', sql); - // Parse SQL into AST with the appropriate dialect const ast = parser.astify(sql, { database: dialect }); // Get all table references from parser with the appropriate dialect const allTables = parser.tableList(sql, { database: dialect }); - console.info('[extractPhysicalTables] Raw table list from parser:', allTables); // Extract CTE names to exclude them const cteNames = new Set(); @@ -91,20 +82,16 @@ export function extractPhysicalTables(sql: string, dataSourceSyntax?: string): P const processedTables = new Set(); for (const tableRef of allTables) { - console.info('[extractPhysicalTables] Processing table reference:', tableRef); const parsed = parseTableReference(tableRef); - console.info('[extractPhysicalTables] Parsed table:', JSON.stringify(parsed)); // Skip if it's a CTE if (cteNames.has(parsed.table.toLowerCase())) { - console.info('[extractPhysicalTables] Skipping CTE:', parsed.table); continue; } // Skip duplicates const tableKey = `${parsed.database || ''}.${parsed.schema || ''}.${parsed.table}`; if (processedTables.has(tableKey)) { - console.info('[extractPhysicalTables] Skipping duplicate:', tableKey); continue; } @@ -112,13 +99,8 @@ export function extractPhysicalTables(sql: string, dataSourceSyntax?: string): P physicalTables.push(parsed); } - console.info( - '[extractPhysicalTables] Final physical tables:', - JSON.stringify(physicalTables, null, 2) - ); return physicalTables; } catch (error) { - console.error('[extractPhysicalTables] Error parsing SQL:', error); throw new Error( `Failed to parse SQL: ${error instanceof Error ? error.message : 'Unknown error'}` ); @@ -230,30 +212,14 @@ export function normalizeTableIdentifier(identifier: ParsedTable): string { * For example, "schema.table" matches "database.schema.table" if schema and table match */ export function tablesMatch(queryTable: ParsedTable, permissionTable: ParsedTable): boolean { - console.info('[tablesMatch] Comparing tables:'); - console.info('[tablesMatch] Query table:', JSON.stringify(queryTable)); - console.info('[tablesMatch] Permission table:', JSON.stringify(permissionTable)); - // Exact table name must match if (queryTable.table.toLowerCase() !== permissionTable.table.toLowerCase()) { - console.info( - '[tablesMatch] Table names do not match:', - queryTable.table, - 'vs', - permissionTable.table - ); return false; } // If permission specifies schema, query must match if (permissionTable.schema && queryTable.schema) { if (permissionTable.schema.toLowerCase() !== queryTable.schema.toLowerCase()) { - console.info( - '[tablesMatch] Schemas do not match:', - queryTable.schema, - 'vs', - permissionTable.schema - ); return false; } } @@ -261,12 +227,6 @@ export function tablesMatch(queryTable: ParsedTable, permissionTable: ParsedTabl // If permission specifies database, query must match if (permissionTable.database && queryTable.database) { if (permissionTable.database.toLowerCase() !== queryTable.database.toLowerCase()) { - console.info( - '[tablesMatch] Databases do not match:', - queryTable.database, - 'vs', - permissionTable.database - ); return false; } } @@ -274,11 +234,9 @@ export function tablesMatch(queryTable: ParsedTable, permissionTable: ParsedTabl // If permission has schema but query doesn't, it's not a match // (we require explicit schema matching for security) if (permissionTable.schema && !queryTable.schema) { - console.info('[tablesMatch] Permission requires schema but query has none'); return false; } - console.info('[tablesMatch] Tables match!'); return true; } @@ -299,20 +257,12 @@ export function extractTablesFromYml(ymlContent: string): ParsedTable[] { const tables: ParsedTable[] = []; const processedTables = new Set(); - console.info('[extractTablesFromYml] Starting YML extraction'); - console.info('[extractTablesFromYml] YML content:', `${ymlContent.substring(0, 200)}...`); - try { // Parse YML content const parsed = yaml.parse(ymlContent); - console.info( - '[extractTablesFromYml] Parsed YML structure:', - `${JSON.stringify(parsed, null, 2).substring(0, 500)}...` - ); // Check for flat format (top-level name, schema, database) if (parsed?.name && !parsed?.models && (parsed?.schema || parsed?.database)) { - console.info('[extractTablesFromYml] Found flat format dataset'); const parsedTable: ParsedTable = { table: parsed.name, fullName: parsed.name, @@ -334,7 +284,6 @@ export function extractTablesFromYml(ymlContent: string): ParsedTable[] { } } - console.info('[extractTablesFromYml] Flat format table:', JSON.stringify(parsedTable)); const key = normalizeTableIdentifier(parsedTable); if (!processedTables.has(key)) { processedTables.add(key); @@ -344,13 +293,7 @@ export function extractTablesFromYml(ymlContent: string): ParsedTable[] { // Look for models array if (parsed?.models && Array.isArray(parsed.models)) { - console.info( - '[extractTablesFromYml] Found models array with', - parsed.models.length, - 'models' - ); for (const model of parsed.models) { - console.info('[extractTablesFromYml] Processing model:', JSON.stringify(model)); // Process models that have name and at least schema or database if (model.name && (model.schema || model.database)) { const parsedTable: ParsedTable = { @@ -374,26 +317,17 @@ export function extractTablesFromYml(ymlContent: string): ParsedTable[] { } } - console.info('[extractTablesFromYml] Parsed model table:', JSON.stringify(parsedTable)); const key = normalizeTableIdentifier(parsedTable); if (!processedTables.has(key)) { processedTables.add(key); tables.push(parsedTable); } - } else { - console.warn( - '[extractTablesFromYml] Skipping model without schema/database:', - JSON.stringify(model) - ); } } } - } catch (error) { + } catch (_error) { // If YML parsing fails, return empty array - console.error('[extractTablesFromYml] Failed to parse YML:', error); } - console.info('[extractTablesFromYml] Total tables extracted:', tables.length); - console.info('[extractTablesFromYml] Extracted tables:', JSON.stringify(tables, null, 2)); return tables; }