visus-mcp 0.6.1 → 0.6.2
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/.claude/settings.local.json +28 -1
- package/.mcpregistry_github_token +1 -1
- package/.mcpregistry_registry_token +1 -1
- package/CLAUDE.md +197 -0
- package/TROUBLESHOOT-COGNITO-AUTH-20260324-2029.md +415 -0
- package/TROUBLESHOOT-COGNITO-JWT-20260324.md +592 -0
- package/dist/browser/playwright-renderer.d.ts.map +1 -1
- package/dist/browser/playwright-renderer.js +71 -51
- package/dist/browser/playwright-renderer.js.map +1 -1
- package/dist/index.js +0 -0
- package/infrastructure/stack.ts +1 -0
- package/lambda-deploy/index.js +81512 -0
- package/lambda-deploy/index.js.map +7 -0
- package/lambda-package/browser/__mocks__/playwright-renderer.d.ts +25 -0
- package/lambda-package/browser/__mocks__/playwright-renderer.d.ts.map +1 -0
- package/lambda-package/browser/__mocks__/playwright-renderer.js +119 -0
- package/lambda-package/browser/__mocks__/playwright-renderer.js.map +1 -0
- package/lambda-package/browser/playwright-renderer.d.ts +40 -0
- package/lambda-package/browser/playwright-renderer.d.ts.map +1 -0
- package/lambda-package/browser/playwright-renderer.js +214 -0
- package/lambda-package/browser/playwright-renderer.js.map +1 -0
- package/lambda-package/browser/reader.d.ts +31 -0
- package/lambda-package/browser/reader.d.ts.map +1 -0
- package/lambda-package/browser/reader.js +98 -0
- package/lambda-package/browser/reader.js.map +1 -0
- package/lambda-package/index.d.ts +18 -0
- package/lambda-package/index.d.ts.map +1 -0
- package/lambda-package/index.js +238 -0
- package/lambda-package/index.js.map +1 -0
- package/lambda-package/lambda-handler.d.ts +28 -0
- package/lambda-package/lambda-handler.d.ts.map +1 -0
- package/lambda-package/lambda-handler.js +257 -0
- package/lambda-package/lambda-handler.js.map +1 -0
- package/lambda-package/package-lock.json +7435 -0
- package/lambda-package/package.json +74 -0
- package/lambda-package/runtime.d.ts +50 -0
- package/lambda-package/runtime.d.ts.map +1 -0
- package/lambda-package/runtime.js +86 -0
- package/lambda-package/runtime.js.map +1 -0
- package/lambda-package/sanitizer/elicit-runner.d.ts +48 -0
- package/lambda-package/sanitizer/elicit-runner.d.ts.map +1 -0
- package/lambda-package/sanitizer/elicit-runner.js +100 -0
- package/lambda-package/sanitizer/elicit-runner.js.map +1 -0
- package/lambda-package/sanitizer/framework-mapper.d.ts +24 -0
- package/lambda-package/sanitizer/framework-mapper.d.ts.map +1 -0
- package/lambda-package/sanitizer/framework-mapper.js +342 -0
- package/lambda-package/sanitizer/framework-mapper.js.map +1 -0
- package/lambda-package/sanitizer/hitl-gate.d.ts +69 -0
- package/lambda-package/sanitizer/hitl-gate.d.ts.map +1 -0
- package/lambda-package/sanitizer/hitl-gate.js +101 -0
- package/lambda-package/sanitizer/hitl-gate.js.map +1 -0
- package/lambda-package/sanitizer/index.d.ts +63 -0
- package/lambda-package/sanitizer/index.d.ts.map +1 -0
- package/lambda-package/sanitizer/index.js +105 -0
- package/lambda-package/sanitizer/index.js.map +1 -0
- package/lambda-package/sanitizer/injection-detector.d.ts +34 -0
- package/lambda-package/sanitizer/injection-detector.d.ts.map +1 -0
- package/lambda-package/sanitizer/injection-detector.js +89 -0
- package/lambda-package/sanitizer/injection-detector.js.map +1 -0
- package/lambda-package/sanitizer/patterns.d.ts +30 -0
- package/lambda-package/sanitizer/patterns.d.ts.map +1 -0
- package/lambda-package/sanitizer/patterns.js +372 -0
- package/lambda-package/sanitizer/patterns.js.map +1 -0
- package/lambda-package/sanitizer/pii-allowlist.d.ts +49 -0
- package/lambda-package/sanitizer/pii-allowlist.d.ts.map +1 -0
- package/lambda-package/sanitizer/pii-allowlist.js +231 -0
- package/lambda-package/sanitizer/pii-allowlist.js.map +1 -0
- package/lambda-package/sanitizer/pii-redactor.d.ts +41 -0
- package/lambda-package/sanitizer/pii-redactor.d.ts.map +1 -0
- package/lambda-package/sanitizer/pii-redactor.js +213 -0
- package/lambda-package/sanitizer/pii-redactor.js.map +1 -0
- package/lambda-package/sanitizer/severity-classifier.d.ts +33 -0
- package/lambda-package/sanitizer/severity-classifier.d.ts.map +1 -0
- package/lambda-package/sanitizer/severity-classifier.js +113 -0
- package/lambda-package/sanitizer/severity-classifier.js.map +1 -0
- package/lambda-package/sanitizer/threat-reporter.d.ts +66 -0
- package/lambda-package/sanitizer/threat-reporter.d.ts.map +1 -0
- package/lambda-package/sanitizer/threat-reporter.js +163 -0
- package/lambda-package/sanitizer/threat-reporter.js.map +1 -0
- package/lambda-package/tools/fetch-structured.d.ts +51 -0
- package/lambda-package/tools/fetch-structured.d.ts.map +1 -0
- package/lambda-package/tools/fetch-structured.js +237 -0
- package/lambda-package/tools/fetch-structured.js.map +1 -0
- package/lambda-package/tools/fetch.d.ts +49 -0
- package/lambda-package/tools/fetch.d.ts.map +1 -0
- package/lambda-package/tools/fetch.js +131 -0
- package/lambda-package/tools/fetch.js.map +1 -0
- package/lambda-package/tools/read.d.ts +51 -0
- package/lambda-package/tools/read.d.ts.map +1 -0
- package/lambda-package/tools/read.js +127 -0
- package/lambda-package/tools/read.js.map +1 -0
- package/lambda-package/tools/search.d.ts +45 -0
- package/lambda-package/tools/search.d.ts.map +1 -0
- package/lambda-package/tools/search.js +220 -0
- package/lambda-package/tools/search.js.map +1 -0
- package/lambda-package/types.d.ts +167 -0
- package/lambda-package/types.d.ts.map +1 -0
- package/lambda-package/types.js +16 -0
- package/lambda-package/types.js.map +1 -0
- package/lambda-package/utils/format-converter.d.ts +39 -0
- package/lambda-package/utils/format-converter.d.ts.map +1 -0
- package/lambda-package/utils/format-converter.js +191 -0
- package/lambda-package/utils/format-converter.js.map +1 -0
- package/lambda-package/utils/truncate.d.ts +26 -0
- package/lambda-package/utils/truncate.d.ts.map +1 -0
- package/lambda-package/utils/truncate.js +54 -0
- package/lambda-package/utils/truncate.js.map +1 -0
- package/lambda.zip +0 -0
- package/package.json +3 -2
- package/server.json +3 -3
- package/src/browser/playwright-renderer.ts +74 -51
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Visus MCP - Dual-Mode Entry Point (Phase 2)
|
|
4
|
+
*
|
|
5
|
+
* Supports two runtime modes:
|
|
6
|
+
* 1. stdio MCP server (npx visus-mcp) - Open source tier
|
|
7
|
+
* 2. AWS Lambda handler (API Gateway) - Hosted tier
|
|
8
|
+
*
|
|
9
|
+
* Runtime detection determines which mode to use based on environment variables.
|
|
10
|
+
*
|
|
11
|
+
* Tools:
|
|
12
|
+
* - visus_fetch: Fetch and sanitize web page content
|
|
13
|
+
* - visus_fetch_structured: Extract structured data from web pages
|
|
14
|
+
*
|
|
15
|
+
* ALL content passes through the Lateos injection sanitizer before reaching the LLM.
|
|
16
|
+
*/
|
|
17
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
18
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
19
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
20
|
+
import { visusFetch, visusFetchToolDefinition } from './tools/fetch.js';
|
|
21
|
+
import { visusFetchStructured, visusFetchStructuredToolDefinition } from './tools/fetch-structured.js';
|
|
22
|
+
import { visusRead, visusReadToolDefinition } from './tools/read.js';
|
|
23
|
+
import { visusSearch, visusSearchToolDefinition } from './tools/search.js';
|
|
24
|
+
import { closeBrowser } from './browser/playwright-renderer.js';
|
|
25
|
+
import { detectRuntime, logRuntimeConfig, validateRuntime } from './runtime.js';
|
|
26
|
+
import { shouldElicit } from './sanitizer/hitl-gate.js';
|
|
27
|
+
import { runElicitation } from './sanitizer/elicit-runner.js';
|
|
28
|
+
/**
|
|
29
|
+
* Create and configure the MCP server
|
|
30
|
+
*/
|
|
31
|
+
const server = new Server({
|
|
32
|
+
name: 'visus-mcp',
|
|
33
|
+
version: '0.6.0'
|
|
34
|
+
}, {
|
|
35
|
+
capabilities: {
|
|
36
|
+
tools: {}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Handle tool list requests
|
|
41
|
+
*/
|
|
42
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
43
|
+
return {
|
|
44
|
+
tools: [
|
|
45
|
+
visusFetchToolDefinition,
|
|
46
|
+
visusFetchStructuredToolDefinition,
|
|
47
|
+
visusReadToolDefinition,
|
|
48
|
+
visusSearchToolDefinition
|
|
49
|
+
]
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Helper function to handle HITL elicitation for CRITICAL threats
|
|
54
|
+
*
|
|
55
|
+
* Returns modified output with threat_report removed if user declined,
|
|
56
|
+
* or blocked response if user declined to proceed.
|
|
57
|
+
*/
|
|
58
|
+
async function handleCriticalThreatElicitation(output, url) {
|
|
59
|
+
const threatReport = output.threat_report;
|
|
60
|
+
// Check if elicitation is needed
|
|
61
|
+
if (shouldElicit(threatReport ?? null)) {
|
|
62
|
+
const { proceed, includeReport } = await runElicitation(server, threatReport, url);
|
|
63
|
+
if (!proceed) {
|
|
64
|
+
// User declined — return blocked response with threat report
|
|
65
|
+
return {
|
|
66
|
+
output: {
|
|
67
|
+
url,
|
|
68
|
+
blocked: true,
|
|
69
|
+
reason: 'User declined to proceed after CRITICAL threat detected',
|
|
70
|
+
threat_report: threatReport
|
|
71
|
+
},
|
|
72
|
+
blocked: true
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// User accepted — proceed with sanitized content
|
|
76
|
+
// Remove threat_report if user didn't request it
|
|
77
|
+
if (!includeReport && output.threat_report) {
|
|
78
|
+
const { threat_report, ...outputWithoutReport } = output;
|
|
79
|
+
return { output: outputWithoutReport, blocked: false };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { output, blocked: false };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Handle tool execution requests
|
|
86
|
+
*/
|
|
87
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
88
|
+
const { name, arguments: args } = request.params;
|
|
89
|
+
try {
|
|
90
|
+
switch (name) {
|
|
91
|
+
case 'visus_fetch': {
|
|
92
|
+
const result = await visusFetch(args);
|
|
93
|
+
if (!result.ok) {
|
|
94
|
+
throw new McpError(ErrorCode.InternalError, `visus_fetch failed: ${result.error.message}`);
|
|
95
|
+
}
|
|
96
|
+
// Handle HITL elicitation for CRITICAL threats
|
|
97
|
+
const { output } = await handleCriticalThreatElicitation(result.value, args.url);
|
|
98
|
+
return {
|
|
99
|
+
content: [
|
|
100
|
+
{
|
|
101
|
+
type: 'text',
|
|
102
|
+
text: JSON.stringify(output, null, 2)
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
case 'visus_fetch_structured': {
|
|
108
|
+
const result = await visusFetchStructured(args);
|
|
109
|
+
if (!result.ok) {
|
|
110
|
+
throw new McpError(ErrorCode.InternalError, `visus_fetch_structured failed: ${result.error.message}`);
|
|
111
|
+
}
|
|
112
|
+
// Handle HITL elicitation for CRITICAL threats
|
|
113
|
+
const { output } = await handleCriticalThreatElicitation(result.value, args.url);
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: 'text',
|
|
118
|
+
text: JSON.stringify(output, null, 2)
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
case 'visus_read': {
|
|
124
|
+
const result = await visusRead(args);
|
|
125
|
+
if (!result.ok) {
|
|
126
|
+
throw new McpError(ErrorCode.InternalError, `visus_read failed: ${result.error.message}`);
|
|
127
|
+
}
|
|
128
|
+
// Handle HITL elicitation for CRITICAL threats
|
|
129
|
+
const { output } = await handleCriticalThreatElicitation(result.value, args.url);
|
|
130
|
+
return {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: 'text',
|
|
134
|
+
text: JSON.stringify(output, null, 2)
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
case 'visus_search': {
|
|
140
|
+
const result = await visusSearch(args);
|
|
141
|
+
if (!result.ok) {
|
|
142
|
+
throw new McpError(ErrorCode.InternalError, `visus_search failed: ${result.error.message}`);
|
|
143
|
+
}
|
|
144
|
+
// Handle HITL elicitation for CRITICAL threats
|
|
145
|
+
// For search, use the query as the "URL" in the elicitation message
|
|
146
|
+
const { output } = await handleCriticalThreatElicitation(result.value, `search: ${args.query}`);
|
|
147
|
+
return {
|
|
148
|
+
content: [
|
|
149
|
+
{
|
|
150
|
+
type: 'text',
|
|
151
|
+
text: JSON.stringify(output, null, 2)
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
default:
|
|
157
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
if (error instanceof McpError) {
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
/**
|
|
168
|
+
* Start the MCP server (stdio mode)
|
|
169
|
+
*/
|
|
170
|
+
async function startMcpServer() {
|
|
171
|
+
const transport = new StdioServerTransport();
|
|
172
|
+
// Connect server to transport
|
|
173
|
+
await server.connect(transport);
|
|
174
|
+
// Log startup to stderr (not stdout - MCP uses stdout)
|
|
175
|
+
console.error(JSON.stringify({
|
|
176
|
+
timestamp: new Date().toISOString(),
|
|
177
|
+
event: 'mcp_server_started',
|
|
178
|
+
name: 'visus-mcp',
|
|
179
|
+
version: '0.6.0',
|
|
180
|
+
tools: ['visus_fetch', 'visus_fetch_structured', 'visus_read', 'visus_search']
|
|
181
|
+
}));
|
|
182
|
+
// Graceful shutdown
|
|
183
|
+
process.on('SIGINT', async () => {
|
|
184
|
+
console.error(JSON.stringify({
|
|
185
|
+
timestamp: new Date().toISOString(),
|
|
186
|
+
event: 'mcp_server_shutdown'
|
|
187
|
+
}));
|
|
188
|
+
await closeBrowser();
|
|
189
|
+
process.exit(0);
|
|
190
|
+
});
|
|
191
|
+
process.on('SIGTERM', async () => {
|
|
192
|
+
console.error(JSON.stringify({
|
|
193
|
+
timestamp: new Date().toISOString(),
|
|
194
|
+
event: 'mcp_server_shutdown'
|
|
195
|
+
}));
|
|
196
|
+
await closeBrowser();
|
|
197
|
+
process.exit(0);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Main entry point - Dual-mode detection
|
|
202
|
+
*/
|
|
203
|
+
async function main() {
|
|
204
|
+
// Detect runtime environment
|
|
205
|
+
const runtime = detectRuntime();
|
|
206
|
+
logRuntimeConfig(runtime);
|
|
207
|
+
validateRuntime(runtime);
|
|
208
|
+
// Route to appropriate entry point
|
|
209
|
+
if (runtime.isStdio) {
|
|
210
|
+
// Open-source tier: stdio MCP server
|
|
211
|
+
await startMcpServer();
|
|
212
|
+
}
|
|
213
|
+
else if (runtime.isLambda) {
|
|
214
|
+
// Hosted tier: Lambda handler
|
|
215
|
+
// In Lambda mode, the handler is exported and invoked by AWS
|
|
216
|
+
// This code path is not executed; see lambda-handler.ts export below
|
|
217
|
+
console.error(JSON.stringify({
|
|
218
|
+
timestamp: new Date().toISOString(),
|
|
219
|
+
event: 'lambda_mode_detected',
|
|
220
|
+
message: 'Lambda handler will be invoked by AWS runtime'
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Export Lambda handler (for AWS deployment)
|
|
225
|
+
// This is only used when the file is imported as a module by Lambda runtime
|
|
226
|
+
export { handler } from './lambda-handler.js';
|
|
227
|
+
// Run stdio MCP server when executed directly (not in Lambda)
|
|
228
|
+
if (!process.env.AWS_LAMBDA_FUNCTION_NAME) {
|
|
229
|
+
main().catch((error) => {
|
|
230
|
+
console.error(JSON.stringify({
|
|
231
|
+
timestamp: new Date().toISOString(),
|
|
232
|
+
event: 'startup_error',
|
|
233
|
+
error: error instanceof Error ? error.message : String(error)
|
|
234
|
+
}));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Lambda Handler - Phase 2 Hosted Tier
|
|
3
|
+
*
|
|
4
|
+
* Provides RESTful API endpoint for Visus sanitization service
|
|
5
|
+
* Invoked via API Gateway → Lambda → DynamoDB audit logging
|
|
6
|
+
*
|
|
7
|
+
* SECURITY RULES (from CLAUDE.md):
|
|
8
|
+
* - No secrets in code (use Secrets Manager)
|
|
9
|
+
* - No wildcard IAM permissions
|
|
10
|
+
* - All user input sanitized
|
|
11
|
+
* - No cross-user data access
|
|
12
|
+
* - Reserved concurrent executions set
|
|
13
|
+
* - No plaintext logging of tokens/PII
|
|
14
|
+
*/
|
|
15
|
+
import type { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
|
16
|
+
/**
|
|
17
|
+
* Lambda handler for Visus API
|
|
18
|
+
*
|
|
19
|
+
* Routes:
|
|
20
|
+
* - POST /fetch → visus_fetch
|
|
21
|
+
* - POST /fetch-structured → visus_fetch_structured
|
|
22
|
+
*
|
|
23
|
+
* @param event API Gateway event
|
|
24
|
+
* @param context Lambda context
|
|
25
|
+
* @returns API Gateway response
|
|
26
|
+
*/
|
|
27
|
+
export declare function handler(event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult>;
|
|
28
|
+
//# sourceMappingURL=lambda-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda-handler.d.ts","sourceRoot":"","sources":["../src/lambda-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAsFvF;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,oBAAoB,EAC3B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,qBAAqB,CAAC,CAsNhC"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Lambda Handler - Phase 2 Hosted Tier
|
|
3
|
+
*
|
|
4
|
+
* Provides RESTful API endpoint for Visus sanitization service
|
|
5
|
+
* Invoked via API Gateway → Lambda → DynamoDB audit logging
|
|
6
|
+
*
|
|
7
|
+
* SECURITY RULES (from CLAUDE.md):
|
|
8
|
+
* - No secrets in code (use Secrets Manager)
|
|
9
|
+
* - No wildcard IAM permissions
|
|
10
|
+
* - All user input sanitized
|
|
11
|
+
* - No cross-user data access
|
|
12
|
+
* - Reserved concurrent executions set
|
|
13
|
+
* - No plaintext logging of tokens/PII
|
|
14
|
+
*/
|
|
15
|
+
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
16
|
+
import { DynamoDBDocumentClient, PutCommand } from '@aws-sdk/lib-dynamodb';
|
|
17
|
+
import { visusFetch } from './tools/fetch.js';
|
|
18
|
+
import { visusFetchStructured } from './tools/fetch-structured.js';
|
|
19
|
+
import { closeBrowser } from './browser/playwright-renderer.js';
|
|
20
|
+
// Initialize DynamoDB client
|
|
21
|
+
const ddbClient = new DynamoDBClient({});
|
|
22
|
+
const docClient = DynamoDBDocumentClient.from(ddbClient);
|
|
23
|
+
/**
|
|
24
|
+
* Fire-and-forget audit logging to DynamoDB
|
|
25
|
+
*
|
|
26
|
+
* Logs request metadata without blocking the response.
|
|
27
|
+
* Errors are logged but do not affect the API response.
|
|
28
|
+
*
|
|
29
|
+
* @param userId User ID from Cognito JWT
|
|
30
|
+
* @param requestId AWS request ID
|
|
31
|
+
* @param url URL being fetched
|
|
32
|
+
* @param endpoint API endpoint (/fetch or /fetch-structured)
|
|
33
|
+
* @param patternsDetected Sanitization patterns detected
|
|
34
|
+
* @param piiRedacted PII types redacted
|
|
35
|
+
*/
|
|
36
|
+
function logAuditEvent(userId, requestId, url, endpoint, patternsDetected, piiRedacted) {
|
|
37
|
+
const tableName = process.env.AUDIT_TABLE_NAME;
|
|
38
|
+
if (!tableName) {
|
|
39
|
+
console.error('AUDIT_TABLE_NAME not set - skipping audit logging');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const now = new Date();
|
|
43
|
+
const ttl = Math.floor(now.getTime() / 1000) + (30 * 24 * 60 * 60); // 30 days from now
|
|
44
|
+
const item = {
|
|
45
|
+
user_id: userId,
|
|
46
|
+
timestamp: now.toISOString(),
|
|
47
|
+
request_id: requestId,
|
|
48
|
+
url,
|
|
49
|
+
endpoint,
|
|
50
|
+
patterns_detected: patternsDetected,
|
|
51
|
+
pii_redacted: piiRedacted,
|
|
52
|
+
ttl, // Auto-delete after 30 days
|
|
53
|
+
};
|
|
54
|
+
// Fire-and-forget: do not await
|
|
55
|
+
docClient.send(new PutCommand({
|
|
56
|
+
TableName: tableName,
|
|
57
|
+
Item: item,
|
|
58
|
+
})).catch((error) => {
|
|
59
|
+
// Log error but do not throw (fire-and-forget pattern)
|
|
60
|
+
console.error(JSON.stringify({
|
|
61
|
+
timestamp: now.toISOString(),
|
|
62
|
+
event: 'audit_logging_failed',
|
|
63
|
+
error: error instanceof Error ? error.message : String(error),
|
|
64
|
+
request_id: requestId,
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Lambda handler for Visus API
|
|
70
|
+
*
|
|
71
|
+
* Routes:
|
|
72
|
+
* - POST /fetch → visus_fetch
|
|
73
|
+
* - POST /fetch-structured → visus_fetch_structured
|
|
74
|
+
*
|
|
75
|
+
* @param event API Gateway event
|
|
76
|
+
* @param context Lambda context
|
|
77
|
+
* @returns API Gateway response
|
|
78
|
+
*/
|
|
79
|
+
export async function handler(event, context) {
|
|
80
|
+
const requestId = context.awsRequestId;
|
|
81
|
+
// Log request to stderr
|
|
82
|
+
console.error(JSON.stringify({
|
|
83
|
+
timestamp: new Date().toISOString(),
|
|
84
|
+
event: 'lambda_invocation',
|
|
85
|
+
request_id: requestId,
|
|
86
|
+
path: event.path,
|
|
87
|
+
method: event.httpMethod,
|
|
88
|
+
source_ip: event.requestContext.identity.sourceIp,
|
|
89
|
+
user_agent: event.headers['User-Agent'] || event.headers['user-agent'],
|
|
90
|
+
}));
|
|
91
|
+
try {
|
|
92
|
+
// CORS headers for all responses (environment-variable-driven allowlist)
|
|
93
|
+
const allowedOrigins = (process.env.ALLOWED_ORIGINS || '*').split(',');
|
|
94
|
+
const origin = event.headers.origin || event.headers.Origin || '';
|
|
95
|
+
const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0] || '*';
|
|
96
|
+
const corsHeaders = {
|
|
97
|
+
'Access-Control-Allow-Origin': allowOrigin,
|
|
98
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
99
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
100
|
+
'Content-Type': 'application/json',
|
|
101
|
+
};
|
|
102
|
+
// Handle preflight OPTIONS request
|
|
103
|
+
if (event.httpMethod === 'OPTIONS') {
|
|
104
|
+
return {
|
|
105
|
+
statusCode: 200,
|
|
106
|
+
headers: corsHeaders,
|
|
107
|
+
body: '',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Health check endpoint (no auth required, allows GET and POST)
|
|
111
|
+
// SECURITY FIX (FINDING 2): Moved before POST-only validation to support standard GET health checks
|
|
112
|
+
if (event.path === '/health' || event.path === '/dev/health' || event.path === '/prod/health') {
|
|
113
|
+
return {
|
|
114
|
+
statusCode: 200,
|
|
115
|
+
headers: corsHeaders,
|
|
116
|
+
body: JSON.stringify({
|
|
117
|
+
status: 'healthy',
|
|
118
|
+
service: 'visus-mcp',
|
|
119
|
+
version: '0.3.1',
|
|
120
|
+
timestamp: new Date().toISOString(),
|
|
121
|
+
}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Only allow POST requests for protected endpoints
|
|
125
|
+
if (event.httpMethod !== 'POST') {
|
|
126
|
+
return {
|
|
127
|
+
statusCode: 405,
|
|
128
|
+
headers: corsHeaders,
|
|
129
|
+
body: JSON.stringify({ error: 'Method not allowed. Use POST.' }),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// Parse request body
|
|
133
|
+
let body;
|
|
134
|
+
try {
|
|
135
|
+
body = JSON.parse(event.body || '{}');
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
return {
|
|
139
|
+
statusCode: 400,
|
|
140
|
+
headers: corsHeaders,
|
|
141
|
+
body: JSON.stringify({ error: 'Invalid JSON in request body' }),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// SECURITY FIX (FINDING 1): Application-level authentication enforcement
|
|
145
|
+
// Extract user ID from Cognito authorizer
|
|
146
|
+
const userId = event.requestContext.authorizer?.claims?.sub;
|
|
147
|
+
// Require authentication for all protected endpoints (not already handled above)
|
|
148
|
+
if (!userId) {
|
|
149
|
+
console.error(JSON.stringify({
|
|
150
|
+
timestamp: new Date().toISOString(),
|
|
151
|
+
event: 'auth_required',
|
|
152
|
+
request_id: requestId,
|
|
153
|
+
path: event.path,
|
|
154
|
+
reason: 'Missing Cognito authorizer context - Lambda must be invoked via API Gateway',
|
|
155
|
+
}));
|
|
156
|
+
return {
|
|
157
|
+
statusCode: 401,
|
|
158
|
+
headers: corsHeaders,
|
|
159
|
+
body: JSON.stringify({
|
|
160
|
+
error: 'Unauthorized: Authentication required. This Lambda must be invoked via API Gateway with Cognito authorizer.',
|
|
161
|
+
}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// Route based on path
|
|
165
|
+
if (event.path === '/fetch' || event.path === '/dev/fetch' || event.path === '/prod/fetch') {
|
|
166
|
+
const fetchReq = body;
|
|
167
|
+
// Validate request
|
|
168
|
+
if (!fetchReq.url || typeof fetchReq.url !== 'string') {
|
|
169
|
+
return {
|
|
170
|
+
statusCode: 400,
|
|
171
|
+
headers: corsHeaders,
|
|
172
|
+
body: JSON.stringify({ error: 'Missing or invalid "url" field' }),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// Call visus_fetch
|
|
176
|
+
const result = await visusFetch(fetchReq);
|
|
177
|
+
if (!result.ok) {
|
|
178
|
+
return {
|
|
179
|
+
statusCode: 500,
|
|
180
|
+
headers: corsHeaders,
|
|
181
|
+
body: JSON.stringify({ error: result.error.message }),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// Fire-and-forget audit logging
|
|
185
|
+
logAuditEvent(userId, requestId, fetchReq.url, '/fetch', result.value.sanitization.patterns_detected, result.value.sanitization.pii_types_redacted);
|
|
186
|
+
return {
|
|
187
|
+
statusCode: 200,
|
|
188
|
+
headers: corsHeaders,
|
|
189
|
+
body: JSON.stringify(result.value),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (event.path === '/fetch-structured' || event.path === '/dev/fetch-structured' || event.path === '/prod/fetch-structured') {
|
|
193
|
+
const fetchReq = body;
|
|
194
|
+
// Validate request
|
|
195
|
+
if (!fetchReq.url || typeof fetchReq.url !== 'string') {
|
|
196
|
+
return {
|
|
197
|
+
statusCode: 400,
|
|
198
|
+
headers: corsHeaders,
|
|
199
|
+
body: JSON.stringify({ error: 'Missing or invalid "url" field' }),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (!fetchReq.schema || typeof fetchReq.schema !== 'object') {
|
|
203
|
+
return {
|
|
204
|
+
statusCode: 400,
|
|
205
|
+
headers: corsHeaders,
|
|
206
|
+
body: JSON.stringify({ error: 'Missing or invalid "schema" field' }),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// Call visus_fetch_structured
|
|
210
|
+
const result = await visusFetchStructured(fetchReq);
|
|
211
|
+
if (!result.ok) {
|
|
212
|
+
return {
|
|
213
|
+
statusCode: 500,
|
|
214
|
+
headers: corsHeaders,
|
|
215
|
+
body: JSON.stringify({ error: result.error.message }),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
// Fire-and-forget audit logging
|
|
219
|
+
logAuditEvent(userId, requestId, fetchReq.url, '/fetch-structured', result.value.sanitization.patterns_detected, result.value.sanitization.pii_types_redacted);
|
|
220
|
+
return {
|
|
221
|
+
statusCode: 200,
|
|
222
|
+
headers: corsHeaders,
|
|
223
|
+
body: JSON.stringify(result.value),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
// Unknown path
|
|
227
|
+
return {
|
|
228
|
+
statusCode: 404,
|
|
229
|
+
headers: corsHeaders,
|
|
230
|
+
body: JSON.stringify({ error: 'Not found. Use /fetch or /fetch-structured' }),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
// Log error to stderr (CloudWatch Logs)
|
|
235
|
+
console.error(JSON.stringify({
|
|
236
|
+
timestamp: new Date().toISOString(),
|
|
237
|
+
event: 'lambda_error',
|
|
238
|
+
request_id: requestId,
|
|
239
|
+
error: error instanceof Error ? error.message : String(error),
|
|
240
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
241
|
+
}));
|
|
242
|
+
return {
|
|
243
|
+
statusCode: 500,
|
|
244
|
+
headers: {
|
|
245
|
+
'Content-Type': 'application/json',
|
|
246
|
+
'Access-Control-Allow-Origin': '*',
|
|
247
|
+
},
|
|
248
|
+
body: JSON.stringify({ error: 'Internal server error' }),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
// Close browser to free resources
|
|
253
|
+
// Lambda containers are reused, but we clean up after each invocation
|
|
254
|
+
await closeBrowser();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=lambda-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda-handler.js","sourceRoot":"","sources":["../src/lambda-handler.ts"],"names":[],"mappings":"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"}
|