/** * Universal Data Access Analyzer * Works across multiple programming languages using the adapter pattern * Analyzes database access patterns and data layer interactions */ import { UniversalAnalyzer } from '../../languages/UniversalAnalyzer.js'; import type { Violation } from '../../types.js'; import type { AST, LanguageAdapter } from '../../languages/types.js'; /** * Configuration for Data Access analyzer */ export interface DataAccessAnalyzerConfig { checkOrgFilters?: boolean; checkSQLInjection?: boolean; directAccess?: 'flag' | 'allow'; databases?: { [key: string]: { name: string; importPatterns: string[]; queryPatterns: string[]; ormPatterns?: string[]; }; }; organizationPatterns?: string[]; orgFilterTables?: string[]; orgFilterColumns?: string[]; schemas?: Array<{ name: string; tables: Array<{ name: string; columns: Array<{ name: string; type: string; }>; }>; }>; tablePatterns?: { orm?: RegExp[]; sql?: RegExp[]; queryBuilder?: RegExp[]; }; performanceThresholds?: { complexQueryCount?: number; unfilteredQueryCount?: number; joinedTableCount?: number; }; securityPatterns?: { sqlInjectionRisks?: string[]; parameterizedQueries?: string[]; }; } export declare const DEFAULT_DATA_ACCESS_CONFIG: DataAccessAnalyzerConfig; export declare class UniversalDataAccessAnalyzer extends UniversalAnalyzer { readonly name = "data-access"; readonly description = "Analyzes database access patterns and data layer interactions"; readonly category = "security"; protected analyzeAST(ast: AST, adapter: LanguageAdapter, config: DataAccessAnalyzerConfig, sourceCode: string): Promise; /** * Map imports to database types */ private mapDatabaseImports; /** * Extract database calls from AST */ private extractDatabaseCalls; /** * Analyze a database query */ private analyzeQuery; /** * Check for violations in a database call */ private checkViolations; /** * Check general data access patterns */ private checkGeneralPatterns; /** * Helper methods */ private isFunctionCall; private isTemplateLiteral; private isVariableAssignment; private containsSQLKeywords; /** * Spec 22 R4.2: Requires ≥2 SQL keywords for variable-assignment detection. * * Single-keyword substring matches (e.g. "FROM" inside "Array.from") produce * ~120 false positives on the recall corpus. Genuine SQL in variable * assignments (string literals, ORM chains) almost always has ≥2 keywords * (SELECT+FROM, INSERT+INTO, DELETE+FROM, etc.). * * This is only used for the variable-assignment fallback path — template * literals and function calls use separate, context-aware gating. */ private containsSQLStructure; /** * Spec 17 R2 provenance gate: a template literal is a SQL candidate * because of where it sits (inside a DB-provenanced call's arguments), * NOT because its body contains SQL-shaped substrings. * * Content scanning with substring matching is removed — template bodies * containing natural-language words like "from" or "select" are no longer * misclassified. The cost: template literals assigned to variables whose * values eventually flow to DB calls are not detected (requires dataflow * analysis, which is outside the product's stated scope per Spec 15 R3). */ private isTemplateInDBProvenancedCall; private isOrmPattern; private isDatabaseCall; private extractTables; private hasOrganizationFilter; private checkQuerySecurity; private extractMethodName; /** * Spec 21 R6.2: Three-tier org-filter detection. * * Tier 1 (config-primary): `orgFilterTables` — the user's explicit declaration * of which tables are multi-tenant. Tenancy is policy; this is the * declaration of record. * * Tier 2 (usage-inference secondary): A table requires the filter if the * project's own corpus shows it scoped — i.e., a column matching * `orgFilterColumns` (default: org_id/tenant_id/organization_id/workspace_id) * exists on it in the schema definitions in config. * This is what makes non-English table names (e.g., 注文) detectable * with zero explicit orgFilterTables declaration. * * Tier 3 (fallback): English table list retained as defaults, evidence-tagged * `fallback` like every other name list in Spec 21. */ private requiresOrgFilter; private isStringLiteral; private isConnectionString; /** * R4.1: Find database queries inside loops and flag them as N+1 risks. * Each finding carries the query call location (never line 1). */ private checkLoopQueries; /** * R4.1: Determine if a node is a database call expression. * Lightweight check — reused from extractDatabaseCalls logic. */ /** * R4.1: Determine if a node is a database call expression. * Spec 21: When provenance context is available, uses provenance-based detection * (conjunctive guard — never name alone). In names mode or without context, * falls back to the legacy dbPatterns text match. */ private isDbCallNode; /** * R4.1/R4.2: Walk the parent chain to find the innermost enclosing loop. * Returns the loop node and nesting depth. * * Detects: * - for / while / do loops via adapter.isLoop() * - .forEach / .map / .filter callbacks via AST pattern matching */ private findEnclosingLoop; /** * R4.1: Check if a node is a call_expression invoking an iterator method * (.forEach, .map, .filter, .reduce, .some, .every) — these create * implicit loops where a DB query inside the callback is an N+1 risk. */ private isIteratorCallback; /** * Extract the property name from a property_identifier node. */ private getPropertyName; /** * Walk the parent chain to find the enclosing function/method/arrow name. * Returns 'top-level' if no enclosing function is found. * * Used for stable fingerprint symbols — the enclosing function name is * immune to line drift (Spec 18 Gap 2). */ private findEnclosingFunctionName; /** * Extract the name/identifier from a function or method AST node. */ private getNodeName; } //# sourceMappingURL=UniversalDataAccessAnalyzer.d.ts.map