@sigma4life/mysql-mcp-server 1.0.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 (149) hide show
  1. package/.env.example +35 -0
  2. package/.github/workflows/ci.yml +18 -0
  3. package/AUTHENTICATION.md +24 -0
  4. package/CLAUDE.md +37 -0
  5. package/CONTRIBUTING.md +19 -0
  6. package/LICENSE +21 -0
  7. package/QUERY_ACCESS_SETUP.md +65 -0
  8. package/README.md +144 -0
  9. package/SECURITY.md +10 -0
  10. package/TESTING.md +54 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +197 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/core/cache.d.ts +11 -0
  16. package/dist/core/cache.d.ts.map +1 -0
  17. package/dist/core/cache.js +30 -0
  18. package/dist/core/cache.js.map +1 -0
  19. package/dist/core/config.d.ts +24 -0
  20. package/dist/core/config.d.ts.map +1 -0
  21. package/dist/core/config.js +63 -0
  22. package/dist/core/config.js.map +1 -0
  23. package/dist/core/database-url.d.ts +11 -0
  24. package/dist/core/database-url.d.ts.map +1 -0
  25. package/dist/core/database-url.js +37 -0
  26. package/dist/core/database-url.js.map +1 -0
  27. package/dist/core/database-url.test.d.ts +2 -0
  28. package/dist/core/database-url.test.d.ts.map +1 -0
  29. package/dist/core/database-url.test.js +22 -0
  30. package/dist/core/database-url.test.js.map +1 -0
  31. package/dist/core/logger.d.ts +3 -0
  32. package/dist/core/logger.d.ts.map +1 -0
  33. package/dist/core/logger.js +17 -0
  34. package/dist/core/logger.js.map +1 -0
  35. package/dist/core/mcp.d.ts +14 -0
  36. package/dist/core/mcp.d.ts.map +1 -0
  37. package/dist/core/mcp.js +23 -0
  38. package/dist/core/mcp.js.map +1 -0
  39. package/dist/core/query-safety.d.ts +10 -0
  40. package/dist/core/query-safety.d.ts.map +1 -0
  41. package/dist/core/query-safety.js +50 -0
  42. package/dist/core/query-safety.js.map +1 -0
  43. package/dist/core/query-safety.test.d.ts +2 -0
  44. package/dist/core/query-safety.test.d.ts.map +1 -0
  45. package/dist/core/query-safety.test.js +30 -0
  46. package/dist/core/query-safety.test.js.map +1 -0
  47. package/dist/core/schema-types.d.ts +53 -0
  48. package/dist/core/schema-types.d.ts.map +1 -0
  49. package/dist/core/schema-types.js +2 -0
  50. package/dist/core/schema-types.js.map +1 -0
  51. package/dist/core/security/access-control.d.ts +32 -0
  52. package/dist/core/security/access-control.d.ts.map +1 -0
  53. package/dist/core/security/access-control.js +244 -0
  54. package/dist/core/security/access-control.js.map +1 -0
  55. package/dist/core/security/config-loader.d.ts +20 -0
  56. package/dist/core/security/config-loader.d.ts.map +1 -0
  57. package/dist/core/security/config-loader.js +227 -0
  58. package/dist/core/security/config-loader.js.map +1 -0
  59. package/dist/core/security/types.d.ts +64 -0
  60. package/dist/core/security/types.d.ts.map +1 -0
  61. package/dist/core/security/types.js +28 -0
  62. package/dist/core/security/types.js.map +1 -0
  63. package/dist/core/sql-parser.d.ts +23 -0
  64. package/dist/core/sql-parser.d.ts.map +1 -0
  65. package/dist/core/sql-parser.js +460 -0
  66. package/dist/core/sql-parser.js.map +1 -0
  67. package/dist/core/sql-parser.test.d.ts +2 -0
  68. package/dist/core/sql-parser.test.d.ts.map +1 -0
  69. package/dist/core/sql-parser.test.js +21 -0
  70. package/dist/core/sql-parser.test.js.map +1 -0
  71. package/dist/handlers/accessible-schema.d.ts +53 -0
  72. package/dist/handlers/accessible-schema.d.ts.map +1 -0
  73. package/dist/handlers/accessible-schema.js +192 -0
  74. package/dist/handlers/accessible-schema.js.map +1 -0
  75. package/dist/handlers/data.d.ts +17 -0
  76. package/dist/handlers/data.d.ts.map +1 -0
  77. package/dist/handlers/data.js +30 -0
  78. package/dist/handlers/data.js.map +1 -0
  79. package/dist/handlers/relationships.d.ts +14 -0
  80. package/dist/handlers/relationships.d.ts.map +1 -0
  81. package/dist/handlers/relationships.js +77 -0
  82. package/dist/handlers/relationships.js.map +1 -0
  83. package/dist/handlers/schema.d.ts +14 -0
  84. package/dist/handlers/schema.d.ts.map +1 -0
  85. package/dist/handlers/schema.js +104 -0
  86. package/dist/handlers/schema.js.map +1 -0
  87. package/dist/handlers/search.d.ts +14 -0
  88. package/dist/handlers/search.d.ts.map +1 -0
  89. package/dist/handlers/search.js +18 -0
  90. package/dist/handlers/search.js.map +1 -0
  91. package/dist/handlers/validation.d.ts +32 -0
  92. package/dist/handlers/validation.d.ts.map +1 -0
  93. package/dist/handlers/validation.js +116 -0
  94. package/dist/handlers/validation.js.map +1 -0
  95. package/dist/index.d.ts +3 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +294 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/mysql/connection.d.ts +15 -0
  100. package/dist/mysql/connection.d.ts.map +1 -0
  101. package/dist/mysql/connection.js +57 -0
  102. package/dist/mysql/connection.js.map +1 -0
  103. package/dist/mysql/identifiers.d.ts +3 -0
  104. package/dist/mysql/identifiers.d.ts.map +1 -0
  105. package/dist/mysql/identifiers.js +10 -0
  106. package/dist/mysql/identifiers.js.map +1 -0
  107. package/dist/mysql/identifiers.test.d.ts +2 -0
  108. package/dist/mysql/identifiers.test.d.ts.map +1 -0
  109. package/dist/mysql/identifiers.test.js +11 -0
  110. package/dist/mysql/identifiers.test.js.map +1 -0
  111. package/dist/mysql/queries.d.ts +49 -0
  112. package/dist/mysql/queries.d.ts.map +1 -0
  113. package/dist/mysql/queries.js +206 -0
  114. package/dist/mysql/queries.js.map +1 -0
  115. package/docs/clients/claude-code.md +28 -0
  116. package/docs/clients/claude-desktop.md +35 -0
  117. package/docs/clients/codex.md +28 -0
  118. package/docs/clients/cursor.md +26 -0
  119. package/docs/clients/opencode.md +35 -0
  120. package/docs/clients/vscode.md +25 -0
  121. package/package.json +49 -0
  122. package/query-access.example.json +21 -0
  123. package/src/cli.ts +221 -0
  124. package/src/core/cache.ts +41 -0
  125. package/src/core/config.ts +97 -0
  126. package/src/core/database-url.test.ts +28 -0
  127. package/src/core/database-url.ts +47 -0
  128. package/src/core/logger.ts +24 -0
  129. package/src/core/mcp.ts +23 -0
  130. package/src/core/query-safety.test.ts +36 -0
  131. package/src/core/query-safety.ts +63 -0
  132. package/src/core/schema-types.ts +58 -0
  133. package/src/core/security/access-control.ts +321 -0
  134. package/src/core/security/config-loader.ts +315 -0
  135. package/src/core/security/types.ts +114 -0
  136. package/src/core/sql-parser.test.ts +37 -0
  137. package/src/core/sql-parser.ts +572 -0
  138. package/src/handlers/accessible-schema.ts +314 -0
  139. package/src/handlers/data.ts +66 -0
  140. package/src/handlers/relationships.ts +114 -0
  141. package/src/handlers/schema.ts +154 -0
  142. package/src/handlers/search.ts +34 -0
  143. package/src/handlers/validation.ts +165 -0
  144. package/src/index.ts +337 -0
  145. package/src/mysql/connection.ts +68 -0
  146. package/src/mysql/identifiers.test.ts +12 -0
  147. package/src/mysql/identifiers.ts +10 -0
  148. package/src/mysql/queries.ts +285 -0
  149. package/tsconfig.json +24 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Access Control Validation for execute_query
3
+ *
4
+ * Validates SQL queries against access control configuration:
5
+ * - Database access (must be configured)
6
+ * - Table whitelist/blacklist
7
+ * - Column access (inclusion/exclusion modes)
8
+ * - SELECT * blocking
9
+ */
10
+ import { AccessControlError, } from "./types.js";
11
+ import { getTableConfigForSchema } from "./config-loader.js";
12
+ import { parseQuery } from "../sql-parser.js";
13
+ import { logger } from "../logger.js";
14
+ /**
15
+ * Validate a query against access control configuration
16
+ * @throws AccessControlError if validation fails
17
+ */
18
+ export function validateQueryAccess(query, database, config) {
19
+ const violations = [];
20
+ // Step 1: Check if database is configured
21
+ const dbViolation = validateDatabaseAccess(database, config);
22
+ if (dbViolation) {
23
+ throw new AccessControlError([dbViolation]);
24
+ }
25
+ // Step 2: Parse the query
26
+ const parsed = parseQuery(query, database);
27
+ logger.debug(`Parsed query info: tables=${parsed.tables.length}, columns=${parsed.columns.length}, hasSelectStar=${parsed.hasSelectStar}`);
28
+ // Step 3: Validate SELECT * usage
29
+ if (config.requireExplicitColumns && parsed.hasSelectStar) {
30
+ violations.push(...validateSelectStar(parsed.selectStarTables));
31
+ }
32
+ // Step 4: Validate table access
33
+ for (const table of parsed.tables) {
34
+ const tableViolation = validateTableAccess(table, config);
35
+ if (tableViolation) {
36
+ violations.push(tableViolation);
37
+ }
38
+ }
39
+ // Step 5: Validate column access (only if no SELECT *)
40
+ // If SELECT * is used, we can't know which columns will be returned
41
+ // so we already blocked it above
42
+ if (!parsed.hasSelectStar) {
43
+ for (const column of parsed.columns) {
44
+ const columnViolation = validateColumnAccess(column, config);
45
+ if (columnViolation) {
46
+ violations.push(columnViolation);
47
+ }
48
+ }
49
+ }
50
+ // Throw if any violations found
51
+ if (violations.length > 0) {
52
+ logger.warn(`Access control violations: ${violations.map((v) => v.message).join("; ")}`);
53
+ throw new AccessControlError(violations);
54
+ }
55
+ logger.debug("Query passed access control validation");
56
+ }
57
+ /**
58
+ * Validate database is configured
59
+ */
60
+ function validateDatabaseAccess(database, config) {
61
+ const dbUpper = database.toUpperCase();
62
+ if (!config.databases[dbUpper]) {
63
+ return {
64
+ type: "database_not_configured",
65
+ database,
66
+ message: `Database '${database}' is not configured for query access. ` +
67
+ `Add it to QUERY_ACCESS_CONFIG to enable queries.`,
68
+ };
69
+ }
70
+ return null;
71
+ }
72
+ /**
73
+ * Validate SELECT * usage
74
+ */
75
+ function validateSelectStar(selectStarTables) {
76
+ const violations = [];
77
+ for (const tableRef of selectStarTables) {
78
+ if (tableRef === "*") {
79
+ violations.push({
80
+ type: "select_star",
81
+ message: "SELECT * is not allowed. All SELECT statements must explicitly list columns. " +
82
+ "Example: SELECT name, email FROM customers",
83
+ });
84
+ }
85
+ else {
86
+ violations.push({
87
+ type: "select_star",
88
+ table: tableRef,
89
+ message: `SELECT ${tableRef}.* is not allowed. ` +
90
+ `Please specify columns explicitly instead of using table.* syntax.`,
91
+ });
92
+ }
93
+ }
94
+ return violations;
95
+ }
96
+ /**
97
+ * Validate table access against whitelist/blacklist
98
+ */
99
+ function validateTableAccess(table, config) {
100
+ // Skip subquery pseudo-tables
101
+ if (table.schema === "__subquery__") {
102
+ return null;
103
+ }
104
+ // Skip CTE references (they're query-scoped aliases, not real tables)
105
+ if (table.schema === "__cte__") {
106
+ return null;
107
+ }
108
+ const schemaConfig = getTableConfigForSchema(config, table.database, table.schema);
109
+ if (!schemaConfig) {
110
+ return {
111
+ type: "schema_not_configured",
112
+ database: table.database,
113
+ schema: table.schema,
114
+ table: table.table,
115
+ message: `Schema '${table.schema}' in database '${table.database}' is not configured for query access. ` +
116
+ `Add schema rules to QUERY_ACCESS_CONFIG.`,
117
+ };
118
+ }
119
+ const { tableConfig } = schemaConfig;
120
+ const tableNameLower = table.table.toLowerCase();
121
+ // Check whitelist/blacklist
122
+ const listLower = tableConfig.list.map((t) => t.toLowerCase());
123
+ switch (tableConfig.mode) {
124
+ case "whitelist":
125
+ if (!listLower.includes(tableNameLower)) {
126
+ return {
127
+ type: "table_not_allowed",
128
+ database: table.database,
129
+ schema: table.schema,
130
+ table: table.table,
131
+ message: `Table '${table.database}.${table.schema}.${table.table}' is not in the allowed tables list. ` +
132
+ `Allowed tables for ${table.database}.${table.schema}: ${tableConfig.list.join(", ") || "(none)"}`,
133
+ };
134
+ }
135
+ break;
136
+ case "blacklist":
137
+ if (listLower.includes(tableNameLower)) {
138
+ return {
139
+ type: "table_not_allowed",
140
+ database: table.database,
141
+ schema: table.schema,
142
+ table: table.table,
143
+ message: `Table '${table.database}.${table.schema}.${table.table}' cannot be queried. ` +
144
+ `This table is in the exclusion list for database '${table.database}', schema '${table.schema}'.`,
145
+ };
146
+ }
147
+ break;
148
+ case "none":
149
+ // No table-level restrictions
150
+ break;
151
+ }
152
+ return null;
153
+ }
154
+ /**
155
+ * Validate column access against inclusion/exclusion rules
156
+ */
157
+ function validateColumnAccess(column, config) {
158
+ // Skip unknown table columns (can't validate)
159
+ if (column.table === "__unknown__") {
160
+ return null;
161
+ }
162
+ const schemaConfig = getTableConfigForSchema(config, column.database, column.schema);
163
+ if (!schemaConfig) {
164
+ // Schema not configured - already caught in table validation
165
+ return null;
166
+ }
167
+ const { columnAccess } = schemaConfig;
168
+ const tableNameLower = column.table.toLowerCase();
169
+ const columnNameLower = column.column.toLowerCase();
170
+ // Find policy for this table (case-insensitive)
171
+ let policy = null;
172
+ let policyTableName = "";
173
+ for (const [table, tablePolicy] of Object.entries(columnAccess)) {
174
+ if (table.toLowerCase() === tableNameLower) {
175
+ policy = tablePolicy;
176
+ policyTableName = table;
177
+ break;
178
+ }
179
+ }
180
+ // No policy = allow all columns
181
+ if (!policy) {
182
+ return null;
183
+ }
184
+ const columnsLower = policy.columns.map((c) => c.toLowerCase());
185
+ if (policy.mode === "inclusion") {
186
+ // Whitelist: column must be in the list
187
+ if (!columnsLower.includes(columnNameLower)) {
188
+ return {
189
+ type: "column_not_allowed",
190
+ database: column.database,
191
+ schema: column.schema,
192
+ table: column.table,
193
+ column: column.column,
194
+ message: `Column '${column.column}' from '${column.database}.${column.schema}.${column.table}' cannot be selected. ` +
195
+ `Allowed columns for ${policyTableName}: ${policy.columns.join(", ")}`,
196
+ };
197
+ }
198
+ }
199
+ else {
200
+ // Blacklist: column must NOT be in the list
201
+ if (columnsLower.includes(columnNameLower)) {
202
+ return {
203
+ type: "column_excluded",
204
+ database: column.database,
205
+ schema: column.schema,
206
+ table: column.table,
207
+ column: column.column,
208
+ message: `Column '${column.column}' from '${column.database}.${column.schema}.${column.table}' cannot be selected. ` +
209
+ `Excluded columns: ${policy.columns.join(", ")}`,
210
+ };
211
+ }
212
+ }
213
+ return null;
214
+ }
215
+ // Singleton config holder
216
+ let globalConfig = null;
217
+ /**
218
+ * Initialize the global access control config
219
+ * Called once at startup from index.ts
220
+ */
221
+ export function initAccessControl(config) {
222
+ globalConfig = config;
223
+ logger.info("Access control initialized");
224
+ }
225
+ /**
226
+ * Get the global access control config
227
+ * @throws Error if not initialized
228
+ */
229
+ export function getAccessControlConfig() {
230
+ if (!globalConfig) {
231
+ throw new Error("Access control not initialized. Ensure QUERY_ACCESS_CONFIG is set and valid.");
232
+ }
233
+ return globalConfig;
234
+ }
235
+ /**
236
+ * Check if access control is initialized
237
+ */
238
+ export function isAccessControlInitialized() {
239
+ return globalConfig !== null;
240
+ }
241
+ // Re-export types for convenience
242
+ export { AccessControlError } from "./types.js";
243
+ export { loadAccessControlConfig, getTableConfigForSchema, } from "./config-loader.js";
244
+ //# sourceMappingURL=access-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-control.js","sourceRoot":"","sources":["../../../src/core/security/access-control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Access Control Configuration Loader
3
+ *
4
+ * Loads configuration from JSON file specified by QUERY_ACCESS_CONFIG env var.
5
+ * Validates configuration structure and provides helpful error messages.
6
+ */
7
+ import { AccessControlConfig, TableConfig, ColumnAccessPolicy } from './types.js';
8
+ /**
9
+ * Load and validate access control configuration
10
+ * @throws Error if config is invalid or missing (restrictive default)
11
+ */
12
+ export declare function loadAccessControlConfig(): AccessControlConfig;
13
+ /**
14
+ * Get the effective table config for a database/schema combination
15
+ */
16
+ export declare function getTableConfigForSchema(config: AccessControlConfig, database: string, schema: string): {
17
+ tableConfig: TableConfig;
18
+ columnAccess: Record<string, ColumnAccessPolicy>;
19
+ } | null;
20
+ //# sourceMappingURL=config-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../../src/core/security/config-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,mBAAmB,EAEnB,WAAW,EAEX,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAMpB;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,mBAAmB,CAuC7D;AA0MD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CAAE,GAAG,IAAI,CAyCvF"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Access Control Configuration Loader
3
+ *
4
+ * Loads configuration from JSON file specified by QUERY_ACCESS_CONFIG env var.
5
+ * Validates configuration structure and provides helpful error messages.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { logger } from '../logger.js';
10
+ // Environment variable for config file path
11
+ const CONFIG_ENV_VAR = 'QUERY_ACCESS_CONFIG';
12
+ /**
13
+ * Load and validate access control configuration
14
+ * @throws Error if config is invalid or missing (restrictive default)
15
+ */
16
+ export function loadAccessControlConfig() {
17
+ const configPath = process.env[CONFIG_ENV_VAR];
18
+ if (!configPath) {
19
+ throw new Error(`Access control configuration not found. ` +
20
+ `Set ${CONFIG_ENV_VAR} environment variable to the path of your config file. ` +
21
+ `Example: ${CONFIG_ENV_VAR}=/path/to/query-access.json`);
22
+ }
23
+ // Resolve path (handle relative paths)
24
+ const resolvedPath = path.resolve(configPath);
25
+ if (!fs.existsSync(resolvedPath)) {
26
+ throw new Error(`Access control config file not found at: ${resolvedPath}. ` +
27
+ `Create the config file or update ${CONFIG_ENV_VAR} to point to the correct location.`);
28
+ }
29
+ logger.info(`Loading access control config from: ${resolvedPath}`);
30
+ let rawConfig;
31
+ try {
32
+ const content = fs.readFileSync(resolvedPath, 'utf-8');
33
+ rawConfig = JSON.parse(content);
34
+ }
35
+ catch (error) {
36
+ throw new Error(`Failed to parse access control config: ${error.message}`);
37
+ }
38
+ // Validate and normalize the configuration
39
+ const config = validateConfig(rawConfig);
40
+ logger.info(`Access control config loaded: ${Object.keys(config.databases).length} database(s) configured`);
41
+ return config;
42
+ }
43
+ /**
44
+ * Validate configuration structure
45
+ */
46
+ function validateConfig(raw) {
47
+ if (typeof raw !== 'object' || raw === null) {
48
+ throw new Error('Access control config must be a JSON object');
49
+ }
50
+ // Validate requireExplicitColumns
51
+ if (typeof raw.requireExplicitColumns !== 'boolean') {
52
+ throw new Error("Access control config must have 'requireExplicitColumns' (boolean)");
53
+ }
54
+ // Validate databases
55
+ if (typeof raw.databases !== 'object' || raw.databases === null) {
56
+ throw new Error("Access control config must have 'databases' object");
57
+ }
58
+ const databases = {};
59
+ for (const [dbName, dbConfig] of Object.entries(raw.databases)) {
60
+ databases[dbName.toUpperCase()] = validateDatabaseConfig(dbName, dbConfig);
61
+ }
62
+ return {
63
+ requireExplicitColumns: raw.requireExplicitColumns,
64
+ databases,
65
+ };
66
+ }
67
+ /**
68
+ * Validate database configuration
69
+ */
70
+ function validateDatabaseConfig(dbName, raw) {
71
+ if (typeof raw !== 'object' || raw === null) {
72
+ throw new Error(`Database config for '${dbName}' must be an object`);
73
+ }
74
+ // Error on deprecated columnExclusions format
75
+ if (raw.columnExclusions) {
76
+ throw new Error(`Database '${dbName}' uses deprecated 'columnExclusions' format. ` +
77
+ `Please migrate to 'columnAccess' with { mode: 'exclusion' | 'inclusion', columns: [...] } per table. ` +
78
+ `See documentation for the new format.`);
79
+ }
80
+ const result = {};
81
+ // Check for schema-level config (full format)
82
+ if (raw.schemas) {
83
+ if (typeof raw.schemas !== 'object') {
84
+ throw new Error(`'schemas' in database '${dbName}' must be an object`);
85
+ }
86
+ result.schemas = {};
87
+ for (const [schemaName, schemaConfig] of Object.entries(raw.schemas)) {
88
+ result.schemas[schemaName.toLowerCase()] = validateSchemaConfig(dbName, schemaName, schemaConfig);
89
+ }
90
+ }
91
+ // Check for compact format (tables at database level)
92
+ if (raw.tables) {
93
+ result.tables = validateTableConfig(dbName, '_default_', raw.tables);
94
+ }
95
+ // Must have either schemas or tables
96
+ if (!result.schemas && !result.tables) {
97
+ throw new Error(`Database '${dbName}' must have either 'schemas' or 'tables' configuration`);
98
+ }
99
+ return result;
100
+ }
101
+ /**
102
+ * Validate schema configuration
103
+ */
104
+ function validateSchemaConfig(dbName, schemaName, raw) {
105
+ if (typeof raw !== 'object' || raw === null) {
106
+ throw new Error(`Schema config for '${dbName}.${schemaName}' must be an object`);
107
+ }
108
+ if (!raw.tables) {
109
+ throw new Error(`Schema '${dbName}.${schemaName}' must have 'tables' configuration`);
110
+ }
111
+ return {
112
+ tables: validateTableConfig(dbName, schemaName, raw.tables),
113
+ };
114
+ }
115
+ /**
116
+ * Validate table configuration
117
+ */
118
+ function validateTableConfig(dbName, schemaName, raw) {
119
+ if (typeof raw !== 'object' || raw === null) {
120
+ throw new Error(`Table config for '${dbName}.${schemaName}' must be an object`);
121
+ }
122
+ // Error on deprecated columnExclusions format
123
+ if (raw.columnExclusions) {
124
+ throw new Error(`Table config for '${dbName}.${schemaName}' uses deprecated 'columnExclusions' format. ` +
125
+ `Please migrate to 'columnAccess' with { mode: 'exclusion' | 'inclusion', columns: [...] } per table. ` +
126
+ `See documentation for the new format.`);
127
+ }
128
+ // Validate mode
129
+ const validModes = ['whitelist', 'blacklist', 'none'];
130
+ if (!validModes.includes(raw.mode)) {
131
+ throw new Error(`Table mode for '${dbName}.${schemaName}' must be one of: ${validModes.join(', ')}`);
132
+ }
133
+ // Validate list
134
+ if (!Array.isArray(raw.list)) {
135
+ throw new Error(`Table list for '${dbName}.${schemaName}' must be an array`);
136
+ }
137
+ const list = raw.list.map((t) => {
138
+ if (typeof t !== 'string') {
139
+ throw new Error(`Table list for '${dbName}.${schemaName}' must contain only strings`);
140
+ }
141
+ return t; // Keep original case for display, but compare case-insensitively
142
+ });
143
+ const result = {
144
+ mode: raw.mode,
145
+ list,
146
+ };
147
+ // Optional column access policies
148
+ if (raw.columnAccess) {
149
+ result.columnAccess = validateColumnAccess(`${dbName}.${schemaName}`, raw.columnAccess);
150
+ }
151
+ return result;
152
+ }
153
+ /**
154
+ * Validate column access policies
155
+ */
156
+ function validateColumnAccess(context, raw) {
157
+ if (typeof raw !== 'object' || raw === null) {
158
+ throw new Error(`Column access for '${context}' must be an object`);
159
+ }
160
+ const result = {};
161
+ for (const [tableName, policy] of Object.entries(raw)) {
162
+ if (typeof policy !== 'object' || policy === null) {
163
+ throw new Error(`Column access for '${context}.${tableName}' must be an object with 'mode' and 'columns'`);
164
+ }
165
+ const p = policy;
166
+ // Validate mode
167
+ const validModes = ['inclusion', 'exclusion'];
168
+ if (!validModes.includes(p.mode)) {
169
+ throw new Error(`Column access mode for '${context}.${tableName}' must be 'inclusion' or 'exclusion'`);
170
+ }
171
+ // Validate columns
172
+ if (!Array.isArray(p.columns)) {
173
+ throw new Error(`Column access for '${context}.${tableName}' must have 'columns' array`);
174
+ }
175
+ const columns = p.columns.map((c) => {
176
+ if (typeof c !== 'string') {
177
+ throw new Error(`Column access for '${context}.${tableName}' columns must contain only strings`);
178
+ }
179
+ return c;
180
+ });
181
+ result[tableName] = {
182
+ mode: p.mode,
183
+ columns,
184
+ };
185
+ }
186
+ return result;
187
+ }
188
+ /**
189
+ * Get the effective table config for a database/schema combination
190
+ */
191
+ export function getTableConfigForSchema(config, database, schema) {
192
+ const dbConfig = config.databases[database.toUpperCase()];
193
+ if (!dbConfig) {
194
+ return null;
195
+ }
196
+ const schemaLower = schema.toLowerCase();
197
+ // Check schema-level config first
198
+ if (dbConfig.schemas) {
199
+ // Try exact match
200
+ if (dbConfig.schemas[schemaLower]) {
201
+ const schemaConfig = dbConfig.schemas[schemaLower];
202
+ return {
203
+ tableConfig: schemaConfig.tables,
204
+ columnAccess: schemaConfig.tables.columnAccess || {},
205
+ };
206
+ }
207
+ // Try wildcard
208
+ if (dbConfig.schemas['*']) {
209
+ const schemaConfig = dbConfig.schemas['*'];
210
+ return {
211
+ tableConfig: schemaConfig.tables,
212
+ columnAccess: schemaConfig.tables.columnAccess || {},
213
+ };
214
+ }
215
+ // No matching schema config
216
+ return null;
217
+ }
218
+ // Use compact format (database-level tables config)
219
+ if (dbConfig.tables) {
220
+ return {
221
+ tableConfig: dbConfig.tables,
222
+ columnAccess: dbConfig.tables.columnAccess || {},
223
+ };
224
+ }
225
+ return null;
226
+ }
227
+ //# sourceMappingURL=config-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../src/core/security/config-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Access Control Types for execute_query
3
+ *
4
+ * Hierarchical configuration structure:
5
+ * database → schema → table → column
6
+ */
7
+ export interface ColumnAccessPolicy {
8
+ mode: 'inclusion' | 'exclusion';
9
+ columns: string[];
10
+ }
11
+ export interface TableConfig {
12
+ mode: 'whitelist' | 'blacklist' | 'none';
13
+ list: string[];
14
+ columnAccess?: Record<string, ColumnAccessPolicy>;
15
+ }
16
+ export interface SchemaConfig {
17
+ tables: TableConfig;
18
+ }
19
+ export interface DatabaseConfig {
20
+ schemas?: Record<string, SchemaConfig>;
21
+ tables?: TableConfig;
22
+ }
23
+ export interface AccessControlConfig {
24
+ requireExplicitColumns: boolean;
25
+ databases: Record<string, DatabaseConfig>;
26
+ }
27
+ export type ViolationType = 'select_star' | 'table_not_allowed' | 'column_excluded' | 'column_not_allowed' | 'database_not_configured' | 'schema_not_configured';
28
+ export interface AccessViolation {
29
+ type: ViolationType;
30
+ message: string;
31
+ database?: string;
32
+ schema?: string;
33
+ table?: string;
34
+ column?: string;
35
+ }
36
+ export interface AccessValidationResult {
37
+ allowed: boolean;
38
+ violations: AccessViolation[];
39
+ }
40
+ export interface QualifiedTableRef {
41
+ database: string;
42
+ schema: string;
43
+ table: string;
44
+ alias?: string;
45
+ }
46
+ export interface QualifiedColumnRef {
47
+ database: string;
48
+ schema: string;
49
+ table: string;
50
+ column: string;
51
+ }
52
+ export interface ParsedQueryInfo {
53
+ tables: QualifiedTableRef[];
54
+ columns: QualifiedColumnRef[];
55
+ hasSelectStar: boolean;
56
+ selectStarTables: string[];
57
+ aliases: Map<string, QualifiedTableRef>;
58
+ }
59
+ export declare class AccessControlError extends Error {
60
+ readonly violations: AccessViolation[];
61
+ constructor(violations: AccessViolation[]);
62
+ }
63
+ export declare function formatAccessViolations(violations: AccessViolation[]): string;
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/security/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAGD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;IACzC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CACnD;AAGD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;CACrB;AAGD,MAAM,WAAW,cAAc;IAE7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAGD,MAAM,WAAW,mBAAmB;IAClC,sBAAsB,EAAE,OAAO,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC3C;AAGD,MAAM,MAAM,aAAa,GACrB,aAAa,GACb,mBAAmB,GACnB,iBAAiB,GACjB,oBAAoB,GACpB,yBAAyB,GACzB,uBAAuB,CAAC;AAG5B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAGD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CACzC;AAGD,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAgB,UAAU,EAAE,eAAe,EAAE,CAAC;gBAElC,UAAU,EAAE,eAAe,EAAE;CAM1C;AAGD,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,CAW5E"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Access Control Types for execute_query
3
+ *
4
+ * Hierarchical configuration structure:
5
+ * database → schema → table → column
6
+ */
7
+ // Custom error class for access control violations
8
+ export class AccessControlError extends Error {
9
+ violations;
10
+ constructor(violations) {
11
+ const message = formatAccessViolations(violations);
12
+ super(message);
13
+ this.name = 'AccessControlError';
14
+ this.violations = violations;
15
+ }
16
+ }
17
+ // Format violations into user-friendly error messages
18
+ export function formatAccessViolations(violations) {
19
+ if (violations.length === 0) {
20
+ return 'No access violations';
21
+ }
22
+ if (violations.length === 1) {
23
+ return violations[0].message;
24
+ }
25
+ const lines = violations.map((v, i) => ` ${i + 1}. ${v.message}`);
26
+ return `Multiple access control violations:\n${lines.join('\n')}`;
27
+ }
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/security/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoFH,mDAAmD;AACnD,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3B,UAAU,CAAoB;IAE9C,YAAY,UAA6B;QACvC,MAAM,OAAO,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;QACnD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,sDAAsD;AACtD,MAAM,UAAU,sBAAsB,CAAC,UAA6B;IAClE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,sBAAsB,CAAC;IAChC,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/B,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,OAAO,wCAAwC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACpE,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * SQL Parser Utility for Access Control
3
+ *
4
+ * Uses node-sql-parser to parse SQL and extract:
5
+ * - Tables (including JOINs, subqueries, CTEs)
6
+ * - Columns being selected
7
+ * - SELECT * detection
8
+ * - Alias resolution
9
+ */
10
+ import { ParsedQueryInfo } from "./security/types.js";
11
+ /**
12
+ * Parse a SQL query and extract tables, columns, and SELECT * usage
13
+ */
14
+ export declare function parseQuery(sql: string, database: string): ParsedQueryInfo;
15
+ /**
16
+ * Check if a query contains SELECT * or table.*
17
+ */
18
+ export declare function hasSelectStar(sql: string): boolean;
19
+ /**
20
+ * Extract table names from a simple SQL query (utility function)
21
+ */
22
+ export declare function extractTableNames(sql: string): string[];
23
+ //# sourceMappingURL=sql-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-parser.d.ts","sourceRoot":"","sources":["../../src/core/sql-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACL,eAAe,EAGhB,MAAM,qBAAqB,CAAC;AAM7B;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CA4BzE;AAqeD;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBvD"}