@bryan-thompson/inspector-assessment-client 1.6.0 → 1.7.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/assets/{OAuthCallback-ZcXdfhZQ.js → OAuthCallback-cGhwkoyY.js} +1 -1
- package/dist/assets/{OAuthDebugCallback-xt1SlIHS.js → OAuthDebugCallback-2rmUqser.js} +1 -1
- package/dist/assets/{index-B3lTiDVe.js → index-BnFixpvH.js} +4 -4
- package/dist/index.html +1 -1
- package/lib/lib/assessmentTypes.d.ts +670 -0
- package/lib/lib/assessmentTypes.d.ts.map +1 -0
- package/lib/lib/assessmentTypes.js +220 -0
- package/lib/lib/aupPatterns.d.ts +63 -0
- package/lib/lib/aupPatterns.d.ts.map +1 -0
- package/lib/lib/aupPatterns.js +344 -0
- package/lib/lib/prohibitedLibraries.d.ts +76 -0
- package/lib/lib/prohibitedLibraries.d.ts.map +1 -0
- package/lib/lib/prohibitedLibraries.js +364 -0
- package/lib/lib/securityPatterns.d.ts +64 -0
- package/lib/lib/securityPatterns.d.ts.map +1 -0
- package/lib/lib/securityPatterns.js +453 -0
- package/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
- package/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
- package/lib/services/assessment/AssessmentOrchestrator.js +418 -0
- package/lib/services/assessment/ResponseValidator.d.ts +69 -0
- package/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
- package/lib/services/assessment/ResponseValidator.js +1038 -0
- package/lib/services/assessment/TestDataGenerator.d.ts +86 -0
- package/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
- package/lib/services/assessment/TestDataGenerator.js +669 -0
- package/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
- package/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
- package/lib/services/assessment/TestScenarioEngine.js +505 -0
- package/lib/services/assessment/ToolClassifier.d.ts +61 -0
- package/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
- package/lib/services/assessment/ToolClassifier.js +349 -0
- package/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
- package/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
- package/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
- package/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
- package/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
- package/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
- package/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/BaseAssessor.js +171 -0
- package/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
- package/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
- package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
- package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
- package/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
- package/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
- package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
- package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
- package/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
- package/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
- package/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
- package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
- package/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
- package/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
- package/lib/services/assessment/modules/index.d.ts +33 -0
- package/lib/services/assessment/modules/index.d.ts.map +1 -0
- package/lib/services/assessment/modules/index.js +35 -0
- package/package.json +15 -3
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUP Compliance Assessor
|
|
3
|
+
* Scans MCP server for Acceptable Use Policy violations
|
|
4
|
+
*
|
|
5
|
+
* Checks:
|
|
6
|
+
* - Tool names and descriptions
|
|
7
|
+
* - README content
|
|
8
|
+
* - Source code (if sourceCodePath provided)
|
|
9
|
+
*
|
|
10
|
+
* Based on Anthropic's 14 AUP categories (A-N)
|
|
11
|
+
*
|
|
12
|
+
* Supports optional Claude Code integration for semantic analysis
|
|
13
|
+
* to reduce false positives (e.g., security tools, disclaimers).
|
|
14
|
+
*/
|
|
15
|
+
import { BaseAssessor } from "./BaseAssessor.js";
|
|
16
|
+
import { checkTextForAUPViolations, checkTextForHighRiskDomains, } from "../../../lib/aupPatterns.js";
|
|
17
|
+
export class AUPComplianceAssessor extends BaseAssessor {
|
|
18
|
+
// Optional Claude Code bridge for semantic analysis
|
|
19
|
+
claudeBridge = null;
|
|
20
|
+
/**
|
|
21
|
+
* Set the Claude Code bridge for semantic violation analysis
|
|
22
|
+
*/
|
|
23
|
+
setClaudeBridge(bridge) {
|
|
24
|
+
this.claudeBridge = bridge;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if Claude semantic analysis is enabled
|
|
28
|
+
*/
|
|
29
|
+
isSemanticAnalysisEnabled() {
|
|
30
|
+
return (this.claudeBridge !== null &&
|
|
31
|
+
this.claudeBridge.isFeatureEnabled("aupSemanticAnalysis"));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Run AUP compliance assessment
|
|
35
|
+
* If Claude semantic analysis is enabled, violations are verified to reduce false positives.
|
|
36
|
+
*/
|
|
37
|
+
async assess(context) {
|
|
38
|
+
this.log("Starting AUP compliance assessment");
|
|
39
|
+
this.testCount = 0;
|
|
40
|
+
const violations = [];
|
|
41
|
+
const highRiskDomains = [];
|
|
42
|
+
const scannedLocations = {
|
|
43
|
+
toolNames: false,
|
|
44
|
+
toolDescriptions: false,
|
|
45
|
+
readme: false,
|
|
46
|
+
sourceCode: false,
|
|
47
|
+
};
|
|
48
|
+
// Build a map of tool descriptions for semantic analysis context
|
|
49
|
+
const toolDescriptionMap = new Map();
|
|
50
|
+
for (const tool of context.tools) {
|
|
51
|
+
toolDescriptionMap.set(tool.name, tool.description || "");
|
|
52
|
+
}
|
|
53
|
+
// Scan tool names
|
|
54
|
+
this.log("Scanning tool names...");
|
|
55
|
+
scannedLocations.toolNames = true;
|
|
56
|
+
for (const tool of context.tools) {
|
|
57
|
+
this.testCount++;
|
|
58
|
+
const toolViolations = this.scanToolName(tool.name);
|
|
59
|
+
violations.push(...toolViolations);
|
|
60
|
+
// Check for high-risk domains
|
|
61
|
+
const domains = checkTextForHighRiskDomains(tool.name);
|
|
62
|
+
for (const domain of domains) {
|
|
63
|
+
if (!highRiskDomains.includes(domain.domain)) {
|
|
64
|
+
highRiskDomains.push(domain.domain);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Scan tool descriptions
|
|
69
|
+
this.log("Scanning tool descriptions...");
|
|
70
|
+
scannedLocations.toolDescriptions = true;
|
|
71
|
+
for (const tool of context.tools) {
|
|
72
|
+
if (tool.description) {
|
|
73
|
+
this.testCount++;
|
|
74
|
+
const descViolations = this.scanToolDescription(tool.name, tool.description);
|
|
75
|
+
violations.push(...descViolations);
|
|
76
|
+
const domains = checkTextForHighRiskDomains(tool.description);
|
|
77
|
+
for (const domain of domains) {
|
|
78
|
+
if (!highRiskDomains.includes(domain.domain)) {
|
|
79
|
+
highRiskDomains.push(domain.domain);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Scan README content
|
|
85
|
+
if (context.readmeContent) {
|
|
86
|
+
this.log("Scanning README content...");
|
|
87
|
+
scannedLocations.readme = true;
|
|
88
|
+
this.testCount++;
|
|
89
|
+
const readmeViolations = this.scanReadme(context.readmeContent);
|
|
90
|
+
violations.push(...readmeViolations);
|
|
91
|
+
const domains = checkTextForHighRiskDomains(context.readmeContent);
|
|
92
|
+
for (const domain of domains) {
|
|
93
|
+
if (!highRiskDomains.includes(domain.domain)) {
|
|
94
|
+
highRiskDomains.push(domain.domain);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Scan source code if available
|
|
99
|
+
if (context.sourceCodeFiles && context.config.enableSourceCodeAnalysis) {
|
|
100
|
+
this.log("Scanning source code files...");
|
|
101
|
+
scannedLocations.sourceCode = true;
|
|
102
|
+
for (const [filePath, content] of context.sourceCodeFiles) {
|
|
103
|
+
// Skip non-relevant files
|
|
104
|
+
if (this.shouldSkipFile(filePath))
|
|
105
|
+
continue;
|
|
106
|
+
this.testCount++;
|
|
107
|
+
const sourceViolations = this.scanSourceFile(filePath, content);
|
|
108
|
+
violations.push(...sourceViolations);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// If Claude semantic analysis is enabled, verify violations to reduce false positives
|
|
112
|
+
if (this.isSemanticAnalysisEnabled() && violations.length > 0) {
|
|
113
|
+
this.log(`Running semantic analysis on ${violations.length} potential violations...`);
|
|
114
|
+
return await this.runSemanticAnalysis(violations, highRiskDomains, scannedLocations, toolDescriptionMap);
|
|
115
|
+
}
|
|
116
|
+
// Standard assessment without semantic analysis
|
|
117
|
+
const status = this.determineAUPStatus(violations);
|
|
118
|
+
const explanation = this.generateExplanation(violations, highRiskDomains, scannedLocations);
|
|
119
|
+
const recommendations = this.generateRecommendations(violations, highRiskDomains);
|
|
120
|
+
this.log(`Assessment complete: ${violations.length} violations found, ${highRiskDomains.length} high-risk domains`);
|
|
121
|
+
return {
|
|
122
|
+
violations,
|
|
123
|
+
highRiskDomains,
|
|
124
|
+
scannedLocations,
|
|
125
|
+
status,
|
|
126
|
+
explanation,
|
|
127
|
+
recommendations,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Run Claude semantic analysis on flagged violations
|
|
132
|
+
* Separates confirmed violations from likely false positives
|
|
133
|
+
*/
|
|
134
|
+
async runSemanticAnalysis(violations, highRiskDomains, scannedLocations, toolDescriptionMap) {
|
|
135
|
+
const confirmedViolations = [];
|
|
136
|
+
const flaggedForReview = [];
|
|
137
|
+
let falsePositivesFiltered = 0;
|
|
138
|
+
// Analyze each violation with Claude
|
|
139
|
+
for (const violation of violations) {
|
|
140
|
+
try {
|
|
141
|
+
// Get tool description for context
|
|
142
|
+
const toolDescription = violation.location === "tool_name" ||
|
|
143
|
+
violation.location === "tool_description"
|
|
144
|
+
? toolDescriptionMap.get(violation.matchedText.split(" ")[0]) || ""
|
|
145
|
+
: "";
|
|
146
|
+
const analysis = await this.claudeBridge.analyzeAUPViolation(violation.matchedText, {
|
|
147
|
+
toolName: violation.location === "tool_name"
|
|
148
|
+
? violation.matchedText
|
|
149
|
+
: "unknown",
|
|
150
|
+
toolDescription,
|
|
151
|
+
category: violation.category,
|
|
152
|
+
categoryName: violation.categoryName,
|
|
153
|
+
location: violation.location,
|
|
154
|
+
});
|
|
155
|
+
// Handle null result (Claude unavailable or error)
|
|
156
|
+
if (!analysis) {
|
|
157
|
+
flaggedForReview.push({
|
|
158
|
+
...violation,
|
|
159
|
+
semanticAnalysis: {
|
|
160
|
+
isConfirmedViolation: true,
|
|
161
|
+
confidence: 50,
|
|
162
|
+
reasoning: "Claude analysis unavailable. Flagged for manual review.",
|
|
163
|
+
source: "pattern-only",
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const enhancedViolation = {
|
|
169
|
+
...violation,
|
|
170
|
+
semanticAnalysis: {
|
|
171
|
+
isConfirmedViolation: analysis.isViolation,
|
|
172
|
+
confidence: analysis.confidence,
|
|
173
|
+
reasoning: analysis.reasoning,
|
|
174
|
+
source: "claude-verified",
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
// High confidence confirmed violations
|
|
178
|
+
if (analysis.isViolation && analysis.confidence >= 70) {
|
|
179
|
+
confirmedViolations.push(enhancedViolation);
|
|
180
|
+
}
|
|
181
|
+
// Uncertain - flag for human review
|
|
182
|
+
else if (analysis.isViolation || analysis.confidence >= 40) {
|
|
183
|
+
flaggedForReview.push(enhancedViolation);
|
|
184
|
+
}
|
|
185
|
+
// Low confidence - likely false positive
|
|
186
|
+
else {
|
|
187
|
+
falsePositivesFiltered++;
|
|
188
|
+
this.log(`Filtered likely false positive: "${violation.matchedText}" - ${analysis.reasoning}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
// On analysis error, conservatively add to flagged for review
|
|
193
|
+
flaggedForReview.push({
|
|
194
|
+
...violation,
|
|
195
|
+
semanticAnalysis: {
|
|
196
|
+
isConfirmedViolation: true,
|
|
197
|
+
confidence: 50,
|
|
198
|
+
reasoning: `Analysis error: ${error}. Flagged for manual review.`,
|
|
199
|
+
source: "pattern-only",
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Determine status based on confirmed violations only
|
|
205
|
+
const status = this.determineAUPStatus(confirmedViolations);
|
|
206
|
+
const explanation = this.generateSemanticExplanation(confirmedViolations, flaggedForReview, falsePositivesFiltered, highRiskDomains, scannedLocations);
|
|
207
|
+
const recommendations = this.generateSemanticRecommendations(confirmedViolations, flaggedForReview, highRiskDomains);
|
|
208
|
+
this.log(`Semantic analysis complete: ${confirmedViolations.length} confirmed, ${flaggedForReview.length} flagged, ${falsePositivesFiltered} filtered`);
|
|
209
|
+
return {
|
|
210
|
+
violations: [...confirmedViolations, ...flaggedForReview],
|
|
211
|
+
confirmedViolations,
|
|
212
|
+
flaggedForReview,
|
|
213
|
+
highRiskDomains,
|
|
214
|
+
scannedLocations,
|
|
215
|
+
status,
|
|
216
|
+
explanation,
|
|
217
|
+
recommendations,
|
|
218
|
+
semanticAnalysisEnabled: true,
|
|
219
|
+
falsePositivesFiltered,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Generate explanation for semantic analysis results
|
|
224
|
+
*/
|
|
225
|
+
generateSemanticExplanation(confirmed, flagged, filtered, highRiskDomains, scannedLocations) {
|
|
226
|
+
const parts = [];
|
|
227
|
+
parts.push(`Semantic analysis enabled (Claude-verified). ${filtered} likely false positives filtered.`);
|
|
228
|
+
if (confirmed.length === 0 && flagged.length === 0) {
|
|
229
|
+
parts.push("No AUP violations confirmed after semantic analysis.");
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
if (confirmed.length > 0) {
|
|
233
|
+
const criticalCount = confirmed.filter((v) => v.severity === "CRITICAL").length;
|
|
234
|
+
const highCount = confirmed.filter((v) => v.severity === "HIGH").length;
|
|
235
|
+
if (criticalCount > 0) {
|
|
236
|
+
parts.push(`CRITICAL: ${criticalCount} confirmed critical violation(s).`);
|
|
237
|
+
}
|
|
238
|
+
if (highCount > 0) {
|
|
239
|
+
parts.push(`HIGH: ${highCount} confirmed high-severity violation(s).`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (flagged.length > 0) {
|
|
243
|
+
parts.push(`${flagged.length} item(s) flagged for manual review.`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (highRiskDomains.length > 0) {
|
|
247
|
+
parts.push(`High-risk domains: ${highRiskDomains.join(", ")}. Additional review recommended.`);
|
|
248
|
+
}
|
|
249
|
+
const scannedList = Object.entries(scannedLocations)
|
|
250
|
+
.filter(([, scanned]) => scanned)
|
|
251
|
+
.map(([location]) => location);
|
|
252
|
+
parts.push(`Scanned: ${scannedList.join(", ")}.`);
|
|
253
|
+
return parts.join(" ");
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Generate recommendations for semantic analysis results
|
|
257
|
+
*/
|
|
258
|
+
generateSemanticRecommendations(confirmed, flagged, highRiskDomains) {
|
|
259
|
+
const recommendations = [];
|
|
260
|
+
// Confirmed violations
|
|
261
|
+
if (confirmed.length > 0) {
|
|
262
|
+
const criticalViolations = confirmed.filter((v) => v.severity === "CRITICAL");
|
|
263
|
+
if (criticalViolations.length > 0) {
|
|
264
|
+
recommendations.push("CRITICAL (Claude-verified): This MCP server contains content that violates Anthropic's Acceptable Use Policy:");
|
|
265
|
+
for (const v of criticalViolations) {
|
|
266
|
+
recommendations.push(`- Category ${v.category} (${v.categoryName}): "${v.matchedText}" - ${v.semanticAnalysis?.reasoning || ""}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const highViolations = confirmed.filter((v) => v.severity === "HIGH");
|
|
270
|
+
if (highViolations.length > 0) {
|
|
271
|
+
recommendations.push("HIGH (Claude-verified): Confirmed AUP violations:");
|
|
272
|
+
for (const v of highViolations) {
|
|
273
|
+
recommendations.push(`- Category ${v.category} (${v.categoryName}): "${v.matchedText}" - ${v.semanticAnalysis?.reasoning || ""}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// Flagged for review
|
|
278
|
+
if (flagged.length > 0) {
|
|
279
|
+
recommendations.push("MANUAL REVIEW REQUIRED: The following items need human verification:");
|
|
280
|
+
for (const v of flagged) {
|
|
281
|
+
recommendations.push(`- Category ${v.category}: "${v.matchedText}" (${v.semanticAnalysis?.confidence || 50}% confidence) - ${v.semanticAnalysis?.reasoning || ""}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// High-risk domains
|
|
285
|
+
if (highRiskDomains.length > 0) {
|
|
286
|
+
recommendations.push(`This server operates in high-risk domain(s): ${highRiskDomains.join(", ")}. Ensure appropriate safeguards.`);
|
|
287
|
+
}
|
|
288
|
+
// If no issues
|
|
289
|
+
if (recommendations.length === 0) {
|
|
290
|
+
recommendations.push("No AUP compliance issues confirmed after semantic analysis. Server appears compliant with Anthropic's Acceptable Use Policy.");
|
|
291
|
+
}
|
|
292
|
+
return recommendations;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Scan a tool name for AUP violations
|
|
296
|
+
*/
|
|
297
|
+
scanToolName(toolName) {
|
|
298
|
+
const matches = checkTextForAUPViolations(toolName);
|
|
299
|
+
return matches.map((match) => ({
|
|
300
|
+
category: match.category,
|
|
301
|
+
categoryName: match.categoryName,
|
|
302
|
+
severity: match.severity,
|
|
303
|
+
pattern: match.matchedPattern,
|
|
304
|
+
matchedText: match.matchedText,
|
|
305
|
+
location: "tool_name",
|
|
306
|
+
confidence: "high",
|
|
307
|
+
requiresHumanReview: match.requiresHumanReview,
|
|
308
|
+
reviewGuidance: match.reviewGuidance,
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Scan a tool description for AUP violations
|
|
313
|
+
*/
|
|
314
|
+
scanToolDescription(toolName, description) {
|
|
315
|
+
const matches = checkTextForAUPViolations(description);
|
|
316
|
+
return matches.map((match) => ({
|
|
317
|
+
category: match.category,
|
|
318
|
+
categoryName: match.categoryName,
|
|
319
|
+
severity: match.severity,
|
|
320
|
+
pattern: match.matchedPattern,
|
|
321
|
+
matchedText: match.matchedText,
|
|
322
|
+
location: "tool_description",
|
|
323
|
+
confidence: "medium", // Descriptions can have legitimate context
|
|
324
|
+
requiresHumanReview: match.requiresHumanReview,
|
|
325
|
+
reviewGuidance: `Tool: ${toolName}. ${match.reviewGuidance || ""}`,
|
|
326
|
+
}));
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Scan README content for AUP violations
|
|
330
|
+
*/
|
|
331
|
+
scanReadme(content) {
|
|
332
|
+
const matches = checkTextForAUPViolations(content);
|
|
333
|
+
return matches.map((match) => ({
|
|
334
|
+
category: match.category,
|
|
335
|
+
categoryName: match.categoryName,
|
|
336
|
+
severity: match.severity,
|
|
337
|
+
pattern: match.matchedPattern,
|
|
338
|
+
matchedText: match.matchedText,
|
|
339
|
+
location: "readme",
|
|
340
|
+
confidence: "low", // READMEs often discuss what NOT to do
|
|
341
|
+
requiresHumanReview: true,
|
|
342
|
+
reviewGuidance: `README match - verify context. ${match.reviewGuidance || ""}`,
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Scan a source file for AUP violations
|
|
347
|
+
*/
|
|
348
|
+
scanSourceFile(filePath, content) {
|
|
349
|
+
const violations = [];
|
|
350
|
+
const lines = content.split("\n");
|
|
351
|
+
for (let i = 0; i < lines.length; i++) {
|
|
352
|
+
const line = lines[i];
|
|
353
|
+
const matches = checkTextForAUPViolations(line);
|
|
354
|
+
for (const match of matches) {
|
|
355
|
+
violations.push({
|
|
356
|
+
category: match.category,
|
|
357
|
+
categoryName: match.categoryName,
|
|
358
|
+
severity: match.severity,
|
|
359
|
+
pattern: match.matchedPattern,
|
|
360
|
+
matchedText: match.matchedText,
|
|
361
|
+
location: "source_code",
|
|
362
|
+
filePath,
|
|
363
|
+
lineNumber: i + 1,
|
|
364
|
+
confidence: "medium",
|
|
365
|
+
requiresHumanReview: match.requiresHumanReview,
|
|
366
|
+
reviewGuidance: match.reviewGuidance,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return violations;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Check if a file should be skipped for AUP scanning
|
|
374
|
+
*/
|
|
375
|
+
shouldSkipFile(filePath) {
|
|
376
|
+
const skipPatterns = [
|
|
377
|
+
/node_modules/,
|
|
378
|
+
/\.test\.(ts|js|tsx|jsx)$/,
|
|
379
|
+
/\.spec\.(ts|js|tsx|jsx)$/,
|
|
380
|
+
/\.d\.ts$/,
|
|
381
|
+
/package-lock\.json$/,
|
|
382
|
+
/yarn\.lock$/,
|
|
383
|
+
/\.map$/,
|
|
384
|
+
/\.min\.(js|css)$/,
|
|
385
|
+
];
|
|
386
|
+
return skipPatterns.some((pattern) => pattern.test(filePath));
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Determine overall status based on violations
|
|
390
|
+
*/
|
|
391
|
+
determineAUPStatus(violations) {
|
|
392
|
+
// CRITICAL violations = automatic FAIL
|
|
393
|
+
const criticalViolations = violations.filter((v) => v.severity === "CRITICAL");
|
|
394
|
+
if (criticalViolations.length > 0) {
|
|
395
|
+
return "FAIL";
|
|
396
|
+
}
|
|
397
|
+
// HIGH violations = FAIL unless all low confidence
|
|
398
|
+
const highViolations = violations.filter((v) => v.severity === "HIGH");
|
|
399
|
+
const highConfidenceHigh = highViolations.filter((v) => v.confidence === "high" || v.confidence === "medium");
|
|
400
|
+
if (highConfidenceHigh.length > 0) {
|
|
401
|
+
return "FAIL";
|
|
402
|
+
}
|
|
403
|
+
// MEDIUM/FLAG violations = NEED_MORE_INFO
|
|
404
|
+
if (violations.length > 0) {
|
|
405
|
+
return "NEED_MORE_INFO";
|
|
406
|
+
}
|
|
407
|
+
return "PASS";
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Generate explanation text
|
|
411
|
+
*/
|
|
412
|
+
generateExplanation(violations, highRiskDomains, scannedLocations) {
|
|
413
|
+
const parts = [];
|
|
414
|
+
// Summary
|
|
415
|
+
if (violations.length === 0 && highRiskDomains.length === 0) {
|
|
416
|
+
parts.push("No AUP violations detected.");
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const criticalCount = violations.filter((v) => v.severity === "CRITICAL").length;
|
|
420
|
+
const highCount = violations.filter((v) => v.severity === "HIGH").length;
|
|
421
|
+
const mediumCount = violations.filter((v) => v.severity === "MEDIUM").length;
|
|
422
|
+
if (criticalCount > 0) {
|
|
423
|
+
parts.push(`CRITICAL: ${criticalCount} critical AUP violation(s) detected that require immediate review.`);
|
|
424
|
+
}
|
|
425
|
+
if (highCount > 0) {
|
|
426
|
+
parts.push(`HIGH: ${highCount} high-severity violation(s) detected.`);
|
|
427
|
+
}
|
|
428
|
+
if (mediumCount > 0) {
|
|
429
|
+
parts.push(`MEDIUM: ${mediumCount} medium-severity item(s) flagged for review.`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// High-risk domains
|
|
433
|
+
if (highRiskDomains.length > 0) {
|
|
434
|
+
parts.push(`High-risk domains detected: ${highRiskDomains.join(", ")}. Additional review recommended.`);
|
|
435
|
+
}
|
|
436
|
+
// Coverage
|
|
437
|
+
const scannedList = Object.entries(scannedLocations)
|
|
438
|
+
.filter(([, scanned]) => scanned)
|
|
439
|
+
.map(([location]) => location);
|
|
440
|
+
parts.push(`Scanned: ${scannedList.join(", ")}.`);
|
|
441
|
+
return parts.join(" ");
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Generate recommendations
|
|
445
|
+
*/
|
|
446
|
+
generateRecommendations(violations, highRiskDomains) {
|
|
447
|
+
const recommendations = [];
|
|
448
|
+
// Critical violations
|
|
449
|
+
const criticalViolations = violations.filter((v) => v.severity === "CRITICAL");
|
|
450
|
+
if (criticalViolations.length > 0) {
|
|
451
|
+
recommendations.push("CRITICAL: This MCP server contains content that violates Anthropic's Acceptable Use Policy and cannot be approved for the directory.");
|
|
452
|
+
for (const v of criticalViolations) {
|
|
453
|
+
recommendations.push(`- Category ${v.category} (${v.categoryName}): "${v.matchedText}" in ${v.location}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// High violations
|
|
457
|
+
const highViolations = violations.filter((v) => v.severity === "HIGH");
|
|
458
|
+
if (highViolations.length > 0) {
|
|
459
|
+
recommendations.push("HIGH: Review the following items for potential AUP violations:");
|
|
460
|
+
for (const v of highViolations) {
|
|
461
|
+
recommendations.push(`- Category ${v.category} (${v.categoryName}): "${v.matchedText}" in ${v.location}`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
// High-risk domains
|
|
465
|
+
if (highRiskDomains.length > 0) {
|
|
466
|
+
recommendations.push(`This server operates in high-risk domain(s): ${highRiskDomains.join(", ")}. Ensure appropriate safeguards and human oversight are in place.`);
|
|
467
|
+
}
|
|
468
|
+
// If no issues
|
|
469
|
+
if (recommendations.length === 0) {
|
|
470
|
+
recommendations.push("No AUP compliance issues detected. Server appears compliant with Anthropic's Acceptable Use Policy.");
|
|
471
|
+
}
|
|
472
|
+
return recommendations;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Assessor Class
|
|
3
|
+
* Provides common functionality for all assessment modules
|
|
4
|
+
*/
|
|
5
|
+
import { AssessmentConfiguration, AssessmentStatus } from "../../../lib/assessmentTypes.js";
|
|
6
|
+
import { AssessmentContext } from "../AssessmentOrchestrator.js";
|
|
7
|
+
export declare abstract class BaseAssessor {
|
|
8
|
+
protected config: AssessmentConfiguration;
|
|
9
|
+
protected testCount: number;
|
|
10
|
+
constructor(config: AssessmentConfiguration);
|
|
11
|
+
/**
|
|
12
|
+
* Abstract method that each assessor must implement
|
|
13
|
+
*/
|
|
14
|
+
abstract assess(context: AssessmentContext): Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* Common method to determine status based on pass rate
|
|
17
|
+
*/
|
|
18
|
+
protected determineStatus(passed: number, total: number, threshold?: number): AssessmentStatus;
|
|
19
|
+
/**
|
|
20
|
+
* Log assessment progress
|
|
21
|
+
*/
|
|
22
|
+
protected log(message: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Log error
|
|
25
|
+
*/
|
|
26
|
+
protected logError(message: string, error?: any): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get test count for this assessor
|
|
29
|
+
*/
|
|
30
|
+
getTestCount(): number;
|
|
31
|
+
/**
|
|
32
|
+
* Reset test count
|
|
33
|
+
*/
|
|
34
|
+
resetTestCount(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a feature is enabled in configuration
|
|
37
|
+
*/
|
|
38
|
+
protected isFeatureEnabled(feature: keyof AssessmentConfiguration["assessmentCategories"]): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Sleep for specified milliseconds (useful for rate limiting)
|
|
41
|
+
*/
|
|
42
|
+
protected sleep(ms: number): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Execute with timeout
|
|
45
|
+
*/
|
|
46
|
+
protected executeWithTimeout<T>(promise: Promise<T>, timeoutMs?: number): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Safe JSON parse with error handling
|
|
49
|
+
*/
|
|
50
|
+
protected safeJsonParse(text: string): any;
|
|
51
|
+
/**
|
|
52
|
+
* Extract error message from various error types
|
|
53
|
+
*/
|
|
54
|
+
protected extractErrorMessage(error: any): string;
|
|
55
|
+
/**
|
|
56
|
+
* Check if a response indicates an error
|
|
57
|
+
* Handles various MCP response formats
|
|
58
|
+
*
|
|
59
|
+
* @param response - The response to check
|
|
60
|
+
* @param strictMode - If true, only check explicit error indicators (default: false)
|
|
61
|
+
*/
|
|
62
|
+
protected isErrorResponse(response: any, strictMode?: boolean): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Extract error information from a response
|
|
65
|
+
*/
|
|
66
|
+
protected extractErrorInfo(response: any): {
|
|
67
|
+
code?: string | number;
|
|
68
|
+
message?: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=BaseAssessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/BaseAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,8BAAsB,YAAY;IAChC,SAAS,CAAC,MAAM,EAAE,uBAAuB,CAAC;IAC1C,SAAS,CAAC,SAAS,EAAE,MAAM,CAAK;gBAEpB,MAAM,EAAE,uBAAuB;IAI3C;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC;IAEzD;;OAEG;IACH,SAAS,CAAC,eAAe,CACvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAY,GACtB,gBAAgB;IAUnB;;OAEG;IACH,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI;IAItD;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;OAEG;IACH,SAAS,CAAC,gBAAgB,CACxB,OAAO,EAAE,MAAM,uBAAuB,CAAC,sBAAsB,CAAC,GAC7D,OAAO;IAIV;;OAEG;cACa,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD;;OAEG;cACa,kBAAkB,CAAC,CAAC,EAClC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,GAAE,MAAgC,GAC1C,OAAO,CAAC,CAAC,CAAC;IAWb;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG;IAS1C;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM;IAejD;;;;;;OAMG;IACH,SAAS,CAAC,eAAe,CACvB,QAAQ,EAAE,GAAG,EACb,UAAU,GAAE,OAAe,GAC1B,OAAO;IA8CV;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,GAAG;QACzC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;CAqBF"}
|