@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.
- package/.env.example +35 -0
- package/.github/workflows/ci.yml +18 -0
- package/AUTHENTICATION.md +24 -0
- package/CLAUDE.md +37 -0
- package/CONTRIBUTING.md +19 -0
- package/LICENSE +21 -0
- package/QUERY_ACCESS_SETUP.md +65 -0
- package/README.md +144 -0
- package/SECURITY.md +10 -0
- package/TESTING.md +54 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +197 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/cache.d.ts +11 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +30 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/config.d.ts +24 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +63 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/database-url.d.ts +11 -0
- package/dist/core/database-url.d.ts.map +1 -0
- package/dist/core/database-url.js +37 -0
- package/dist/core/database-url.js.map +1 -0
- package/dist/core/database-url.test.d.ts +2 -0
- package/dist/core/database-url.test.d.ts.map +1 -0
- package/dist/core/database-url.test.js +22 -0
- package/dist/core/database-url.test.js.map +1 -0
- package/dist/core/logger.d.ts +3 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +17 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp.d.ts +14 -0
- package/dist/core/mcp.d.ts.map +1 -0
- package/dist/core/mcp.js +23 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/query-safety.d.ts +10 -0
- package/dist/core/query-safety.d.ts.map +1 -0
- package/dist/core/query-safety.js +50 -0
- package/dist/core/query-safety.js.map +1 -0
- package/dist/core/query-safety.test.d.ts +2 -0
- package/dist/core/query-safety.test.d.ts.map +1 -0
- package/dist/core/query-safety.test.js +30 -0
- package/dist/core/query-safety.test.js.map +1 -0
- package/dist/core/schema-types.d.ts +53 -0
- package/dist/core/schema-types.d.ts.map +1 -0
- package/dist/core/schema-types.js +2 -0
- package/dist/core/schema-types.js.map +1 -0
- package/dist/core/security/access-control.d.ts +32 -0
- package/dist/core/security/access-control.d.ts.map +1 -0
- package/dist/core/security/access-control.js +244 -0
- package/dist/core/security/access-control.js.map +1 -0
- package/dist/core/security/config-loader.d.ts +20 -0
- package/dist/core/security/config-loader.d.ts.map +1 -0
- package/dist/core/security/config-loader.js +227 -0
- package/dist/core/security/config-loader.js.map +1 -0
- package/dist/core/security/types.d.ts +64 -0
- package/dist/core/security/types.d.ts.map +1 -0
- package/dist/core/security/types.js +28 -0
- package/dist/core/security/types.js.map +1 -0
- package/dist/core/sql-parser.d.ts +23 -0
- package/dist/core/sql-parser.d.ts.map +1 -0
- package/dist/core/sql-parser.js +460 -0
- package/dist/core/sql-parser.js.map +1 -0
- package/dist/core/sql-parser.test.d.ts +2 -0
- package/dist/core/sql-parser.test.d.ts.map +1 -0
- package/dist/core/sql-parser.test.js +21 -0
- package/dist/core/sql-parser.test.js.map +1 -0
- package/dist/handlers/accessible-schema.d.ts +53 -0
- package/dist/handlers/accessible-schema.d.ts.map +1 -0
- package/dist/handlers/accessible-schema.js +192 -0
- package/dist/handlers/accessible-schema.js.map +1 -0
- package/dist/handlers/data.d.ts +17 -0
- package/dist/handlers/data.d.ts.map +1 -0
- package/dist/handlers/data.js +30 -0
- package/dist/handlers/data.js.map +1 -0
- package/dist/handlers/relationships.d.ts +14 -0
- package/dist/handlers/relationships.d.ts.map +1 -0
- package/dist/handlers/relationships.js +77 -0
- package/dist/handlers/relationships.js.map +1 -0
- package/dist/handlers/schema.d.ts +14 -0
- package/dist/handlers/schema.d.ts.map +1 -0
- package/dist/handlers/schema.js +104 -0
- package/dist/handlers/schema.js.map +1 -0
- package/dist/handlers/search.d.ts +14 -0
- package/dist/handlers/search.d.ts.map +1 -0
- package/dist/handlers/search.js +18 -0
- package/dist/handlers/search.js.map +1 -0
- package/dist/handlers/validation.d.ts +32 -0
- package/dist/handlers/validation.d.ts.map +1 -0
- package/dist/handlers/validation.js +116 -0
- package/dist/handlers/validation.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +294 -0
- package/dist/index.js.map +1 -0
- package/dist/mysql/connection.d.ts +15 -0
- package/dist/mysql/connection.d.ts.map +1 -0
- package/dist/mysql/connection.js +57 -0
- package/dist/mysql/connection.js.map +1 -0
- package/dist/mysql/identifiers.d.ts +3 -0
- package/dist/mysql/identifiers.d.ts.map +1 -0
- package/dist/mysql/identifiers.js +10 -0
- package/dist/mysql/identifiers.js.map +1 -0
- package/dist/mysql/identifiers.test.d.ts +2 -0
- package/dist/mysql/identifiers.test.d.ts.map +1 -0
- package/dist/mysql/identifiers.test.js +11 -0
- package/dist/mysql/identifiers.test.js.map +1 -0
- package/dist/mysql/queries.d.ts +49 -0
- package/dist/mysql/queries.d.ts.map +1 -0
- package/dist/mysql/queries.js +206 -0
- package/dist/mysql/queries.js.map +1 -0
- package/docs/clients/claude-code.md +28 -0
- package/docs/clients/claude-desktop.md +35 -0
- package/docs/clients/codex.md +28 -0
- package/docs/clients/cursor.md +26 -0
- package/docs/clients/opencode.md +35 -0
- package/docs/clients/vscode.md +25 -0
- package/package.json +49 -0
- package/query-access.example.json +21 -0
- package/src/cli.ts +221 -0
- package/src/core/cache.ts +41 -0
- package/src/core/config.ts +97 -0
- package/src/core/database-url.test.ts +28 -0
- package/src/core/database-url.ts +47 -0
- package/src/core/logger.ts +24 -0
- package/src/core/mcp.ts +23 -0
- package/src/core/query-safety.test.ts +36 -0
- package/src/core/query-safety.ts +63 -0
- package/src/core/schema-types.ts +58 -0
- package/src/core/security/access-control.ts +321 -0
- package/src/core/security/config-loader.ts +315 -0
- package/src/core/security/types.ts +114 -0
- package/src/core/sql-parser.test.ts +37 -0
- package/src/core/sql-parser.ts +572 -0
- package/src/handlers/accessible-schema.ts +314 -0
- package/src/handlers/data.ts +66 -0
- package/src/handlers/relationships.ts +114 -0
- package/src/handlers/schema.ts +154 -0
- package/src/handlers/search.ts +34 -0
- package/src/handlers/validation.ts +165 -0
- package/src/index.ts +337 -0
- package/src/mysql/connection.ts +68 -0
- package/src/mysql/identifiers.test.ts +12 -0
- package/src/mysql/identifiers.ts +10 -0
- package/src/mysql/queries.ts +285 -0
- 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"}
|