@vfarcic/dot-ai 1.7.0 → 1.8.1
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/dist/core/ai-provider-factory.d.ts.map +1 -1
- package/dist/core/ai-provider-factory.js +1 -2
- package/dist/core/embedding-service.d.ts.map +1 -1
- package/dist/core/model-config.d.ts +3 -4
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +4 -5
- package/dist/core/providers/vercel-provider.d.ts.map +1 -1
- package/dist/core/providers/vercel-provider.js +6 -5
- package/dist/core/rbac/audit-logger.d.ts +23 -0
- package/dist/core/rbac/audit-logger.d.ts.map +1 -0
- package/dist/core/rbac/audit-logger.js +63 -0
- package/dist/core/rbac/check-access.d.ts +48 -0
- package/dist/core/rbac/check-access.d.ts.map +1 -0
- package/dist/core/rbac/check-access.js +156 -0
- package/dist/core/rbac/index.d.ts +3 -0
- package/dist/core/rbac/index.d.ts.map +1 -0
- package/dist/core/rbac/index.js +11 -0
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +14 -1
- package/dist/interfaces/mcp.d.ts.map +1 -1
- package/dist/interfaces/mcp.js +129 -44
- package/dist/interfaces/rest-api.d.ts.map +1 -1
- package/dist/interfaces/rest-api.js +53 -1
- package/dist/tools/generate-manifests.d.ts.map +1 -1
- package/dist/tools/generate-manifests.js +22 -2
- package/dist/tools/manage-knowledge.d.ts.map +1 -1
- package/dist/tools/manage-knowledge.js +20 -0
- package/dist/tools/operate.d.ts.map +1 -1
- package/dist/tools/operate.js +37 -0
- package/dist/tools/organizational-data.d.ts.map +1 -1
- package/dist/tools/organizational-data.js +27 -0
- package/dist/tools/recommend.d.ts.map +1 -1
- package/dist/tools/recommend.js +24 -0
- package/dist/tools/remediate.d.ts.map +1 -1
- package/dist/tools/remediate.js +67 -18
- package/package.json +12 -9
- package/shared-prompts/prd-update-decisions.md +7 -0
package/dist/interfaces/mcp.js
CHANGED
|
@@ -29,6 +29,7 @@ const rest_registry_1 = require("./rest-registry");
|
|
|
29
29
|
const rest_api_1 = require("./rest-api");
|
|
30
30
|
const oauth_1 = require("./oauth");
|
|
31
31
|
const request_context_1 = require("./request-context");
|
|
32
|
+
const rbac_1 = require("../core/rbac");
|
|
32
33
|
const express_1 = __importDefault(require("express"));
|
|
33
34
|
const router_js_1 = require("@modelcontextprotocol/sdk/server/auth/router.js");
|
|
34
35
|
const error_response_1 = require("./error-response");
|
|
@@ -92,7 +93,9 @@ class MCPServer {
|
|
|
92
93
|
*/
|
|
93
94
|
registerRestTool(name, description, inputSchema, handler, category, tags) {
|
|
94
95
|
const restTracedHandler = async (args) => {
|
|
95
|
-
return await (0, tracing_1.withToolTracing)(name, args, handler, {
|
|
96
|
+
return await (0, tracing_1.withToolTracing)(name, args, handler, {
|
|
97
|
+
mcpClient: { name: 'http', version: 'rest-api' },
|
|
98
|
+
});
|
|
96
99
|
};
|
|
97
100
|
this.restRegistry.registerTool({
|
|
98
101
|
name,
|
|
@@ -100,7 +103,7 @@ class MCPServer {
|
|
|
100
103
|
inputSchema: inputSchema,
|
|
101
104
|
handler: restTracedHandler,
|
|
102
105
|
category,
|
|
103
|
-
tags
|
|
106
|
+
tags,
|
|
104
107
|
});
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
@@ -108,12 +111,32 @@ class MCPServer {
|
|
|
108
111
|
*/
|
|
109
112
|
registerMcpTool(server, session, name, description, inputSchema, handler) {
|
|
110
113
|
const mcpTracedHandler = async (args) => {
|
|
111
|
-
|
|
114
|
+
// RBAC enforcement (PRD #392) — invocation-time check as second layer of defense
|
|
115
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
116
|
+
if (identity) {
|
|
117
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, { toolName: name });
|
|
118
|
+
if (!rbacResult.allowed) {
|
|
119
|
+
return {
|
|
120
|
+
content: [
|
|
121
|
+
{
|
|
122
|
+
type: 'text',
|
|
123
|
+
text: JSON.stringify({
|
|
124
|
+
error: 'FORBIDDEN',
|
|
125
|
+
message: `Access denied: tool '${name}' not authorized for user '${identity.email}'`,
|
|
126
|
+
}),
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return await (0, tracing_1.withToolTracing)(name, args, handler, {
|
|
133
|
+
mcpClient: session.clientInfo,
|
|
134
|
+
});
|
|
112
135
|
};
|
|
113
136
|
/* eslint-disable @typescript-eslint/no-explicit-any -- MCP SDK type compatibility */
|
|
114
137
|
server.registerTool(name, {
|
|
115
138
|
description,
|
|
116
|
-
inputSchema: inputSchema
|
|
139
|
+
inputSchema: inputSchema,
|
|
117
140
|
}, mcpTracedHandler);
|
|
118
141
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
119
142
|
}
|
|
@@ -123,90 +146,123 @@ class MCPServer {
|
|
|
123
146
|
getToolDefs() {
|
|
124
147
|
return [
|
|
125
148
|
{
|
|
126
|
-
name: recommend_1.RECOMMEND_TOOL_NAME,
|
|
149
|
+
name: recommend_1.RECOMMEND_TOOL_NAME,
|
|
150
|
+
description: recommend_1.RECOMMEND_TOOL_DESCRIPTION,
|
|
127
151
|
schema: recommend_1.RECOMMEND_TOOL_INPUT_SCHEMA,
|
|
128
152
|
handler: async (args) => {
|
|
129
153
|
const requestId = this.generateRequestId();
|
|
130
|
-
this.logger.info(`Processing ${recommend_1.RECOMMEND_TOOL_NAME} tool request`, {
|
|
154
|
+
this.logger.info(`Processing ${recommend_1.RECOMMEND_TOOL_NAME} tool request`, {
|
|
155
|
+
requestId,
|
|
156
|
+
});
|
|
131
157
|
if (!this.pluginManager)
|
|
132
158
|
throw new Error('Plugin system not available. Recommend tool requires agentic-tools plugin.');
|
|
133
159
|
return await (0, recommend_1.handleRecommendTool)(args, this.dotAI, this.logger, requestId, this.pluginManager);
|
|
134
160
|
},
|
|
135
|
-
category: 'Deployment',
|
|
161
|
+
category: 'Deployment',
|
|
162
|
+
tags: ['recommendation', 'kubernetes', 'deployment', 'workflow'],
|
|
136
163
|
},
|
|
137
164
|
{
|
|
138
|
-
name: version_1.VERSION_TOOL_NAME,
|
|
165
|
+
name: version_1.VERSION_TOOL_NAME,
|
|
166
|
+
description: version_1.VERSION_TOOL_DESCRIPTION,
|
|
139
167
|
schema: version_1.VERSION_TOOL_INPUT_SCHEMA,
|
|
140
168
|
handler: async (args) => {
|
|
141
169
|
const requestId = this.generateRequestId();
|
|
142
|
-
this.logger.info(`Processing ${version_1.VERSION_TOOL_NAME} tool request`, {
|
|
170
|
+
this.logger.info(`Processing ${version_1.VERSION_TOOL_NAME} tool request`, {
|
|
171
|
+
requestId,
|
|
172
|
+
});
|
|
143
173
|
return await (0, version_1.handleVersionTool)(args, this.logger, requestId);
|
|
144
174
|
},
|
|
145
|
-
category: 'System',
|
|
175
|
+
category: 'System',
|
|
176
|
+
tags: ['version', 'diagnostics', 'status'],
|
|
146
177
|
},
|
|
147
178
|
{
|
|
148
|
-
name: organizational_data_1.ORGANIZATIONAL_DATA_TOOL_NAME,
|
|
179
|
+
name: organizational_data_1.ORGANIZATIONAL_DATA_TOOL_NAME,
|
|
180
|
+
description: organizational_data_1.ORGANIZATIONAL_DATA_TOOL_DESCRIPTION,
|
|
149
181
|
schema: organizational_data_1.ORGANIZATIONAL_DATA_TOOL_INPUT_SCHEMA,
|
|
150
182
|
handler: async (args) => {
|
|
151
183
|
const requestId = this.generateRequestId();
|
|
152
184
|
this.logger.info(`Processing ${organizational_data_1.ORGANIZATIONAL_DATA_TOOL_NAME} tool request`, { requestId });
|
|
153
185
|
return await (0, organizational_data_1.handleOrganizationalDataTool)(args, this.dotAI, this.logger, requestId);
|
|
154
186
|
},
|
|
155
|
-
category: 'Management',
|
|
187
|
+
category: 'Management',
|
|
188
|
+
tags: ['patterns', 'policies', 'capabilities', 'data'],
|
|
156
189
|
},
|
|
157
190
|
{
|
|
158
|
-
name: remediate_1.REMEDIATE_TOOL_NAME,
|
|
191
|
+
name: remediate_1.REMEDIATE_TOOL_NAME,
|
|
192
|
+
description: remediate_1.REMEDIATE_TOOL_DESCRIPTION,
|
|
159
193
|
schema: remediate_1.REMEDIATE_TOOL_INPUT_SCHEMA,
|
|
160
194
|
handler: async (args) => {
|
|
161
195
|
const requestId = this.generateRequestId();
|
|
162
|
-
this.logger.info(`Processing ${remediate_1.REMEDIATE_TOOL_NAME} tool request`, {
|
|
196
|
+
this.logger.info(`Processing ${remediate_1.REMEDIATE_TOOL_NAME} tool request`, {
|
|
197
|
+
requestId,
|
|
198
|
+
});
|
|
163
199
|
if (!(0, plugin_registry_1.isPluginInitialized)())
|
|
164
200
|
throw new Error('Plugin system not available. Remediate tool requires agentic-tools plugin for kubectl operations.');
|
|
165
201
|
return await (0, remediate_1.handleRemediateTool)(args);
|
|
166
202
|
},
|
|
167
|
-
category: 'Troubleshooting',
|
|
203
|
+
category: 'Troubleshooting',
|
|
204
|
+
tags: ['remediation', 'troubleshooting', 'kubernetes', 'analysis'],
|
|
168
205
|
},
|
|
169
206
|
{
|
|
170
|
-
name: operate_1.OPERATE_TOOL_NAME,
|
|
207
|
+
name: operate_1.OPERATE_TOOL_NAME,
|
|
208
|
+
description: operate_1.OPERATE_TOOL_DESCRIPTION,
|
|
171
209
|
schema: operate_1.OPERATE_TOOL_INPUT_SCHEMA,
|
|
172
210
|
handler: async (args) => {
|
|
173
211
|
const requestId = this.generateRequestId();
|
|
174
|
-
this.logger.info(`Processing ${operate_1.OPERATE_TOOL_NAME} tool request`, {
|
|
212
|
+
this.logger.info(`Processing ${operate_1.OPERATE_TOOL_NAME} tool request`, {
|
|
213
|
+
requestId,
|
|
214
|
+
});
|
|
175
215
|
if (!this.pluginManager)
|
|
176
216
|
throw new Error('Plugin system not available. Operate tool requires agentic-tools plugin for kubectl operations.');
|
|
177
217
|
return await (0, operate_1.handleOperateTool)(args, this.pluginManager);
|
|
178
218
|
},
|
|
179
|
-
category: 'Operations',
|
|
219
|
+
category: 'Operations',
|
|
220
|
+
tags: [
|
|
221
|
+
'operate',
|
|
222
|
+
'operations',
|
|
223
|
+
'kubernetes',
|
|
224
|
+
'day2',
|
|
225
|
+
'update',
|
|
226
|
+
'scale',
|
|
227
|
+
],
|
|
180
228
|
},
|
|
181
229
|
{
|
|
182
|
-
name: project_setup_1.PROJECT_SETUP_TOOL_NAME,
|
|
230
|
+
name: project_setup_1.PROJECT_SETUP_TOOL_NAME,
|
|
231
|
+
description: project_setup_1.PROJECT_SETUP_TOOL_DESCRIPTION,
|
|
183
232
|
schema: project_setup_1.PROJECT_SETUP_TOOL_INPUT_SCHEMA,
|
|
184
233
|
handler: async (args) => {
|
|
185
234
|
const requestId = this.generateRequestId();
|
|
186
235
|
this.logger.info(`Processing ${project_setup_1.PROJECT_SETUP_TOOL_NAME} tool request`, { requestId });
|
|
187
236
|
return await (0, project_setup_1.handleProjectSetupTool)(args, this.logger);
|
|
188
237
|
},
|
|
189
|
-
category: 'Project Setup',
|
|
238
|
+
category: 'Project Setup',
|
|
239
|
+
tags: ['governance', 'infrastructure', 'configuration', 'files'],
|
|
190
240
|
},
|
|
191
241
|
{
|
|
192
|
-
name: query_1.QUERY_TOOL_NAME,
|
|
242
|
+
name: query_1.QUERY_TOOL_NAME,
|
|
243
|
+
description: query_1.QUERY_TOOL_DESCRIPTION,
|
|
193
244
|
schema: query_1.QUERY_TOOL_INPUT_SCHEMA,
|
|
194
245
|
handler: async (args) => {
|
|
195
246
|
const requestId = this.generateRequestId();
|
|
196
|
-
this.logger.info(`Processing ${query_1.QUERY_TOOL_NAME} tool request`, {
|
|
247
|
+
this.logger.info(`Processing ${query_1.QUERY_TOOL_NAME} tool request`, {
|
|
248
|
+
requestId,
|
|
249
|
+
});
|
|
197
250
|
return await (0, query_1.handleQueryTool)(args, this.pluginManager);
|
|
198
251
|
},
|
|
199
|
-
category: 'Intelligence',
|
|
252
|
+
category: 'Intelligence',
|
|
253
|
+
tags: ['query', 'search', 'discover', 'capabilities', 'cluster'],
|
|
200
254
|
},
|
|
201
255
|
{
|
|
202
|
-
name: manage_knowledge_1.MANAGE_KNOWLEDGE_TOOL_NAME,
|
|
256
|
+
name: manage_knowledge_1.MANAGE_KNOWLEDGE_TOOL_NAME,
|
|
257
|
+
description: manage_knowledge_1.MANAGE_KNOWLEDGE_TOOL_DESCRIPTION,
|
|
203
258
|
schema: manage_knowledge_1.MANAGE_KNOWLEDGE_TOOL_INPUT_SCHEMA,
|
|
204
259
|
handler: async (args) => {
|
|
205
260
|
const requestId = this.generateRequestId();
|
|
206
261
|
this.logger.info(`Processing ${manage_knowledge_1.MANAGE_KNOWLEDGE_TOOL_NAME} tool request`, { requestId });
|
|
207
262
|
return await (0, manage_knowledge_1.handleManageKnowledgeTool)(args, this.dotAI, this.logger, requestId);
|
|
208
263
|
},
|
|
209
|
-
category: 'Knowledge',
|
|
264
|
+
category: 'Knowledge',
|
|
265
|
+
tags: ['knowledge', 'documents', 'ingest', 'semantic', 'search'],
|
|
210
266
|
},
|
|
211
267
|
];
|
|
212
268
|
}
|
|
@@ -228,13 +284,16 @@ class MCPServer {
|
|
|
228
284
|
* Each MCP client session gets its own server instance (SDK limitation:
|
|
229
285
|
* Protocol only supports one transport per server).
|
|
230
286
|
*/
|
|
231
|
-
createSessionServer(session) {
|
|
287
|
+
async createSessionServer(session, authIdentity) {
|
|
232
288
|
const server = new mcp_js_1.McpServer({ name: this.config.name, version: this.config.version }, { capabilities: { tools: {}, prompts: {} } });
|
|
233
289
|
// Track client info per session
|
|
234
290
|
server.server.oninitialized = () => {
|
|
235
291
|
const clientVersion = server.server.getClientVersion();
|
|
236
292
|
if (clientVersion) {
|
|
237
|
-
session.clientInfo = {
|
|
293
|
+
session.clientInfo = {
|
|
294
|
+
name: clientVersion.name,
|
|
295
|
+
version: clientVersion.version,
|
|
296
|
+
};
|
|
238
297
|
(0, telemetry_1.getTelemetry)().trackClientConnected(session.clientInfo);
|
|
239
298
|
this.logger.info('MCP client connected', {
|
|
240
299
|
client: clientVersion.name,
|
|
@@ -242,8 +301,10 @@ class MCPServer {
|
|
|
242
301
|
});
|
|
243
302
|
}
|
|
244
303
|
};
|
|
245
|
-
// Register
|
|
246
|
-
|
|
304
|
+
// Register tools on this session server, filtered by RBAC (PRD #392)
|
|
305
|
+
const allDefs = this.getToolDefs();
|
|
306
|
+
const defs = await (0, rbac_1.filterAuthorizedTools)(authIdentity, allDefs);
|
|
307
|
+
for (const def of defs) {
|
|
247
308
|
this.registerMcpTool(server, session, def.name, def.description, def.schema, def.handler);
|
|
248
309
|
}
|
|
249
310
|
// Register prompts
|
|
@@ -263,14 +324,19 @@ class MCPServer {
|
|
|
263
324
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK type compatibility
|
|
264
325
|
server.server.setRequestHandler(types_js_1.GetPromptRequestSchema, async (request) => {
|
|
265
326
|
const requestId = this.generateRequestId();
|
|
266
|
-
this.logger.info('Processing prompts/get request', {
|
|
327
|
+
this.logger.info('Processing prompts/get request', {
|
|
328
|
+
requestId,
|
|
329
|
+
promptName: request.params?.name,
|
|
330
|
+
});
|
|
267
331
|
return await (0, prompts_1.handlePromptsGetRequest)(request.params || { name: '' }, this.logger, requestId);
|
|
268
332
|
});
|
|
269
333
|
}
|
|
270
334
|
configureHostProvider() {
|
|
271
335
|
const aiProvider = this.dotAI.ai;
|
|
272
336
|
this.logger.info('Using configured AI Provider', {
|
|
273
|
-
type: aiProvider.getProviderType
|
|
337
|
+
type: aiProvider.getProviderType
|
|
338
|
+
? aiProvider.getProviderType()
|
|
339
|
+
: 'unknown',
|
|
274
340
|
});
|
|
275
341
|
}
|
|
276
342
|
/**
|
|
@@ -298,7 +364,11 @@ class MCPServer {
|
|
|
298
364
|
this.initialized = true;
|
|
299
365
|
}
|
|
300
366
|
async startHttpTransport() {
|
|
301
|
-
const port = process.env.PORT
|
|
367
|
+
const port = process.env.PORT
|
|
368
|
+
? parseInt(process.env.PORT)
|
|
369
|
+
: this.config.port !== undefined
|
|
370
|
+
? this.config.port
|
|
371
|
+
: 3456;
|
|
302
372
|
const host = process.env.HOST || this.config.host || '0.0.0.0';
|
|
303
373
|
this.logger.info('Using HTTP/SSE transport', { port, host });
|
|
304
374
|
// Create OAuth provider and Express sub-app with SDK router
|
|
@@ -328,7 +398,7 @@ class MCPServer {
|
|
|
328
398
|
this.logger.debug('HTTP request received', {
|
|
329
399
|
method: req.method,
|
|
330
400
|
url: req.url,
|
|
331
|
-
headers: req.headers
|
|
401
|
+
headers: req.headers,
|
|
332
402
|
});
|
|
333
403
|
// Handle CORS for browser-based clients
|
|
334
404
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
@@ -370,10 +440,14 @@ class MCPServer {
|
|
|
370
440
|
if (!isOpenApiEndpoint) {
|
|
371
441
|
const authResult = (0, oauth_1.checkBearerAuth)(req);
|
|
372
442
|
if (!authResult.authorized) {
|
|
373
|
-
this.logger.warn('Authentication failed', {
|
|
443
|
+
this.logger.warn('Authentication failed', {
|
|
444
|
+
message: authResult.message,
|
|
445
|
+
});
|
|
374
446
|
const issuerHref = this.issuerUrl.href.replace(/\/$/, '');
|
|
375
447
|
const resourceMetadataUrl = `${issuerHref}/.well-known/oauth-protected-resource`;
|
|
376
|
-
(0, error_response_1.sendErrorResponse)(res, 401, 'UNAUTHORIZED', authResult.message || 'Authentication required', undefined, {
|
|
448
|
+
(0, error_response_1.sendErrorResponse)(res, 401, 'UNAUTHORIZED', authResult.message || 'Authentication required', undefined, {
|
|
449
|
+
'WWW-Authenticate': `Bearer resource_metadata="${resourceMetadataUrl}"`,
|
|
450
|
+
});
|
|
377
451
|
endSpan(401);
|
|
378
452
|
return;
|
|
379
453
|
}
|
|
@@ -388,7 +462,9 @@ class MCPServer {
|
|
|
388
462
|
}
|
|
389
463
|
// Check if this is a REST API request
|
|
390
464
|
if (this.restApiRouter.isApiRequest(req.url || '')) {
|
|
391
|
-
this.logger.debug('Routing to REST API handler', {
|
|
465
|
+
this.logger.debug('Routing to REST API handler', {
|
|
466
|
+
url: req.url,
|
|
467
|
+
});
|
|
392
468
|
// Mark span as REST API request
|
|
393
469
|
span.setAttribute('request.type', 'rest-api');
|
|
394
470
|
try {
|
|
@@ -410,7 +486,8 @@ class MCPServer {
|
|
|
410
486
|
span.updateName('MCP ' + (req.url || '/'));
|
|
411
487
|
try {
|
|
412
488
|
// Determine if this is an initialize request (needs new transport)
|
|
413
|
-
const isInit = req.method === 'POST' &&
|
|
489
|
+
const isInit = req.method === 'POST' &&
|
|
490
|
+
body != null &&
|
|
414
491
|
(Array.isArray(body)
|
|
415
492
|
? body.some(m => (0, types_js_1.isInitializeRequest)(m))
|
|
416
493
|
: (0, types_js_1.isInitializeRequest)(body));
|
|
@@ -418,16 +495,20 @@ class MCPServer {
|
|
|
418
495
|
// Create a new McpServer + transport pair for this client session.
|
|
419
496
|
// Each session gets its own McpServer instance because the SDK's
|
|
420
497
|
// Protocol class only supports one transport at a time.
|
|
421
|
-
const session = {
|
|
498
|
+
const session = {
|
|
499
|
+
lastActivity: Date.now(),
|
|
500
|
+
};
|
|
422
501
|
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
423
502
|
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
|
|
424
503
|
enableJsonResponse: false,
|
|
425
504
|
onsessioninitialized: (sid) => {
|
|
426
|
-
this.logger.info('Session initialized', {
|
|
505
|
+
this.logger.info('Session initialized', {
|
|
506
|
+
sessionId: sid,
|
|
507
|
+
});
|
|
427
508
|
this.sessions.set(sid, session);
|
|
428
509
|
},
|
|
429
510
|
});
|
|
430
|
-
const server = this.createSessionServer(session);
|
|
511
|
+
const server = await this.createSessionServer(session, authIdentity);
|
|
431
512
|
session.server = server;
|
|
432
513
|
session.transport = transport;
|
|
433
514
|
transport.onclose = () => {
|
|
@@ -443,7 +524,9 @@ class MCPServer {
|
|
|
443
524
|
else {
|
|
444
525
|
// Route to existing session by Mcp-Session-Id header
|
|
445
526
|
const sessionId = req.headers['mcp-session-id'];
|
|
446
|
-
const session = sessionId
|
|
527
|
+
const session = sessionId
|
|
528
|
+
? this.sessions.get(sessionId)
|
|
529
|
+
: undefined;
|
|
447
530
|
if (!session) {
|
|
448
531
|
(0, error_response_1.sendErrorResponse)(res, 404, 'SESSION_NOT_FOUND', 'Session not found');
|
|
449
532
|
endSpan(404);
|
|
@@ -485,7 +568,7 @@ class MCPServer {
|
|
|
485
568
|
async parseRequestBody(req) {
|
|
486
569
|
return new Promise((resolve, reject) => {
|
|
487
570
|
let body = '';
|
|
488
|
-
req.on('data', chunk => body += chunk.toString());
|
|
571
|
+
req.on('data', chunk => (body += chunk.toString()));
|
|
489
572
|
req.on('end', () => {
|
|
490
573
|
try {
|
|
491
574
|
resolve(body ? JSON.parse(body) : undefined);
|
|
@@ -513,12 +596,14 @@ class MCPServer {
|
|
|
513
596
|
try {
|
|
514
597
|
await session.server.close();
|
|
515
598
|
}
|
|
516
|
-
catch {
|
|
599
|
+
catch {
|
|
600
|
+
/* ignore */
|
|
601
|
+
}
|
|
517
602
|
this.sessions.delete(sid);
|
|
518
603
|
}
|
|
519
604
|
// Stop HTTP server if running
|
|
520
605
|
if (this.httpServer) {
|
|
521
|
-
await new Promise(
|
|
606
|
+
await new Promise(resolve => {
|
|
522
607
|
this.httpServer.close(() => {
|
|
523
608
|
this.logger.info('HTTP server stopped');
|
|
524
609
|
resolve();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/interfaces/rest-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,iBAAiB,EAAc,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAoCtC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/interfaces/rest-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,6 +57,8 @@ const mermaid_tools_1 = require("../core/mermaid-tools");
|
|
|
57
57
|
const plugin_registry_1 = require("../core/plugin-registry");
|
|
58
58
|
const manage_knowledge_1 = require("../tools/manage-knowledge");
|
|
59
59
|
const user_management_1 = require("./oauth/user-management");
|
|
60
|
+
const request_context_1 = require("./request-context");
|
|
61
|
+
const rbac_1 = require("../core/rbac");
|
|
60
62
|
/**
|
|
61
63
|
* HTTP status codes for REST responses
|
|
62
64
|
*/
|
|
@@ -222,7 +224,10 @@ class RestApiRouter {
|
|
|
222
224
|
const category = searchParams.get('category') || undefined;
|
|
223
225
|
const tag = searchParams.get('tag') || undefined;
|
|
224
226
|
const search = searchParams.get('search') || undefined;
|
|
225
|
-
|
|
227
|
+
let tools = this.registry.getToolsFiltered({ category, tag, search });
|
|
228
|
+
// RBAC-filtered tool discovery (PRD #392) — OAuth users only see authorized tools
|
|
229
|
+
const discoveryIdentity = (0, request_context_1.getCurrentIdentity)();
|
|
230
|
+
tools = await (0, rbac_1.filterAuthorizedTools)(discoveryIdentity, tools);
|
|
226
231
|
const categories = this.registry.getCategories();
|
|
227
232
|
const tags = this.registry.getTags();
|
|
228
233
|
const response = {
|
|
@@ -261,6 +266,15 @@ class RestApiRouter {
|
|
|
261
266
|
await this.sendErrorResponse(res, requestId, HttpStatus.NOT_FOUND, 'TOOL_NOT_FOUND', `Tool '${toolName}' not found`);
|
|
262
267
|
return;
|
|
263
268
|
}
|
|
269
|
+
// RBAC enforcement (PRD #392) — check tool-level authorization for OAuth users
|
|
270
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
271
|
+
if (identity) {
|
|
272
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, { toolName });
|
|
273
|
+
if (!rbacResult.allowed) {
|
|
274
|
+
await this.sendErrorResponse(res, requestId, 403, 'FORBIDDEN', `Access denied: tool '${toolName}' not authorized for user '${identity.email}'`);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
264
278
|
// Validate request body
|
|
265
279
|
if (!body || typeof body !== 'object') {
|
|
266
280
|
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'INVALID_REQUEST', 'Request body must be a JSON object');
|
|
@@ -1795,6 +1809,18 @@ class RestApiRouter {
|
|
|
1795
1809
|
*/
|
|
1796
1810
|
async handleCreateUser(_req, res, requestId, body) {
|
|
1797
1811
|
try {
|
|
1812
|
+
// RBAC enforcement (PRD #392) — user management requires dotai-admin role
|
|
1813
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
1814
|
+
if (identity) {
|
|
1815
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, {
|
|
1816
|
+
toolName: 'users',
|
|
1817
|
+
resource: 'users',
|
|
1818
|
+
});
|
|
1819
|
+
if (!rbacResult.allowed) {
|
|
1820
|
+
await this.sendErrorResponse(res, requestId, 403, 'FORBIDDEN', 'User management requires dotai-admin role');
|
|
1821
|
+
return;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1798
1824
|
if (!body ||
|
|
1799
1825
|
typeof body !== 'object' ||
|
|
1800
1826
|
!('email' in body) ||
|
|
@@ -1812,6 +1838,7 @@ class RestApiRouter {
|
|
|
1812
1838
|
return;
|
|
1813
1839
|
}
|
|
1814
1840
|
const result = await (0, user_management_1.createUser)(email, password);
|
|
1841
|
+
(0, rbac_1.logUserManagementOperation)(identity, 'created', email);
|
|
1815
1842
|
await this.sendJsonResponse(res, HttpStatus.OK, {
|
|
1816
1843
|
success: true,
|
|
1817
1844
|
data: result,
|
|
@@ -1839,6 +1866,18 @@ class RestApiRouter {
|
|
|
1839
1866
|
*/
|
|
1840
1867
|
async handleListUsers(_req, res, requestId) {
|
|
1841
1868
|
try {
|
|
1869
|
+
// RBAC enforcement (PRD #392) — user management requires dotai-admin role
|
|
1870
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
1871
|
+
if (identity) {
|
|
1872
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, {
|
|
1873
|
+
toolName: 'users',
|
|
1874
|
+
resource: 'users',
|
|
1875
|
+
});
|
|
1876
|
+
if (!rbacResult.allowed) {
|
|
1877
|
+
await this.sendErrorResponse(res, requestId, 403, 'FORBIDDEN', 'User management requires dotai-admin role');
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1842
1881
|
const users = await (0, user_management_1.listUsers)();
|
|
1843
1882
|
await this.sendJsonResponse(res, HttpStatus.OK, {
|
|
1844
1883
|
success: true,
|
|
@@ -1861,6 +1900,18 @@ class RestApiRouter {
|
|
|
1861
1900
|
*/
|
|
1862
1901
|
async handleDeleteUser(_req, res, requestId, email) {
|
|
1863
1902
|
try {
|
|
1903
|
+
// RBAC enforcement (PRD #392) — user management requires dotai-admin role
|
|
1904
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
1905
|
+
if (identity) {
|
|
1906
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, {
|
|
1907
|
+
toolName: 'users',
|
|
1908
|
+
resource: 'users',
|
|
1909
|
+
});
|
|
1910
|
+
if (!rbacResult.allowed) {
|
|
1911
|
+
await this.sendErrorResponse(res, requestId, 403, 'FORBIDDEN', 'User management requires dotai-admin role');
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1864
1915
|
let decodedEmail;
|
|
1865
1916
|
try {
|
|
1866
1917
|
decodedEmail = decodeURIComponent(email);
|
|
@@ -1870,6 +1921,7 @@ class RestApiRouter {
|
|
|
1870
1921
|
return;
|
|
1871
1922
|
}
|
|
1872
1923
|
const result = await (0, user_management_1.deleteUser)(decodedEmail);
|
|
1924
|
+
(0, rbac_1.logUserManagementOperation)(identity, 'deleted', decodedEmail);
|
|
1873
1925
|
await this.sendJsonResponse(res, HttpStatus.OK, {
|
|
1874
1926
|
success: true,
|
|
1875
1927
|
data: result,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-manifests.d.ts","sourceRoot":"","sources":["../../src/tools/generate-manifests.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,EAAE,KAAK,EAA0B,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAgBhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate-manifests.d.ts","sourceRoot":"","sources":["../../src/tools/generate-manifests.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,EAAE,KAAK,EAA0B,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAgBhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA8E5D,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAC/D,eAAO,MAAM,kCAAkC,+IAC+F,CAAC;AAG/I,eAAO,MAAM,mCAAmC;;;CAa/C,CAAC;AAq8BF;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACrD,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CA0WxD"}
|
|
@@ -57,7 +57,27 @@ const solution_cr_1 = require("../core/solution-cr");
|
|
|
57
57
|
const packaging_1 = require("../core/packaging");
|
|
58
58
|
const visualization_1 = require("../core/visualization");
|
|
59
59
|
const plugin_registry_1 = require("../core/plugin-registry");
|
|
60
|
+
const request_context_1 = require("../interfaces/request-context");
|
|
61
|
+
const rbac_1 = require("../core/rbac");
|
|
60
62
|
// PRD #359: All helm operations via unified plugin registry
|
|
63
|
+
/**
|
|
64
|
+
* PRD #392 Milestone 2: Build agent instructions based on deploy permission.
|
|
65
|
+
* When the user has 'apply' permission, includes the deploy option.
|
|
66
|
+
* When they don't, explains that deploying requires 'apply' permission.
|
|
67
|
+
*/
|
|
68
|
+
async function buildDeployInstructions(outputPath, outputFormat) {
|
|
69
|
+
const writeInstr = `Write the files to "${outputPath}".`;
|
|
70
|
+
const formatInstr = outputFormat === 'helm' ? ' The output is a Helm chart.' : outputFormat === 'raw' ? '' : ' The output is a Kustomize overlay.';
|
|
71
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
72
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, {
|
|
73
|
+
toolName: 'recommend',
|
|
74
|
+
verb: 'apply',
|
|
75
|
+
});
|
|
76
|
+
if (rbacResult.allowed) {
|
|
77
|
+
return `${writeInstr}${formatInstr} If immediate deployment is desired, call the recommend tool with stage: "deployManifests".`;
|
|
78
|
+
}
|
|
79
|
+
return `${writeInstr}${formatInstr} Deploying manifests requires 'apply' permission on 'recommend', which is not granted for the current user. Save the files locally or push to Git to apply them through your own workflow.`;
|
|
80
|
+
}
|
|
61
81
|
/**
|
|
62
82
|
* Ensure tmp directory exists
|
|
63
83
|
*/
|
|
@@ -915,7 +935,7 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
|
|
|
915
935
|
validationAttempts: attempt,
|
|
916
936
|
packagingAttempts: packagingResult.attempts,
|
|
917
937
|
timestamp: new Date().toISOString(),
|
|
918
|
-
agentInstructions:
|
|
938
|
+
agentInstructions: await buildDeployInstructions(outputPath, outputFormat),
|
|
919
939
|
...(visualizationUrl ? { visualizationUrl } : {}),
|
|
920
940
|
};
|
|
921
941
|
// Build content blocks - JSON for REST API, agent instruction for MCP agents
|
|
@@ -957,7 +977,7 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
|
|
|
957
977
|
files: [{ relativePath: 'manifests.yaml', content: manifests }],
|
|
958
978
|
validationAttempts: attempt,
|
|
959
979
|
timestamp: new Date().toISOString(),
|
|
960
|
-
agentInstructions:
|
|
980
|
+
agentInstructions: await buildDeployInstructions(outputPath, outputFormat),
|
|
961
981
|
...(visualizationUrl ? { visualizationUrl } : {}),
|
|
962
982
|
};
|
|
963
983
|
// Build content blocks - JSON for REST API, agent instruction for MCP agents
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manage-knowledge.d.ts","sourceRoot":"","sources":["../../src/tools/manage-knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,OAAO,EAIL,yBAAyB,EAE1B,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"manage-knowledge.d.ts","sourceRoot":"","sources":["../../src/tools/manage-knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,OAAO,EAIL,yBAAyB,EAE1B,MAAM,yBAAyB,CAAC;AAUjC,eAAO,MAAM,0BAA0B,oBAAoB,CAAC;AAC5D,eAAO,MAAM,iCAAiC,QAKgB,CAAC;AAG/D,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;CAkC9C,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAiPD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,yBAAyB,EAAE,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CA4HrC;AA2ND;;GAEG;AACH,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAgBD;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAE,KAAK,GAAG,IAAI,EACpB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAiD1B"}
|
|
@@ -14,6 +14,8 @@ exports.handleManageKnowledgeTool = handleManageKnowledgeTool;
|
|
|
14
14
|
const zod_1 = require("zod");
|
|
15
15
|
const plugin_registry_1 = require("../core/plugin-registry");
|
|
16
16
|
const embedding_service_1 = require("../core/embedding-service");
|
|
17
|
+
const request_context_1 = require("../interfaces/request-context");
|
|
18
|
+
const rbac_1 = require("../core/rbac");
|
|
17
19
|
/**
|
|
18
20
|
* Collection name for knowledge base chunks in Qdrant
|
|
19
21
|
*/
|
|
@@ -550,6 +552,24 @@ async function handleManageKnowledgeTool(args, _dotAI, logger, requestId) {
|
|
|
550
552
|
requestId,
|
|
551
553
|
operation: args.operation,
|
|
552
554
|
});
|
|
555
|
+
// PRD #392 Milestone 8: Mutating operations require 'apply' verb
|
|
556
|
+
const MUTATING_KNOWLEDGE_OPS = new Set(['ingest', 'deleteByUri']);
|
|
557
|
+
if (MUTATING_KNOWLEDGE_OPS.has(args.operation)) {
|
|
558
|
+
const identity = (0, request_context_1.getCurrentIdentity)();
|
|
559
|
+
const rbacResult = await (0, rbac_1.checkToolAccess)(identity, {
|
|
560
|
+
toolName: 'manageKnowledge',
|
|
561
|
+
verb: 'apply',
|
|
562
|
+
});
|
|
563
|
+
if (!rbacResult.allowed) {
|
|
564
|
+
return wrapMcpResponse({
|
|
565
|
+
error: 'FORBIDDEN',
|
|
566
|
+
message: `Access denied: '${args.operation}' on knowledge base requires 'apply' permission on 'manageKnowledge'. Search is available with 'execute' permission.`,
|
|
567
|
+
tool: 'manageKnowledge',
|
|
568
|
+
operation: args.operation,
|
|
569
|
+
user: identity?.email,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
553
573
|
// Route to appropriate handler based on operation
|
|
554
574
|
let response;
|
|
555
575
|
switch (args.operation) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operate.d.ts","sourceRoot":"","sources":["../../src/tools/operate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAIL,MAAM,EAEP,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"operate.d.ts","sourceRoot":"","sources":["../../src/tools/operate.ts"],"names":[],"mappings":"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"}
|