@freshguard/freshguard-core 0.13.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/README.md +74 -1
  3. package/SKILL.md +229 -0
  4. package/dist/cli/index.d.ts +13 -0
  5. package/dist/cli/index.d.ts.map +1 -1
  6. package/dist/cli/index.js +74 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/connectors/azure-sql.d.ts +121 -0
  9. package/dist/connectors/azure-sql.d.ts.map +1 -0
  10. package/dist/connectors/azure-sql.js +489 -0
  11. package/dist/connectors/azure-sql.js.map +1 -0
  12. package/dist/connectors/base-connector.d.ts +139 -0
  13. package/dist/connectors/base-connector.d.ts.map +1 -1
  14. package/dist/connectors/base-connector.js +160 -3
  15. package/dist/connectors/base-connector.js.map +1 -1
  16. package/dist/connectors/bigquery.d.ts +100 -0
  17. package/dist/connectors/bigquery.d.ts.map +1 -1
  18. package/dist/connectors/bigquery.js +143 -2
  19. package/dist/connectors/bigquery.js.map +1 -1
  20. package/dist/connectors/duckdb.d.ts +96 -0
  21. package/dist/connectors/duckdb.d.ts.map +1 -1
  22. package/dist/connectors/duckdb.js +144 -7
  23. package/dist/connectors/duckdb.js.map +1 -1
  24. package/dist/connectors/index.d.ts +28 -0
  25. package/dist/connectors/index.d.ts.map +1 -1
  26. package/dist/connectors/index.js +28 -0
  27. package/dist/connectors/index.js.map +1 -1
  28. package/dist/connectors/mssql.d.ts +119 -0
  29. package/dist/connectors/mssql.d.ts.map +1 -0
  30. package/dist/connectors/mssql.js +483 -0
  31. package/dist/connectors/mssql.js.map +1 -0
  32. package/dist/connectors/mysql.d.ts +85 -0
  33. package/dist/connectors/mysql.d.ts.map +1 -1
  34. package/dist/connectors/mysql.js +118 -3
  35. package/dist/connectors/mysql.js.map +1 -1
  36. package/dist/connectors/postgres.d.ts +85 -0
  37. package/dist/connectors/postgres.d.ts.map +1 -1
  38. package/dist/connectors/postgres.js +113 -6
  39. package/dist/connectors/postgres.js.map +1 -1
  40. package/dist/connectors/redshift.d.ts +90 -0
  41. package/dist/connectors/redshift.d.ts.map +1 -1
  42. package/dist/connectors/redshift.js +131 -7
  43. package/dist/connectors/redshift.js.map +1 -1
  44. package/dist/connectors/snowflake.d.ts +108 -0
  45. package/dist/connectors/snowflake.d.ts.map +1 -1
  46. package/dist/connectors/snowflake.js +137 -3
  47. package/dist/connectors/snowflake.js.map +1 -1
  48. package/dist/connectors/synapse.d.ts +123 -0
  49. package/dist/connectors/synapse.d.ts.map +1 -0
  50. package/dist/connectors/synapse.js +495 -0
  51. package/dist/connectors/synapse.js.map +1 -0
  52. package/dist/db/index.d.ts +25 -0
  53. package/dist/db/index.d.ts.map +1 -1
  54. package/dist/db/index.js +23 -0
  55. package/dist/db/index.js.map +1 -1
  56. package/dist/db/migrate.d.ts +23 -0
  57. package/dist/db/migrate.d.ts.map +1 -1
  58. package/dist/db/migrate.js +38 -0
  59. package/dist/db/migrate.js.map +1 -1
  60. package/dist/db/schema.d.ts +11 -0
  61. package/dist/db/schema.d.ts.map +1 -1
  62. package/dist/db/schema.js +70 -0
  63. package/dist/db/schema.js.map +1 -1
  64. package/dist/errors/debug-factory.d.ts +38 -0
  65. package/dist/errors/debug-factory.d.ts.map +1 -1
  66. package/dist/errors/debug-factory.js +40 -0
  67. package/dist/errors/debug-factory.js.map +1 -1
  68. package/dist/errors/index.d.ts +59 -0
  69. package/dist/errors/index.d.ts.map +1 -1
  70. package/dist/errors/index.js +110 -7
  71. package/dist/errors/index.js.map +1 -1
  72. package/dist/index.d.ts +32 -1
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +37 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/metadata/duckdb-storage.d.ts +3 -0
  77. package/dist/metadata/duckdb-storage.d.ts.map +1 -1
  78. package/dist/metadata/duckdb-storage.js +6 -0
  79. package/dist/metadata/duckdb-storage.js.map +1 -1
  80. package/dist/metadata/factory.d.ts +30 -0
  81. package/dist/metadata/factory.d.ts.map +1 -1
  82. package/dist/metadata/factory.js +31 -0
  83. package/dist/metadata/factory.js.map +1 -1
  84. package/dist/metadata/index.d.ts +26 -0
  85. package/dist/metadata/index.d.ts.map +1 -1
  86. package/dist/metadata/index.js +26 -0
  87. package/dist/metadata/index.js.map +1 -1
  88. package/dist/metadata/interface.d.ts +33 -0
  89. package/dist/metadata/interface.d.ts.map +1 -1
  90. package/dist/metadata/interface.js +3 -0
  91. package/dist/metadata/interface.js.map +1 -1
  92. package/dist/metadata/postgresql-storage.d.ts +3 -0
  93. package/dist/metadata/postgresql-storage.d.ts.map +1 -1
  94. package/dist/metadata/postgresql-storage.js +12 -2
  95. package/dist/metadata/postgresql-storage.js.map +1 -1
  96. package/dist/metadata/schema-config.d.ts +53 -0
  97. package/dist/metadata/schema-config.d.ts.map +1 -1
  98. package/dist/metadata/schema-config.js +64 -0
  99. package/dist/metadata/schema-config.js.map +1 -1
  100. package/dist/metadata/types.d.ts +3 -0
  101. package/dist/metadata/types.d.ts.map +1 -1
  102. package/dist/metadata/types.js +3 -0
  103. package/dist/metadata/types.js.map +1 -1
  104. package/dist/monitor/baseline-calculator.d.ts +56 -0
  105. package/dist/monitor/baseline-calculator.d.ts.map +1 -1
  106. package/dist/monitor/baseline-calculator.js +72 -0
  107. package/dist/monitor/baseline-calculator.js.map +1 -1
  108. package/dist/monitor/baseline-config.d.ts +77 -0
  109. package/dist/monitor/baseline-config.d.ts.map +1 -1
  110. package/dist/monitor/baseline-config.js +79 -1
  111. package/dist/monitor/baseline-config.js.map +1 -1
  112. package/dist/monitor/freshness.d.ts +40 -0
  113. package/dist/monitor/freshness.d.ts.map +1 -1
  114. package/dist/monitor/freshness.js +82 -3
  115. package/dist/monitor/freshness.js.map +1 -1
  116. package/dist/monitor/index.d.ts +29 -0
  117. package/dist/monitor/index.d.ts.map +1 -1
  118. package/dist/monitor/index.js +29 -0
  119. package/dist/monitor/index.js.map +1 -1
  120. package/dist/monitor/schema-baseline.d.ts +45 -0
  121. package/dist/monitor/schema-baseline.d.ts.map +1 -1
  122. package/dist/monitor/schema-baseline.js +63 -5
  123. package/dist/monitor/schema-baseline.js.map +1 -1
  124. package/dist/monitor/schema-changes.d.ts +45 -0
  125. package/dist/monitor/schema-changes.d.ts.map +1 -1
  126. package/dist/monitor/schema-changes.js +85 -0
  127. package/dist/monitor/schema-changes.js.map +1 -1
  128. package/dist/monitor/volume.d.ts +43 -0
  129. package/dist/monitor/volume.d.ts.map +1 -1
  130. package/dist/monitor/volume.js +89 -0
  131. package/dist/monitor/volume.js.map +1 -1
  132. package/dist/observability/logger.d.ts +91 -0
  133. package/dist/observability/logger.d.ts.map +1 -1
  134. package/dist/observability/logger.js +108 -0
  135. package/dist/observability/logger.js.map +1 -1
  136. package/dist/observability/metrics.d.ts +140 -0
  137. package/dist/observability/metrics.d.ts.map +1 -1
  138. package/dist/observability/metrics.js +184 -7
  139. package/dist/observability/metrics.js.map +1 -1
  140. package/dist/resilience/circuit-breaker.d.ts +112 -2
  141. package/dist/resilience/circuit-breaker.d.ts.map +1 -1
  142. package/dist/resilience/circuit-breaker.js +140 -6
  143. package/dist/resilience/circuit-breaker.js.map +1 -1
  144. package/dist/resilience/index.d.ts +9 -0
  145. package/dist/resilience/index.d.ts.map +1 -1
  146. package/dist/resilience/index.js +13 -0
  147. package/dist/resilience/index.js.map +1 -1
  148. package/dist/resilience/retry-policy.d.ts +105 -0
  149. package/dist/resilience/retry-policy.d.ts.map +1 -1
  150. package/dist/resilience/retry-policy.js +158 -7
  151. package/dist/resilience/retry-policy.js.map +1 -1
  152. package/dist/resilience/timeout-manager.d.ts +137 -0
  153. package/dist/resilience/timeout-manager.d.ts.map +1 -1
  154. package/dist/resilience/timeout-manager.js +151 -4
  155. package/dist/resilience/timeout-manager.js.map +1 -1
  156. package/dist/security/query-analyzer.d.ts +124 -0
  157. package/dist/security/query-analyzer.d.ts.map +1 -1
  158. package/dist/security/query-analyzer.js +150 -9
  159. package/dist/security/query-analyzer.js.map +1 -1
  160. package/dist/security/schema-cache.d.ts +152 -0
  161. package/dist/security/schema-cache.d.ts.map +1 -1
  162. package/dist/security/schema-cache.js +144 -12
  163. package/dist/security/schema-cache.js.map +1 -1
  164. package/dist/types/connector.d.ts +68 -1
  165. package/dist/types/connector.d.ts.map +1 -1
  166. package/dist/types/connector.js +38 -15
  167. package/dist/types/connector.js.map +1 -1
  168. package/dist/types/driver-results.d.ts +28 -0
  169. package/dist/types/driver-results.d.ts.map +1 -1
  170. package/dist/types/driver-results.js +12 -0
  171. package/dist/types/driver-results.js.map +1 -1
  172. package/dist/types.d.ts +113 -1
  173. package/dist/types.d.ts.map +1 -1
  174. package/dist/types.js +8 -0
  175. package/dist/types.js.map +1 -1
  176. package/dist/validation/index.d.ts +8 -0
  177. package/dist/validation/index.d.ts.map +1 -1
  178. package/dist/validation/index.js +12 -0
  179. package/dist/validation/index.js.map +1 -1
  180. package/dist/validation/runtime-validator.d.ts +98 -0
  181. package/dist/validation/runtime-validator.d.ts.map +1 -1
  182. package/dist/validation/runtime-validator.js +114 -1
  183. package/dist/validation/runtime-validator.js.map +1 -1
  184. package/dist/validation/sanitizers.d.ts +59 -0
  185. package/dist/validation/sanitizers.d.ts.map +1 -1
  186. package/dist/validation/sanitizers.js +104 -20
  187. package/dist/validation/sanitizers.js.map +1 -1
  188. package/dist/validation/schemas.d.ts +73 -0
  189. package/dist/validation/schemas.d.ts.map +1 -1
  190. package/dist/validation/schemas.js +132 -5
  191. package/dist/validation/schemas.js.map +1 -1
  192. package/dist/validators/index.d.ts +54 -0
  193. package/dist/validators/index.d.ts.map +1 -1
  194. package/dist/validators/index.js +93 -2
  195. package/dist/validators/index.js.map +1 -1
  196. package/package.json +6 -2
@@ -1,82 +1,206 @@
1
+ /**
2
+ * Query Complexity Analyzer for FreshGuard Core Phase 2
3
+ *
4
+ * Analyzes SQL queries for complexity and security risks, providing
5
+ * risk scoring and recommendations for safe query execution.
6
+ *
7
+ * @license MIT
8
+ */
9
+ /**
10
+ * Query complexity analysis result
11
+ */
1
12
  export interface QueryComplexity {
13
+ /** Whether the query should be allowed to execute */
2
14
  allowExecution: boolean;
15
+ /** Risk score from 0 (safe) to 100 (dangerous) */
3
16
  riskScore: number;
17
+ /** Complexity score based on query structure */
4
18
  complexityScore: number;
19
+ /** Estimated execution cost */
5
20
  estimatedCost: number;
21
+ /** Security warnings found */
6
22
  securityWarnings: string[];
23
+ /** Performance warnings found */
7
24
  performanceWarnings: string[];
25
+ /** Recommendations for optimization */
8
26
  recommendations: string[];
27
+ /** Query analysis details */
9
28
  details: QueryAnalysisDetails;
10
29
  }
30
+ /**
31
+ * Detailed query analysis breakdown
32
+ */
11
33
  export interface QueryAnalysisDetails {
34
+ /** Query type (SELECT, INSERT, etc.) */
12
35
  queryType: string;
36
+ /** Number of tables involved */
13
37
  tableCount: number;
38
+ /** Number of joins */
14
39
  joinCount: number;
40
+ /** Has subqueries */
15
41
  hasSubqueries: boolean;
42
+ /** Has aggregations */
16
43
  hasAggregations: boolean;
44
+ /** Has wildcards in SELECT */
17
45
  hasWildcards: boolean;
46
+ /** Has LIMIT clause */
18
47
  hasLimit: boolean;
48
+ /** LIMIT value if present */
19
49
  limitValue?: number;
50
+ /** Has WHERE clause */
20
51
  hasWhere: boolean;
52
+ /** Has ORDER BY clause */
21
53
  hasOrderBy: boolean;
54
+ /** Has GROUP BY clause */
22
55
  hasGroupBy: boolean;
56
+ /** Has HAVING clause */
23
57
  hasHaving: boolean;
58
+ /** Estimated result set size */
24
59
  estimatedResultSize: number;
25
60
  }
61
+ /**
62
+ * Table metadata for analysis
63
+ */
26
64
  export interface TableMetadata {
65
+ /** Table name */
27
66
  name: string;
67
+ /** Estimated row count */
28
68
  estimatedRows: number;
69
+ /** Table size in bytes */
29
70
  sizeBytes?: number;
71
+ /** Available indexes */
30
72
  indexes: IndexInfo[];
73
+ /** Column information */
31
74
  columns: ColumnInfo[];
75
+ /** When metadata was last updated */
32
76
  lastUpdated: Date;
33
77
  }
78
+ /**
79
+ * Index information
80
+ */
34
81
  export interface IndexInfo {
82
+ /** Index name */
35
83
  name: string;
84
+ /** Columns in the index */
36
85
  columns: string[];
86
+ /** Whether index is unique */
37
87
  unique: boolean;
88
+ /** Index type (btree, hash, etc.) */
38
89
  type?: string;
39
90
  }
91
+ /**
92
+ * Column information
93
+ */
40
94
  export interface ColumnInfo {
95
+ /** Column name */
41
96
  name: string;
97
+ /** Data type */
42
98
  type: string;
99
+ /** Whether column is nullable */
43
100
  nullable: boolean;
101
+ /** Whether column is indexed */
44
102
  indexed: boolean;
103
+ /** Estimated cardinality */
45
104
  cardinality?: number;
46
105
  }
106
+ /**
107
+ * Query analyzer configuration
108
+ */
47
109
  export interface QueryAnalyzerConfig {
110
+ /** Maximum risk score to allow execution (0-100) */
48
111
  maxRiskScore: number;
112
+ /** Maximum complexity score to allow (0-100) */
49
113
  maxComplexityScore: number;
114
+ /** Maximum estimated cost to allow */
50
115
  maxEstimatedCost: number;
116
+ /** Maximum result set size to allow */
51
117
  maxResultSetSize: number;
118
+ /** Enable performance analysis */
52
119
  enablePerformanceAnalysis: boolean;
120
+ /** Enable security analysis */
53
121
  enableSecurityAnalysis: boolean;
122
+ /** Custom risk factors */
54
123
  customRiskFactors: RiskFactor[];
55
124
  }
125
+ /**
126
+ * Custom risk factor definition
127
+ */
56
128
  export interface RiskFactor {
129
+ /** Pattern to match */
57
130
  pattern: RegExp;
131
+ /** Risk score to add (0-100) */
58
132
  riskScore: number;
133
+ /** Description of the risk */
59
134
  description: string;
135
+ /** Whether this should block execution */
60
136
  blocking: boolean;
61
137
  }
138
+ /**
139
+ * Analyzes SQL queries for complexity and security risks
140
+ */
62
141
  export declare class QueryComplexityAnalyzer {
63
142
  private config;
64
143
  private readonly riskFactors;
65
144
  constructor(config?: Partial<QueryAnalyzerConfig>);
145
+ /**
146
+ * Analyze a SQL query for complexity and security risks
147
+ */
66
148
  analyzeQuery(sql: string, tableMetadata?: TableMetadata[]): QueryComplexity;
149
+ /**
150
+ * Calculate query complexity score (0-100)
151
+ */
67
152
  private calculateComplexityScore;
153
+ /**
154
+ * Calculate security risk score (0-100)
155
+ */
68
156
  private calculateRiskScore;
157
+ /**
158
+ * Calculate estimated execution cost
159
+ */
69
160
  private calculateEstimatedCost;
161
+ /**
162
+ * Generate security warnings
163
+ */
70
164
  private generateSecurityWarnings;
165
+ /**
166
+ * Generate performance warnings
167
+ */
71
168
  private generatePerformanceWarnings;
169
+ /**
170
+ * Generate optimization recommendations
171
+ */
72
172
  private generateRecommendations;
173
+ /**
174
+ * Determine if query execution should be allowed
175
+ */
73
176
  private shouldAllowExecution;
177
+ /**
178
+ * Update configuration
179
+ */
74
180
  updateConfig(config: Partial<QueryAnalyzerConfig>): void;
181
+ /**
182
+ * Add custom risk factor
183
+ */
75
184
  addRiskFactor(factor: RiskFactor): void;
185
+ /**
186
+ * Get current configuration
187
+ */
76
188
  getConfig(): QueryAnalyzerConfig;
77
189
  }
190
+ /**
191
+ * Create a query analyzer with default configuration
192
+ */
78
193
  export declare function createQueryAnalyzer(config?: Partial<QueryAnalyzerConfig>): QueryComplexityAnalyzer;
194
+ /**
195
+ * Create a strict security analyzer
196
+ */
79
197
  export declare function createSecurityAnalyzer(): QueryComplexityAnalyzer;
198
+ /**
199
+ * Create a performance-focused analyzer
200
+ */
80
201
  export declare function createPerformanceAnalyzer(): QueryComplexityAnalyzer;
202
+ /**
203
+ * Default query analyzer instance
204
+ */
81
205
  export declare const defaultQueryAnalyzer: QueryComplexityAnalyzer;
82
206
  //# sourceMappingURL=query-analyzer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-analyzer.d.ts","sourceRoot":"","sources":["../../src/security/query-analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query-analyzer.d.ts","sourceRoot":"","sources":["../../src/security/query-analyzer.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,29 @@
1
+ /**
2
+ * Query Complexity Analyzer for FreshGuard Core Phase 2
3
+ *
4
+ * Analyzes SQL queries for complexity and security risks, providing
5
+ * risk scoring and recommendations for safe query execution.
6
+ *
7
+ * @license MIT
8
+ */
9
+ // ==============================================
10
+ // Default Configuration
11
+ // ==============================================
12
+ /**
13
+ * Default query analyzer configuration
14
+ */
1
15
  const DEFAULT_CONFIG = {
2
16
  maxRiskScore: 70,
3
17
  maxComplexityScore: 80,
4
- maxEstimatedCost: 1000000,
18
+ maxEstimatedCost: 1000000, // 1 million cost units
5
19
  maxResultSetSize: 10000,
6
20
  enablePerformanceAnalysis: true,
7
21
  enableSecurityAnalysis: true,
8
22
  customRiskFactors: []
9
23
  };
24
+ /**
25
+ * Default risk factors for security analysis
26
+ */
10
27
  const DEFAULT_RISK_FACTORS = [
11
28
  {
12
29
  pattern: /union\s+all|union\s+select/i,
@@ -63,12 +80,26 @@ const DEFAULT_RISK_FACTORS = [
63
80
  blocking: false
64
81
  }
65
82
  ];
83
+ // ==============================================
84
+ // SQL Parser Utilities
85
+ // ==============================================
86
+ /**
87
+ * Simple SQL parser for query analysis
88
+ * Note: This is a simplified parser for basic analysis
89
+ */
66
90
  class SimpleSQLParser {
91
+ /**
92
+ * Parse basic query structure
93
+ */
67
94
  static parseQuery(sql) {
68
95
  const normalizedSql = sql.trim().toLowerCase();
96
+ // Determine query type
69
97
  const queryType = this.getQueryType(normalizedSql);
98
+ // Count tables (simplified - counts FROM and JOIN clauses)
70
99
  const tableCount = this.countTables(normalizedSql);
100
+ // Count joins
71
101
  const joinCount = this.countJoins(normalizedSql);
102
+ // Check for various SQL constructs
72
103
  const hasSubqueries = /\(\s*select\b/.test(normalizedSql);
73
104
  const hasAggregations = /\b(count|sum|avg|max|min|group_concat)\s*\(/.test(normalizedSql);
74
105
  const hasWildcards = /select\s+\*\s+from\b/.test(normalizedSql);
@@ -76,9 +107,11 @@ class SimpleSQLParser {
76
107
  const hasOrderBy = /\border\s+by\b/.test(normalizedSql);
77
108
  const hasGroupBy = /\bgroup\s+by\b/.test(normalizedSql);
78
109
  const hasHaving = /\bhaving\b/.test(normalizedSql);
110
+ // Check for LIMIT
79
111
  const limitMatch = /\blimit\s+(\d+)/.exec(normalizedSql);
80
112
  const hasLimit = !!limitMatch;
81
113
  const limitValue = limitMatch?.[1] ? parseInt(limitMatch[1], 10) : undefined;
114
+ // Estimate result set size (simplified)
82
115
  const estimatedResultSize = this.estimateResultSize(tableCount, hasWhere, hasLimit, limitValue);
83
116
  return {
84
117
  queryType,
@@ -96,6 +129,9 @@ class SimpleSQLParser {
96
129
  estimatedResultSize
97
130
  };
98
131
  }
132
+ /**
133
+ * Get query type from SQL
134
+ */
99
135
  static getQueryType(sql) {
100
136
  if (sql.startsWith('select'))
101
137
  return 'SELECT';
@@ -117,26 +153,47 @@ class SimpleSQLParser {
117
153
  return 'DESCRIBE';
118
154
  return 'UNKNOWN';
119
155
  }
156
+ /**
157
+ * Count number of tables in query
158
+ */
120
159
  static countTables(sql) {
160
+ // Count FROM clauses
121
161
  const fromMatches = sql.match(/\bfrom\s+[\w.]+/g) ?? [];
162
+ // Count JOIN clauses
122
163
  const joinMatches = sql.match(/\bjoin\s+[\w.]+/g) ?? [];
123
164
  return fromMatches.length + joinMatches.length;
124
165
  }
166
+ /**
167
+ * Count number of joins
168
+ */
125
169
  static countJoins(sql) {
126
170
  const joinMatches = sql.match(/\b(inner\s+join|left\s+join|right\s+join|full\s+join|join)\b/g) ?? [];
127
171
  return joinMatches.length;
128
172
  }
173
+ /**
174
+ * Estimate result set size
175
+ */
129
176
  static estimateResultSize(tableCount, hasWhere, hasLimit, limitValue) {
177
+ // If LIMIT is specified, use that as max
130
178
  if (hasLimit && limitValue) {
131
179
  return Math.min(limitValue, 10000);
132
180
  }
133
- let estimate = Math.pow(1000, tableCount);
181
+ // Base estimate on table count and filtering
182
+ let estimate = Math.pow(1000, tableCount); // Exponential growth with joins
183
+ // Reduce estimate if WHERE clause exists (assumes filtering)
134
184
  if (hasWhere) {
135
- estimate = Math.floor(estimate * 0.1);
185
+ estimate = Math.floor(estimate * 0.1); // Assume WHERE reduces by 90%
136
186
  }
187
+ // Cap at reasonable maximum
137
188
  return Math.min(estimate, 100000);
138
189
  }
139
190
  }
191
+ // ==============================================
192
+ // Query Complexity Analyzer
193
+ // ==============================================
194
+ /**
195
+ * Analyzes SQL queries for complexity and security risks
196
+ */
140
197
  export class QueryComplexityAnalyzer {
141
198
  config;
142
199
  riskFactors;
@@ -147,14 +204,21 @@ export class QueryComplexityAnalyzer {
147
204
  ...(config.customRiskFactors ?? [])
148
205
  ];
149
206
  }
207
+ /**
208
+ * Analyze a SQL query for complexity and security risks
209
+ */
150
210
  analyzeQuery(sql, tableMetadata = []) {
211
+ // Parse query structure
151
212
  const details = SimpleSQLParser.parseQuery(sql);
213
+ // Calculate scores
152
214
  const complexityScore = this.calculateComplexityScore(details, tableMetadata);
153
215
  const riskScore = this.calculateRiskScore(sql, details);
154
216
  const estimatedCost = this.calculateEstimatedCost(details, tableMetadata);
217
+ // Generate warnings and recommendations
155
218
  const securityWarnings = this.generateSecurityWarnings(sql, details);
156
219
  const performanceWarnings = this.generatePerformanceWarnings(details, tableMetadata);
157
220
  const recommendations = this.generateRecommendations(details, securityWarnings, performanceWarnings);
221
+ // Determine if execution should be allowed
158
222
  const allowExecution = this.shouldAllowExecution(sql, riskScore, complexityScore, estimatedCost, details);
159
223
  return {
160
224
  allowExecution,
@@ -167,8 +231,12 @@ export class QueryComplexityAnalyzer {
167
231
  details
168
232
  };
169
233
  }
234
+ /**
235
+ * Calculate query complexity score (0-100)
236
+ */
170
237
  calculateComplexityScore(details, _tableMetadata) {
171
238
  let score = 0;
239
+ // Base score by query type
172
240
  switch (details.queryType) {
173
241
  case 'SELECT':
174
242
  score += 5;
@@ -193,79 +261,107 @@ export class QueryComplexityAnalyzer {
193
261
  break;
194
262
  default: score += 10;
195
263
  }
196
- score += Math.min(details.tableCount * 10, 30);
197
- score += Math.min(details.joinCount * 15, 40);
264
+ // Table complexity
265
+ score += Math.min(details.tableCount * 10, 30); // Max 30 for tables
266
+ // Join complexity
267
+ score += Math.min(details.joinCount * 15, 40); // Max 40 for joins
268
+ // Subquery complexity
198
269
  if (details.hasSubqueries)
199
270
  score += 20;
271
+ // Aggregation complexity
200
272
  if (details.hasAggregations)
201
273
  score += 10;
274
+ // Wildcard penalty (SELECT *)
202
275
  if (details.hasWildcards)
203
276
  score += 15;
277
+ // Missing WHERE clause on multi-table queries
204
278
  if (details.tableCount > 1 && !details.hasWhere)
205
279
  score += 25;
280
+ // Large result set penalty
206
281
  if (details.estimatedResultSize > 1000)
207
282
  score += 10;
208
283
  if (details.estimatedResultSize > 10000)
209
284
  score += 20;
285
+ // No LIMIT on potentially large results
210
286
  if (!details.hasLimit && details.estimatedResultSize > 1000)
211
287
  score += 15;
212
288
  return Math.min(score, 100);
213
289
  }
290
+ /**
291
+ * Calculate security risk score (0-100)
292
+ */
214
293
  calculateRiskScore(sql, details) {
215
294
  let score = 0;
216
295
  if (!this.config.enableSecurityAnalysis) {
217
296
  return 0;
218
297
  }
298
+ // Check against risk factors
219
299
  for (const factor of this.riskFactors) {
220
300
  if (factor.pattern.test(sql)) {
221
301
  score += factor.riskScore;
222
302
  }
223
303
  }
304
+ // Additional risk factors based on query structure
224
305
  if (details.queryType !== 'SELECT' && details.queryType !== 'SHOW' && details.queryType !== 'DESCRIBE') {
225
- score += 30;
306
+ score += 30; // Non-read operations are inherently riskier
226
307
  }
308
+ // Multiple statements (potential injection)
227
309
  const statementCount = sql.split(';').filter(s => s.trim()).length;
228
310
  if (statementCount > 1) {
229
311
  score += 40;
230
312
  }
231
313
  return Math.min(score, 100);
232
314
  }
315
+ /**
316
+ * Calculate estimated execution cost
317
+ */
233
318
  calculateEstimatedCost(details, tableMetadata) {
234
- let cost = 1;
319
+ let cost = 1; // Base cost
320
+ // Cost based on estimated result size
235
321
  cost += details.estimatedResultSize * 0.1;
322
+ // Join costs (exponential)
236
323
  if (details.joinCount > 0) {
237
324
  cost *= Math.pow(10, details.joinCount);
238
325
  }
326
+ // Table scan costs
239
327
  for (let i = 0; i < details.tableCount; i++) {
240
328
  const metadata = tableMetadata[i];
241
329
  if (metadata) {
242
330
  cost += metadata.estimatedRows * 0.01;
243
331
  }
244
332
  else {
245
- cost += 10000;
333
+ cost += 10000; // Unknown table - assume large
246
334
  }
247
335
  }
336
+ // Subquery costs
248
337
  if (details.hasSubqueries) {
249
338
  cost *= 5;
250
339
  }
340
+ // Aggregation costs
251
341
  if (details.hasAggregations) {
252
342
  cost *= 2;
253
343
  }
344
+ // Sorting costs
254
345
  if (details.hasOrderBy && !details.hasLimit) {
255
346
  cost *= 3;
256
347
  }
257
348
  return Math.floor(cost);
258
349
  }
350
+ /**
351
+ * Generate security warnings
352
+ */
259
353
  generateSecurityWarnings(sql, details) {
260
354
  const warnings = [];
261
355
  if (!this.config.enableSecurityAnalysis) {
262
356
  return warnings;
263
357
  }
358
+ // Check risk factors
264
359
  for (const factor of this.riskFactors) {
265
360
  if (factor.pattern.test(sql)) {
266
361
  warnings.push(factor.description);
267
362
  }
268
363
  }
364
+ // Additional security checks
269
365
  if (details.queryType !== 'SELECT' && details.queryType !== 'SHOW' && details.queryType !== 'DESCRIBE') {
270
366
  warnings.push('Non-read operation detected - ensure proper authorization');
271
367
  }
@@ -277,36 +373,49 @@ export class QueryComplexityAnalyzer {
277
373
  }
278
374
  return warnings;
279
375
  }
376
+ /**
377
+ * Generate performance warnings
378
+ */
280
379
  generatePerformanceWarnings(details, tableMetadata) {
281
380
  const warnings = [];
282
381
  if (!this.config.enablePerformanceAnalysis) {
283
382
  return warnings;
284
383
  }
384
+ // Large result set without LIMIT
285
385
  if (details.estimatedResultSize > 1000 && !details.hasLimit) {
286
386
  warnings.push(`Large result set estimated (${details.estimatedResultSize}) without LIMIT clause`);
287
387
  }
388
+ // Multiple joins without WHERE
288
389
  if (details.joinCount > 1 && !details.hasWhere) {
289
390
  warnings.push('Multiple JOINs without WHERE clause may produce Cartesian product');
290
391
  }
392
+ // SELECT * on large tables
291
393
  if (details.hasWildcards && tableMetadata.some(t => t.estimatedRows > 10000)) {
292
394
  warnings.push('SELECT * on large table(s) - consider selecting specific columns');
293
395
  }
396
+ // ORDER BY without LIMIT on large result
294
397
  if (details.hasOrderBy && !details.hasLimit && details.estimatedResultSize > 1000) {
295
398
  warnings.push('ORDER BY without LIMIT on large result set - consider adding LIMIT');
296
399
  }
400
+ // Subqueries
297
401
  if (details.hasSubqueries) {
298
402
  warnings.push('Subqueries detected - consider using JOINs for better performance');
299
403
  }
300
404
  return warnings;
301
405
  }
406
+ /**
407
+ * Generate optimization recommendations
408
+ */
302
409
  generateRecommendations(details, securityWarnings, performanceWarnings) {
303
410
  const recommendations = [];
411
+ // Security recommendations
304
412
  if (securityWarnings.length > 0) {
305
413
  recommendations.push('Review security warnings and validate query source');
306
414
  }
307
415
  if (details.hasWildcards) {
308
416
  recommendations.push('Replace SELECT * with specific column names');
309
417
  }
418
+ // Performance recommendations
310
419
  if (!details.hasLimit && details.estimatedResultSize > 1000) {
311
420
  recommendations.push('Add LIMIT clause to prevent large result sets');
312
421
  }
@@ -324,7 +433,11 @@ export class QueryComplexityAnalyzer {
324
433
  }
325
434
  return recommendations;
326
435
  }
436
+ /**
437
+ * Determine if query execution should be allowed
438
+ */
327
439
  shouldAllowExecution(sql, riskScore, complexityScore, estimatedCost, details) {
440
+ // Check against thresholds
328
441
  if (riskScore > this.config.maxRiskScore) {
329
442
  return false;
330
443
  }
@@ -337,6 +450,7 @@ export class QueryComplexityAnalyzer {
337
450
  if (details.estimatedResultSize > this.config.maxResultSetSize) {
338
451
  return false;
339
452
  }
453
+ // Check for blocking risk factors
340
454
  for (const factor of this.riskFactors) {
341
455
  if (factor.blocking && factor.pattern.test(sql)) {
342
456
  return false;
@@ -344,19 +458,37 @@ export class QueryComplexityAnalyzer {
344
458
  }
345
459
  return true;
346
460
  }
461
+ /**
462
+ * Update configuration
463
+ */
347
464
  updateConfig(config) {
348
465
  this.config = { ...this.config, ...config };
349
466
  }
467
+ /**
468
+ * Add custom risk factor
469
+ */
350
470
  addRiskFactor(factor) {
351
471
  this.riskFactors.push(factor);
352
472
  }
473
+ /**
474
+ * Get current configuration
475
+ */
353
476
  getConfig() {
354
477
  return { ...this.config };
355
478
  }
356
479
  }
480
+ // ==============================================
481
+ // Factory Functions
482
+ // ==============================================
483
+ /**
484
+ * Create a query analyzer with default configuration
485
+ */
357
486
  export function createQueryAnalyzer(config) {
358
487
  return new QueryComplexityAnalyzer(config);
359
488
  }
489
+ /**
490
+ * Create a strict security analyzer
491
+ */
360
492
  export function createSecurityAnalyzer() {
361
493
  return new QueryComplexityAnalyzer({
362
494
  maxRiskScore: 30,
@@ -367,9 +499,12 @@ export function createSecurityAnalyzer() {
367
499
  enablePerformanceAnalysis: false
368
500
  });
369
501
  }
502
+ /**
503
+ * Create a performance-focused analyzer
504
+ */
370
505
  export function createPerformanceAnalyzer() {
371
506
  return new QueryComplexityAnalyzer({
372
- maxRiskScore: 100,
507
+ maxRiskScore: 100, // Allow all from security perspective
373
508
  maxComplexityScore: 60,
374
509
  maxEstimatedCost: 500000,
375
510
  maxResultSetSize: 5000,
@@ -377,5 +512,11 @@ export function createPerformanceAnalyzer() {
377
512
  enablePerformanceAnalysis: true
378
513
  });
379
514
  }
515
+ // ==============================================
516
+ // Default Analyzer Instance
517
+ // ==============================================
518
+ /**
519
+ * Default query analyzer instance
520
+ */
380
521
  export const defaultQueryAnalyzer = createQueryAnalyzer();
381
522
  //# sourceMappingURL=query-analyzer.js.map