UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

809 lines (700 loc) 28 kB
tool: schema_version: 2.0 id: supabase type: mcp name: Supabase Platform Management version: 1.0.0 description: Supabase project and database management with SQL execution, migrations, RLS policies, and real-time subscriptions knowledge_strategy: executable executable_knowledge: validators: # Validator for execute_sql - id: validate-execute-sql validates: execute_sql language: javascript checks: - required_fields: [project_id, query] - sql_injection_prevention: true function: | (function() { const errors = []; // 1. Required fields if (!args.args.project_id) { errors.push("project_id is required"); } if (!args.args.query) { errors.push("query is required"); } // 2. Validate project_id format (proj_xxx) if (args.args.project_id && !/^proj_[a-z0-9_]+$/i.test(args.args.project_id)) { errors.push("project_id must match format: proj_[id]"); } // 3. Basic SQL injection prevention if (args.args.query) { const query = args.args.query.toLowerCase(); // Check for dangerous patterns if (query.includes('drop table') || query.includes('drop database')) { errors.push("DROP operations not allowed via execute_sql - use apply_migration"); } // Check for DDL operations if (query.match(/\b(create|alter|drop)\s+(table|index|view|function|trigger)/)) { errors.push("DDL operations not allowed in execute_sql - use apply_migration instead"); } } return { valid: errors.length === 0, errors: errors }; })(); # Validator for apply_migration - id: validate-apply-migration validates: apply_migration language: javascript checks: - required_fields: [project_id, name, query] - migration_name_format: snake_case function: | (function() { const errors = []; // 1. Required fields if (!args.args.project_id) { errors.push("project_id is required"); } if (!args.args.name) { errors.push("name is required"); } if (!args.args.query) { errors.push("query is required"); } // 2. Validate migration name format (snake_case) if (args.args.name && !/^[a-z0-9_]+$/.test(args.args.name)) { errors.push("migration name must be snake_case (lowercase letters, numbers, underscores only)"); } // 3. Check for hardcoded IDs in data migrations if (args.args.query && args.args.query.match(/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i)) { errors.push("WARNING: Migration contains hardcoded UUID - consider using generated IDs instead"); } return { valid: errors.length === 0, errors: errors }; })(); # Validator for create_branch - id: validate-create-branch validates: create_branch language: javascript checks: - required_fields: [project_id, confirm_cost_id] - branch_name_format: true function: | (function() { const errors = []; // 1. Required fields if (!args.args.project_id) { errors.push("project_id is required"); } if (!args.args.confirm_cost_id) { errors.push("confirm_cost_id is required - call confirm_cost first"); } // 2. Validate branch name if provided if (args.args.name && !/^[a-z0-9-]+$/.test(args.args.name)) { errors.push("branch name must be lowercase letters, numbers, and hyphens only"); } return { valid: errors.length === 0, errors: errors }; })(); # Validator for deploy_edge_function - id: validate-deploy-edge-function validates: deploy_edge_function language: javascript checks: - required_fields: [project_id, name, files] - file_structure: true function: | (function() { const errors = []; // 1. Required fields if (!args.args.project_id) { errors.push("project_id is required"); } if (!args.args.name) { errors.push("name is required"); } if (!args.args.files) { errors.push("files array is required"); } // 2. Validate files structure if (args.args.files) { if (!Array.isArray(args.args.files)) { errors.push("files must be an array"); } else { args.args.files.forEach((file, index) => { if (!file.name) { errors.push(`files[${index}] missing required 'name' field`); } if (!file.content) { errors.push(`files[${index}] missing required 'content' field`); } }); } } // 3. Check for entrypoint if (args.args.entrypoint_path && !args.args.entrypoint_path.endsWith('.ts')) { errors.push("entrypoint_path should be a TypeScript file (.ts)"); } return { valid: errors.length === 0, errors: errors }; })(); # Validator for create_project - id: validate-create-project validates: create_project language: javascript checks: - required_fields: [name, region, organization_id, confirm_cost_id] - region_validation: true function: | (function() { const errors = []; // 1. Required fields if (!args.args.name) { errors.push("name is required"); } if (!args.args.region) { errors.push("region is required"); } if (!args.args.organization_id) { errors.push("organization_id is required"); } if (!args.args.confirm_cost_id) { errors.push("confirm_cost_id is required - call confirm_cost first"); } // 2. Validate region const validRegions = [ 'us-west-1', 'us-east-1', 'us-east-2', 'ca-central-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-central-1', 'eu-central-2', 'eu-north-1', 'ap-south-1', 'ap-southeast-1', 'ap-northeast-1', 'ap-northeast-2', 'ap-southeast-2', 'sa-east-1' ]; if (args.args.region && !validRegions.includes(args.args.region)) { errors.push(`region must be one of: ${validRegions.join(', ')}`); } return { valid: errors.length === 0, errors: errors }; })(); helpers: - id: build-select-query language: javascript runtime: isolated_vm description: "Build SELECT query with RLS considerations" function: | (function() { const { table, columns, where, orderBy, limit, checkRLS } = args; if (!table) { return { error: 'Table name is required' }; } let query = 'SELECT '; query += columns && columns.length > 0 ? columns.join(', ') : '*'; query += ` FROM ${table}`; if (where && typeof where === 'object') { const conditions = Object.entries(where) .map(([key, value]) => { if (typeof value === 'string') { return `${key} = '${value}'`; } return `${key} = ${value}`; }) .join(' AND '); query += ` WHERE ${conditions}`; } if (orderBy) { query += ` ORDER BY ${orderBy}`; } if (limit) { query += ` LIMIT ${limit}`; } return { query: query, requiresRLS: checkRLS !== false, hint: checkRLS !== false ? 'Ensure RLS policies are enabled on this table' : null }; })(); - id: build-insert-query language: javascript runtime: isolated_vm description: "Build INSERT query with RLS validation" function: | (function() { const { table, data, returning } = args; if (!table) { return { error: 'Table name is required' }; } if (!data || typeof data !== 'object') { return { error: 'Data object is required' }; } const columns = Object.keys(data); const values = Object.values(data).map(v => { if (typeof v === 'string') { return `'${v}'`; } if (v === null) { return 'NULL'; } return v; }); let query = `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${values.join(', ')})`; if (returning) { query += ` RETURNING ${returning === true ? '*' : returning}`; } return { query: query, requiresRLS: true, hint: 'Ensure user has INSERT permissions via RLS policy' }; })(); - id: build-update-query language: javascript runtime: isolated_vm description: "Build UPDATE query with RLS validation" function: | (function() { const { table, data, where, returning } = args; if (!table) { return { error: 'Table name is required' }; } if (!data || typeof data !== 'object') { return { error: 'Data object is required' }; } if (!where || typeof where !== 'object') { return { error: 'WHERE condition is required for UPDATE' }; } const setClauses = Object.entries(data).map(([key, value]) => { if (typeof value === 'string') { return `${key} = '${value}'`; } if (value === null) { return `${key} = NULL`; } return `${key} = ${value}`; }); const whereClauses = Object.entries(where).map(([key, value]) => { if (typeof value === 'string') { return `${key} = '${value}'`; } return `${key} = ${value}`; }); let query = `UPDATE ${table} SET ${setClauses.join(', ')} WHERE ${whereClauses.join(' AND ')}`; if (returning) { query += ` RETURNING ${returning === true ? '*' : returning}`; } return { query: query, requiresRLS: true, hint: 'Ensure user has UPDATE permissions via RLS policy' }; })(); - id: validate-rls-policy language: javascript runtime: isolated_vm description: "Validate RLS policy syntax and structure" function: | (function() { const { policy, table, operation } = args; if (!policy || typeof policy !== 'object') { return { valid: false, errors: ['Policy object is required'] }; } const errors = []; // Check required fields if (!policy.name) { errors.push('Policy name is required'); } if (!table) { errors.push('Table name is required'); } if (!operation) { errors.push('Operation is required (SELECT, INSERT, UPDATE, DELETE, ALL)'); } // Validate operation const validOperations = ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'ALL']; if (operation && !validOperations.includes(operation.toUpperCase())) { errors.push(`Operation must be one of: ${validOperations.join(', ')}`); } // Check for USING clause (required for SELECT, UPDATE, DELETE, ALL) if (!policy.using && ['SELECT', 'UPDATE', 'DELETE', 'ALL'].includes(operation?.toUpperCase())) { errors.push('USING clause is required for this operation'); } // Check for WITH CHECK clause (required for INSERT, UPDATE) if (!policy.withCheck && ['INSERT', 'UPDATE'].includes(operation?.toUpperCase())) { errors.push('WITH CHECK clause recommended for this operation'); } return { valid: errors.length === 0, errors: errors, warnings: policy.withCheck ? [] : ['Consider adding WITH CHECK clause for additional security'] }; })(); - id: format-realtime-subscription language: javascript runtime: isolated_vm description: "Format real-time subscription configuration" function: | (function() { const { table, event, filter, schema } = args; if (!table) { return { error: 'Table name is required' }; } const events = event ? (Array.isArray(event) ? event : [event]) : ['INSERT', 'UPDATE', 'DELETE']; const config = { event: events.join(','), schema: schema || 'public', table: table }; if (filter) { config.filter = filter; } return { channel: `${schema || 'public'}:${table}`, config: config, example: ` const channel = supabase .channel('${schema || 'public'}:${table}') .on('postgres_changes', ${JSON.stringify(config, null, 2)}, (payload) => { console.log('Change received!', payload) }) .subscribe() ` }; })(); - id: validate-table-permissions language: javascript runtime: isolated_vm description: "Validate table permissions and RLS status" function: | (function() { const { table, hasRLS, policies } = args; if (!table) { return { error: 'Table name is required' }; } const warnings = []; const recommendations = []; // Check if RLS is enabled if (hasRLS === false) { warnings.push('RLS is disabled - table data is publicly accessible'); recommendations.push('Enable RLS with: ALTER TABLE ' + table + ' ENABLE ROW LEVEL SECURITY'); } // Check if policies exist if (hasRLS && (!policies || policies.length === 0)) { warnings.push('RLS is enabled but no policies exist - table is inaccessible'); recommendations.push('Create at least one RLS policy to allow access'); } // Check for overly permissive policies if (policies && Array.isArray(policies)) { policies.forEach(policy => { if (policy.using === 'true' || policy.using === '(true)') { warnings.push(`Policy '${policy.name}' allows access to all rows`); } if (policy.operation === 'ALL' && (policy.using === 'true' || !policy.using)) { warnings.push(`Policy '${policy.name}' allows all operations without restrictions`); } }); } return { table: table, rlsEnabled: hasRLS === true, policyCount: policies ? policies.length : 0, warnings: warnings, recommendations: recommendations, isSecure: hasRLS && policies && policies.length > 0 }; })(); - id: parse-postgres-error language: javascript runtime: isolated_vm description: "Parse and format Postgres error messages" function: | (function() { const { error, query } = args; if (!error) { return null; } const result = { message: error.message || 'Unknown error', code: error.code || null, hint: null, context: query ? `Query: ${query.substring(0, 100)}...` : null }; // Common Postgres error codes const errorMap = { '23505': 'Unique constraint violation', '23503': 'Foreign key constraint violation', '23502': 'Not null constraint violation', '23514': 'Check constraint violation', '42P01': 'Table does not exist', '42703': 'Column does not exist', '42501': 'Insufficient privilege (check RLS policies)', '42883': 'Function does not exist' }; if (error.code && errorMap[error.code]) { result.hint = errorMap[error.code]; } // RLS-specific hints if (error.code === '42501' || error.message?.includes('permission denied')) { result.hint = 'Permission denied - check RLS policies and user authentication'; result.rlsHint = 'Ensure user is authenticated and RLS policy allows this operation'; } return result; })(); - id: generate-migration-name language: javascript runtime: isolated_vm description: "Generate timestamped migration name" function: | (function() { const { description } = args; if (!description) { return { error: 'Description is required' }; } // Convert to snake_case const snakeCase = description .toLowerCase() .replace(/[^a-z0-9]+/g, '_') .replace(/^_|_$/g, ''); // Generate timestamp (YYYYMMDDHHMMSS format) const now = new Date(); const timestamp = now.toISOString() .replace(/[-:T.]/g, '') .substring(0, 14); const migrationName = `${timestamp}_${snakeCase}`; return { name: migrationName, timestamp: timestamp, description: snakeCase, example: `apply_migration({ name: "${migrationName}", query: "..." })` }; })(); api_complexity: rls_policy_patterns: - pattern: authenticated_user description: "Allow access only to authenticated users" example: | USING (auth.uid() IS NOT NULL) use_case: "Restrict access to logged-in users only" - pattern: user_owned_rows description: "Users can only access their own rows" example: | USING (auth.uid() = user_id) use_case: "Private user data (profiles, settings)" - pattern: role_based_access description: "Access based on user role" example: | USING ( EXISTS ( SELECT 1 FROM user_roles WHERE user_id = auth.uid() AND role IN ('admin', 'editor') ) ) use_case: "Admin panels, content management" - pattern: team_member_access description: "Access for team/organization members" example: | USING ( EXISTS ( SELECT 1 FROM team_members WHERE team_id = projects.team_id AND user_id = auth.uid() ) ) use_case: "Collaborative workspaces, multi-tenant apps" realtime_subscription_patterns: - pattern: table_changes description: "Subscribe to all changes on a table" config: | { event: '*', schema: 'public', table: 'messages' } use_case: "Real-time chat, activity feeds" - pattern: filtered_changes description: "Subscribe to specific rows" config: | { event: 'INSERT', schema: 'public', table: 'messages', filter: 'room_id=eq.123' } use_case: "Room-specific updates, filtered feeds" - pattern: user_specific_changes description: "Subscribe to user's own data" config: | { event: '*', schema: 'public', table: 'notifications', filter: 'user_id=eq.[USER_ID]' } use_case: "User notifications, personal updates" auth_integration_quirks: - quirk: auth_uid_null description: "auth.uid() returns NULL for unauthenticated requests" impact: "RLS policies using auth.uid() will block anonymous access" solution: "Use separate policies for authenticated and anonymous users" - quirk: jwt_token_expiry description: "JWT tokens expire after configured duration (default 1 hour)" impact: "Long-running operations may fail mid-execution" solution: "Implement token refresh logic in client applications" - quirk: rls_bypass_service_role description: "Service role key bypasses RLS policies" impact: "Backend operations ignore RLS - can access all data" solution: "Never expose service role key to clients - use anon/user keys only" - quirk: policy_evaluation_order description: "Multiple policies are OR'd together (any match grants access)" impact: "Cannot create deny policies - all policies must grant access" solution: "Design policies to be restrictive by default" anti_patterns: - pattern: missing_rls_policies description: "Enabling RLS without creating policies" category: security severity: high wrong: | ALTER TABLE users ENABLE ROW LEVEL SECURITY; -- ❌ No policies created - table is now inaccessible correct: | ALTER TABLE users ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can view own profile" ON users FOR SELECT USING (auth.uid() = id); CREATE POLICY "Users can update own profile" ON users FOR UPDATE USING (auth.uid() = id); -- RLS enabled with appropriate policies rationale: "RLS without policies makes tables completely inaccessible. Always create policies after enabling RLS." - pattern: overly_permissive_policies description: "Using USING (true) for all operations" category: security severity: critical wrong: | CREATE POLICY "Allow all" ON sensitive_data FOR ALL USING (true); -- ❌ Allows anyone to do anything correct: | CREATE POLICY "Allow authenticated users" ON sensitive_data FOR SELECT USING (auth.uid() IS NOT NULL AND auth.uid() = user_id); -- ✅ Restricts access to authenticated users and their own data rationale: "USING (true) defeats the purpose of RLS. Always implement meaningful access controls." - pattern: hardcoded_uuids_in_migrations description: "Hardcoding UUIDs in data migrations" category: migrations severity: medium wrong: | -- ❌ Hardcoded UUID will fail if record doesn't exist INSERT INTO projects (id, name, owner_id) VALUES ('123e4567-e89b-12d3-a456-426614174000', 'My Project', '...'); correct: | -- ✅ Generate UUIDs or use RETURNING clause INSERT INTO projects (name, owner_id) VALUES ('My Project', (SELECT id FROM users WHERE email = 'admin@example.com')) RETURNING id; rationale: "Hardcoded UUIDs cause migration failures across environments. Use generated IDs or lookups." - pattern: ddl_in_execute_sql description: "Running DDL operations via execute_sql" category: migrations severity: high wrong: | execute_sql({ query: "CREATE TABLE users (id uuid, name text)" }) -- ❌ DDL not tracked in migrations correct: | apply_migration({ name: "create_users_table", query: "CREATE TABLE users (id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), name text NOT NULL)" }) -- ✅ DDL tracked in migrations table rationale: "DDL operations must be tracked via migrations for version control and rollback capability." examples: execute_sql: - scenario: success description: "Execute SELECT query with RLS" input: project_id: "proj_abc123" query: "SELECT * FROM posts WHERE user_id = auth.uid()" output: rows: [{ id: 1, title: "My Post", user_id: "user_xyz" }] count: 1 - scenario: failure_invalid_param description: "Missing required project_id" input: query: "SELECT * FROM posts" error: code: VALIDATION_ERROR message: "project_id is required" validator: validate-execute-sql - scenario: failure_ddl_operation description: "Attempting DDL via execute_sql" input: project_id: "proj_abc123" query: "CREATE TABLE test (id int)" error: code: VALIDATION_ERROR message: "DDL operations not allowed in execute_sql - use apply_migration instead" validator: validate-execute-sql apply_migration: - scenario: success description: "Apply migration to create table" input: project_id: "proj_abc123" name: "create_posts_table" query: | CREATE TABLE posts ( id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), title text NOT NULL, content text, user_id uuid REFERENCES auth.users(id), created_at timestamptz DEFAULT now() ); ALTER TABLE posts ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can view own posts" ON posts FOR SELECT USING (auth.uid() = user_id); output: migration_id: "mig_xyz789" status: "applied" - scenario: failure_invalid_param description: "Invalid migration name format" input: project_id: "proj_abc123" name: "CreatePostsTable" query: "CREATE TABLE posts (id int)" error: code: VALIDATION_ERROR message: "migration name must be snake_case (lowercase letters, numbers, underscores only)" validator: validate-apply-migration mcp_specific: server_command: "https://mcp.supabase.com/mcp" transport: sse auth: oauth query_parameters: - name: project_ref required: false description: "Scope server to specific project (recommended)" - name: read_only required: false description: "Restrict to read-only operations (recommended)" - name: features required: false description: "Specify which tool groups to enable" health_check: method: tool_call command: list_projects expected_response: "Array of projects or organization prompt" timeout_ms: 10000