@bryan-thompson/inspector-assessment-client 1.35.2 → 1.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/assets/{OAuthCallback-jfmizOMH.js → OAuthCallback-Cfp3Vzdz.js} +1 -1
  2. package/dist/assets/{OAuthDebugCallback-bU5kKvnt.js → OAuthDebugCallback-7BLaxlcq.js} +1 -1
  3. package/dist/assets/{index-Ce63ds7G.js → index-B21S7_ML.js} +4 -4
  4. package/dist/index.html +1 -1
  5. package/lib/lib/assessment/coreTypes.d.ts +23 -0
  6. package/lib/lib/assessment/coreTypes.d.ts.map +1 -1
  7. package/lib/lib/assessment/extendedTypes.d.ts +49 -2
  8. package/lib/lib/assessment/extendedTypes.d.ts.map +1 -1
  9. package/lib/lib/assessment/jsonlEventSchemas.d.ts +4 -4
  10. package/lib/lib/assessment/resultTypes.d.ts +32 -1
  11. package/lib/lib/assessment/resultTypes.d.ts.map +1 -1
  12. package/lib/lib/aupPatterns.d.ts +50 -0
  13. package/lib/lib/aupPatterns.d.ts.map +1 -1
  14. package/lib/lib/aupPatterns.js +140 -0
  15. package/lib/lib/moduleScoring.d.ts.map +1 -1
  16. package/lib/lib/moduleScoring.js +39 -2
  17. package/lib/lib/securityPatterns.d.ts.map +1 -1
  18. package/lib/lib/securityPatterns.js +92 -0
  19. package/lib/services/assessment/modules/DeveloperExperienceAssessor.d.ts +26 -1
  20. package/lib/services/assessment/modules/DeveloperExperienceAssessor.d.ts.map +1 -1
  21. package/lib/services/assessment/modules/DeveloperExperienceAssessor.js +160 -1
  22. package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -1
  23. package/lib/services/assessment/modules/ErrorHandlingAssessor.js +15 -0
  24. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +32 -0
  25. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -1
  26. package/lib/services/assessment/modules/ManifestValidationAssessor.js +218 -20
  27. package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +5 -0
  28. package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -1
  29. package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +29 -0
  30. package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
  31. package/lib/services/assessment/modules/SecurityAssessor.js +13 -0
  32. package/lib/services/assessment/modules/annotations/AlignmentChecker.d.ts +7 -2
  33. package/lib/services/assessment/modules/annotations/AlignmentChecker.d.ts.map +1 -1
  34. package/lib/services/assessment/modules/annotations/AlignmentChecker.js +116 -18
  35. package/lib/services/assessment/modules/annotations/index.d.ts +1 -1
  36. package/lib/services/assessment/modules/annotations/index.d.ts.map +1 -1
  37. package/lib/services/assessment/modules/annotations/index.js +2 -1
  38. package/lib/services/assessment/modules/securityTests/ConfidenceScorer.d.ts.map +1 -1
  39. package/lib/services/assessment/modules/securityTests/ConfidenceScorer.js +28 -0
  40. package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts +95 -0
  41. package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts.map +1 -1
  42. package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.js +174 -0
  43. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts.map +1 -1
  44. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.js +15 -0
  45. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +40 -0
  46. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -1
  47. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +143 -131
  48. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ManifestValidationAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ManifestValidationAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,4BAA4B,EAM7B,MAAM,uBAAuB,CAAC;AAM/B,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAcpB;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IAqLxC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiC7B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAiChC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+CzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAqCpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;OAEG;YACW,yBAAyB;IAqFvC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA+ChC"}
1
+ {"version":3,"file":"ManifestValidationAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ManifestValidationAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,KAAK,EACV,4BAA4B,EAS7B,MAAM,uBAAuB,CAAC;AAO/B;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAwCR;AA+BD,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAcpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAqC1B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IAiMxC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiC7B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAiChC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+CzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAqCpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAyE9B;;OAEG;YACW,cAAc;IAuC5B;;OAEG;YACW,yBAAyB;IAmEvC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA+ChC"}
@@ -14,6 +14,67 @@ import { BaseAssessor } from "./BaseAssessor.js";
14
14
  const REQUIRED_FIELDS = ["name", "version", "mcp_config"];
15
15
  const RECOMMENDED_FIELDS = ["description", "author", "repository"];
16
16
  const CURRENT_MANIFEST_VERSION = "0.3";
17
+ const SEMVER_PATTERN = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
18
+ /**
19
+ * Calculate Levenshtein distance between two strings
20
+ * Uses space-optimized two-row algorithm for O(min(n,m)) memory
21
+ * Used for "did you mean?" suggestions on mismatched tool names (Issue #140)
22
+ * Exported for testing (Issue #141 - ISSUE-002)
23
+ */
24
+ export function levenshteinDistance(a, b, maxDist) {
25
+ // Early termination optimizations
26
+ if (a === b)
27
+ return 0;
28
+ if (a.length === 0)
29
+ return b.length;
30
+ if (b.length === 0)
31
+ return a.length;
32
+ // If length difference exceeds max distance, no need to compute
33
+ if (maxDist && Math.abs(a.length - b.length) > maxDist) {
34
+ return maxDist + 1;
35
+ }
36
+ // Ensure a is the shorter string (optimize space)
37
+ if (a.length > b.length) {
38
+ [a, b] = [b, a];
39
+ }
40
+ // Two-row algorithm: only keep previous and current row
41
+ let prev = Array.from({ length: a.length + 1 }, (_, i) => i);
42
+ let curr = new Array(a.length + 1);
43
+ for (let i = 1; i <= b.length; i++) {
44
+ curr[0] = i;
45
+ for (let j = 1; j <= a.length; j++) {
46
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
47
+ curr[j] = prev[j - 1];
48
+ }
49
+ else {
50
+ curr[j] = Math.min(prev[j - 1] + 1, // substitution
51
+ curr[j - 1] + 1, // insertion
52
+ prev[j] + 1);
53
+ }
54
+ }
55
+ // Swap rows
56
+ [prev, curr] = [curr, prev];
57
+ }
58
+ return prev[a.length];
59
+ }
60
+ /**
61
+ * Find closest matching tool name from a set
62
+ * Returns match if distance <= threshold (default: 10 chars or 40% of length)
63
+ * Generous threshold to catch common renames like "data" -> "resources"
64
+ */
65
+ function findClosestMatch(name, candidates, threshold) {
66
+ const maxDist = threshold ?? Math.max(10, Math.floor(name.length * 0.4));
67
+ let closest = null;
68
+ let minDist = Infinity;
69
+ for (const candidate of candidates) {
70
+ const dist = levenshteinDistance(name.toLowerCase(), candidate.toLowerCase(), maxDist);
71
+ if (dist < minDist && dist <= maxDist) {
72
+ minDist = dist;
73
+ closest = candidate;
74
+ }
75
+ }
76
+ return closest;
77
+ }
17
78
  export class ManifestValidationAssessor extends BaseAssessor {
18
79
  /**
19
80
  * Get mcp_config from manifest (supports both root and nested v0.3 format)
@@ -33,6 +94,57 @@ export class ManifestValidationAssessor extends BaseAssessor {
33
94
  }
34
95
  return undefined;
35
96
  }
97
+ /**
98
+ * Extract contact information from manifest (Issue #141 - D4 check)
99
+ * Supports: author object, author string (email parsing), repository fallback
100
+ *
101
+ * @param manifest - The parsed manifest JSON
102
+ * @returns Extracted contact info or undefined if no contact info found
103
+ */
104
+ extractContactInfo(manifest) {
105
+ // 1. Check author object format (npm-style)
106
+ if (typeof manifest.author === "object" && manifest.author !== null) {
107
+ const authorObj = manifest.author;
108
+ return {
109
+ email: authorObj.email,
110
+ url: authorObj.url,
111
+ name: authorObj.name,
112
+ source: "author_object",
113
+ };
114
+ }
115
+ // 2. Check author string (may contain email: "Name <email@example.com>")
116
+ if (typeof manifest.author === "string" && manifest.author.trim()) {
117
+ const emailMatch = manifest.author.match(/<([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})>/);
118
+ return {
119
+ name: manifest.author.replace(/<[^>]+>/, "").trim() || undefined,
120
+ email: emailMatch?.[1],
121
+ source: "author_string",
122
+ };
123
+ }
124
+ // 3. Fallback to repository (provides contact via issues)
125
+ if (manifest.repository) {
126
+ return {
127
+ url: manifest.repository,
128
+ source: "repository",
129
+ };
130
+ }
131
+ return undefined;
132
+ }
133
+ /**
134
+ * Extract version information from manifest (Issue #141 - D5 check)
135
+ *
136
+ * @param manifest - The parsed manifest JSON
137
+ * @returns Extracted version info or undefined if no version found
138
+ */
139
+ extractVersionInfo(manifest) {
140
+ if (!manifest.version)
141
+ return undefined;
142
+ return {
143
+ version: manifest.version,
144
+ valid: true,
145
+ semverCompliant: SEMVER_PATTERN.test(manifest.version),
146
+ };
147
+ }
36
148
  /**
37
149
  * Run manifest validation assessment
38
150
  */
@@ -129,6 +241,11 @@ export class ManifestValidationAssessor extends BaseAssessor {
129
241
  // Validate version format
130
242
  this.testCount++;
131
243
  validationResults.push(this.validateVersionFormat(manifest.version));
244
+ // Validate tool names match server (Issue #140)
245
+ if (manifest.tools && context.tools.length > 0) {
246
+ const toolResults = this.validateToolNamesMatch(manifest, context.tools);
247
+ validationResults.push(...toolResults);
248
+ }
132
249
  // Validate privacy policy URLs if present
133
250
  let privacyPolicies;
134
251
  if (manifest.privacy_policies &&
@@ -164,6 +281,9 @@ export class ManifestValidationAssessor extends BaseAssessor {
164
281
  const status = this.determineManifestStatus(validationResults, hasRequiredFields);
165
282
  const explanation = this.generateExplanation(validationResults, hasRequiredFields, hasIcon, privacyPolicies);
166
283
  const recommendations = this.generateRecommendations(validationResults, privacyPolicies);
284
+ // Extract D4/D5 fields (Issue #141)
285
+ const contactInfo = this.extractContactInfo(manifest);
286
+ const versionInfo = this.extractVersionInfo(manifest);
167
287
  this.logger.info(`Assessment complete: ${validationResults.filter((r) => r.valid).length}/${validationResults.length} checks passed`);
168
288
  return {
169
289
  hasManifest: true,
@@ -173,6 +293,8 @@ export class ManifestValidationAssessor extends BaseAssessor {
173
293
  hasRequiredFields,
174
294
  missingFields,
175
295
  privacyPolicies,
296
+ contactInfo,
297
+ versionInfo,
176
298
  status,
177
299
  explanation,
178
300
  recommendations,
@@ -426,9 +548,7 @@ export class ManifestValidationAssessor extends BaseAssessor {
426
548
  severity: "ERROR",
427
549
  };
428
550
  }
429
- // Check for semver format
430
- const semverPattern = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?$/;
431
- if (!semverPattern.test(version)) {
551
+ if (!SEMVER_PATTERN.test(version)) {
432
552
  return {
433
553
  field: "version (format)",
434
554
  valid: false,
@@ -444,6 +564,98 @@ export class ManifestValidationAssessor extends BaseAssessor {
444
564
  severity: "INFO",
445
565
  };
446
566
  }
567
+ /**
568
+ * Validate manifest tool declarations against actual server tools (Issue #140)
569
+ * Compares tool names in manifest.tools against context.tools from tools/list
570
+ * Uses Levenshtein distance for "did you mean?" suggestions
571
+ */
572
+ validateToolNamesMatch(manifest, serverTools) {
573
+ const results = [];
574
+ // Skip if manifest doesn't declare tools
575
+ if (!manifest.tools || manifest.tools.length === 0) {
576
+ return results;
577
+ }
578
+ this.testCount++;
579
+ const manifestToolNames = new Set(manifest.tools.map((t) => t.name));
580
+ const serverToolNames = new Set(serverTools.map((t) => t.name));
581
+ // Check for tools declared in manifest but not on server
582
+ const mismatches = [];
583
+ for (const name of manifestToolNames) {
584
+ if (!serverToolNames.has(name)) {
585
+ const suggestion = findClosestMatch(name, serverToolNames);
586
+ mismatches.push({ manifest: name, suggestion });
587
+ }
588
+ }
589
+ // Check for tools on server but not declared in manifest
590
+ const undeclaredTools = [];
591
+ for (const name of serverToolNames) {
592
+ if (!manifestToolNames.has(name)) {
593
+ undeclaredTools.push(name);
594
+ }
595
+ }
596
+ // Report mismatches with suggestions
597
+ if (mismatches.length > 0) {
598
+ const issueLines = mismatches.map((m) => m.suggestion
599
+ ? `"${m.manifest}" (did you mean "${m.suggestion}"?)`
600
+ : `"${m.manifest}"`);
601
+ results.push({
602
+ field: "tools (manifest vs server)",
603
+ valid: false,
604
+ value: mismatches,
605
+ issue: `Manifest declares tools not found on server: ${issueLines.join(", ")}`,
606
+ severity: "WARNING",
607
+ });
608
+ }
609
+ if (undeclaredTools.length > 0) {
610
+ results.push({
611
+ field: "tools (undeclared)",
612
+ valid: false,
613
+ value: undeclaredTools,
614
+ issue: `Server has tools not declared in manifest: ${undeclaredTools.join(", ")}`,
615
+ severity: "INFO",
616
+ });
617
+ }
618
+ // All matched
619
+ if (mismatches.length === 0 && undeclaredTools.length === 0) {
620
+ results.push({
621
+ field: "tools (manifest vs server)",
622
+ valid: true,
623
+ value: `${manifestToolNames.size} tools matched`,
624
+ severity: "INFO",
625
+ });
626
+ }
627
+ return results;
628
+ }
629
+ /**
630
+ * Fetch with retry logic for transient network failures
631
+ */
632
+ async fetchWithRetry(url, method, retries = 2, backoffMs = 100) {
633
+ let lastError = null;
634
+ for (let attempt = 0; attempt <= retries; attempt++) {
635
+ const controller = new AbortController();
636
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
637
+ try {
638
+ const response = await fetch(url, {
639
+ method,
640
+ signal: controller.signal,
641
+ redirect: "follow",
642
+ });
643
+ clearTimeout(timeoutId);
644
+ return response;
645
+ }
646
+ catch (error) {
647
+ clearTimeout(timeoutId);
648
+ lastError = error instanceof Error ? error : new Error(String(error));
649
+ // Don't retry on last attempt
650
+ if (attempt < retries) {
651
+ // Exponential backoff
652
+ await new Promise((resolve) => setTimeout(resolve, backoffMs * Math.pow(2, attempt)));
653
+ }
654
+ }
655
+ }
656
+ // All retries exhausted
657
+ throw lastError;
658
+ }
447
659
  /**
448
660
  * Validate privacy policy URLs are accessible
449
661
  */
@@ -467,15 +679,8 @@ export class ManifestValidationAssessor extends BaseAssessor {
467
679
  continue;
468
680
  }
469
681
  try {
470
- // Use HEAD request for efficiency, fallback to GET if needed
471
- const controller = new AbortController();
472
- const timeoutId = setTimeout(() => controller.abort(), 5000);
473
- const response = await fetch(url, {
474
- method: "HEAD",
475
- signal: controller.signal,
476
- redirect: "follow",
477
- });
478
- clearTimeout(timeoutId);
682
+ // Use HEAD request for efficiency with retry logic
683
+ const response = await this.fetchWithRetry(url, "HEAD");
479
684
  results.push({
480
685
  url,
481
686
  accessible: response.ok,
@@ -489,14 +694,7 @@ export class ManifestValidationAssessor extends BaseAssessor {
489
694
  error: headError instanceof Error ? headError.message : String(headError),
490
695
  });
491
696
  try {
492
- const controller = new AbortController();
493
- const timeoutId = setTimeout(() => controller.abort(), 5000);
494
- const response = await fetch(url, {
495
- method: "GET",
496
- signal: controller.signal,
497
- redirect: "follow",
498
- });
499
- clearTimeout(timeoutId);
697
+ const response = await this.fetchWithRetry(url, "GET");
500
698
  results.push({
501
699
  url,
502
700
  accessible: response.ok,
@@ -17,6 +17,11 @@ export declare class ProhibitedLibrariesAssessor extends BaseAssessor {
17
17
  * Run prohibited libraries assessment
18
18
  */
19
19
  assess(context: AssessmentContext): Promise<ProhibitedLibrariesAssessment>;
20
+ /**
21
+ * Create result when no files are available to scan (Issue #154)
22
+ * Follows the pattern established by ConformanceAssessor
23
+ */
24
+ private createSkippedResult;
20
25
  /**
21
26
  * Check if file is a source file worth scanning
22
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ProhibitedLibrariesAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProhibitedLibrariesAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,6BAA6B,EAI9B,MAAM,uBAAuB,CAAC;AAS/B,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IAiKzC;;OAEG;IACH,OAAO,CAAC,YAAY;IA0BpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;;;;;;OAOG;IACH,OAAO,CAAC,0BAA0B;IAiClC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;CA2EhC"}
1
+ {"version":3,"file":"ProhibitedLibrariesAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProhibitedLibrariesAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,6BAA6B,EAI9B,MAAM,uBAAuB,CAAC;AAS/B,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IAkLzC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,YAAY;IA0BpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;;;;;;OAOG;IACH,OAAO,CAAC,0BAA0B;IAiClC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;CA2EhC"}
@@ -18,6 +18,15 @@ export class ProhibitedLibrariesAssessor extends BaseAssessor {
18
18
  async assess(context) {
19
19
  this.logger.info("Starting prohibited libraries assessment");
20
20
  this.testCount = 0;
21
+ // Issue #154: Check if there are any files to scan
22
+ const hasPackageJson = Boolean(context.packageJson);
23
+ const hasSourceFiles = Boolean(context.sourceCodeFiles &&
24
+ context.config.enableSourceCodeAnalysis &&
25
+ context.sourceCodeFiles.size > 0);
26
+ if (!hasPackageJson && !hasSourceFiles) {
27
+ this.logger.info("No package.json or source files available, skipping assessment");
28
+ return this.createSkippedResult("No package.json or source files provided. Enable source code analysis with --source flag.");
29
+ }
21
30
  const matches = [];
22
31
  const scannedFiles = [];
23
32
  let hasFinancialLibraries = false;
@@ -137,6 +146,26 @@ export class ProhibitedLibrariesAssessor extends BaseAssessor {
137
146
  recommendations,
138
147
  };
139
148
  }
149
+ /**
150
+ * Create result when no files are available to scan (Issue #154)
151
+ * Follows the pattern established by ConformanceAssessor
152
+ */
153
+ createSkippedResult(reason) {
154
+ return {
155
+ matches: [],
156
+ scannedFiles: [],
157
+ hasFinancialLibraries: false,
158
+ hasMediaLibraries: false,
159
+ status: "NEED_MORE_INFO",
160
+ explanation: `Prohibited libraries assessment skipped: ${reason}`,
161
+ recommendations: [
162
+ "Provide --source <path> to enable package.json and source file scanning",
163
+ "Ensure the source path exists and contains package.json or source files",
164
+ ],
165
+ skipped: true,
166
+ skipReason: reason,
167
+ };
168
+ }
140
169
  /**
141
170
  * Check if file is a source file worth scanning
142
171
  */
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/SecurityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAiB9D,OAAO,EACL,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AAEjC,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAAiC;IAErD;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAStD;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;OAGG;YACW,0BAA0B;gBAwBtC,MAAM,EAAE,OAAO,8BAA8B,EAAE,uBAAuB;IAwClE,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA+OrE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoC7B;;OAEG;YACW,+BAA+B;IAiC7C;;;OAGG;YACW,yBAAyB;IA0CvC;;;;;;;OAOG;YACW,yBAAyB;IAmFvC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;CAgDnC"}
1
+ {"version":3,"file":"SecurityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/SecurityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAiB9D,OAAO,EACL,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AAEjC,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAAiC;IAErD;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAStD;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;OAGG;YACW,0BAA0B;gBAwBtC,MAAM,EAAE,OAAO,8BAA8B,EAAE,uBAAuB;IAwClE,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA8PrE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoC7B;;OAEG;YACW,+BAA+B;IAiC7C;;;OAGG;YACW,yBAAyB;IA0CvC;;;;;;;OAOG;YACW,yBAAyB;IAmFvC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;CAgDnC"}
@@ -253,6 +253,12 @@ export class SecurityAssessor extends BaseAssessor {
253
253
  }
254
254
  // Issue #75: Aggregate auth bypass detection results
255
255
  const authBypassSummary = this.aggregateAuthBypassResults(allTests);
256
+ // Issue #152: Calculate test execution metadata for score validation
257
+ const totalTestsAttempted = allTests.length;
258
+ const validTestsCompleted = validTests.length;
259
+ const testCoveragePercent = totalTestsAttempted > 0
260
+ ? Math.round((validTestsCompleted / totalTestsAttempted) * 100)
261
+ : 0;
256
262
  return {
257
263
  promptInjectionTests: allTests,
258
264
  vulnerabilities,
@@ -263,6 +269,13 @@ export class SecurityAssessor extends BaseAssessor {
263
269
  // Issue #134: Test validity warning for response uniformity detection
264
270
  testValidityWarning: validityResult.warning,
265
271
  overallConfidence,
272
+ // Issue #152: Test execution metadata for score validation
273
+ testExecutionMetadata: {
274
+ totalTestsAttempted,
275
+ validTestsCompleted,
276
+ connectionErrorCount: connectionErrors.length,
277
+ testCoveragePercent,
278
+ },
266
279
  };
267
280
  }
268
281
  /**
@@ -38,9 +38,14 @@ export interface AlignmentMetricsResult {
38
38
  };
39
39
  }
40
40
  /**
41
- * Extract annotations from a tool
42
- * Checks multiple sources in priority order: annotations object, direct properties, metadata
41
+ * Enable or disable annotation debug logging (Issue #155)
42
+ * Called by CLI when --debug-annotations flag is provided
43
43
  */
44
+ export declare function setAnnotationDebugMode(enabled: boolean): void;
45
+ /**
46
+ * Check if annotation debug mode is enabled
47
+ */
48
+ export declare function isAnnotationDebugEnabled(): boolean;
44
49
  export declare function extractAnnotations(tool: Tool): ExtractedAnnotations;
45
50
  /**
46
51
  * Extract extended metadata from tool (Issue #54)
@@ -1 +1 @@
1
- {"version":3,"file":"AlignmentChecker.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/annotations/AlignmentChecker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAEhB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,gCAAgC,CAAC;AAoExC;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,kBAAkB,EAAE;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,oBAAoB,CA8DnE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,GACT,oBAAoB,CAAC,kBAAkB,CAAC,CA6D1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,EAAE,CAqBtE;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,IAAI,GAAG,mBAAmB,CAmD3E;AAqCD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,gBAAgB,EAAE,gBAAgB,EAClC,kBAAkB,CAAC,EAAE,wBAAwB,GAC5C,oBAAoB,CA0JtB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,UAAU,EAAE,MAAM,GACjB,gBAAgB,CA8BlB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,UAAU,EAAE,MAAM,GACjB,sBAAsB,CA2BxB"}
1
+ {"version":3,"file":"AlignmentChecker.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/annotations/AlignmentChecker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAEhB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,gCAAgC,CAAC;AAuFxC;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,kBAAkB,EAAE;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AA0CD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE7D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,oBAAoB,CAiNnE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,GACT,oBAAoB,CAAC,kBAAkB,CAAC,CA6D1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,EAAE,CAqBtE;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,IAAI,GAAG,mBAAmB,CAmD3E;AAqCD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,gBAAgB,EAAE,gBAAgB,EAClC,kBAAkB,CAAC,EAAE,wBAAwB,GAC5C,oBAAoB,CA0JtB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,UAAU,EAAE,MAAM,GACjB,gBAAgB,CA8BlB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,UAAU,EAAE,MAAM,GACjB,sBAAsB,CA2BxB"}
@@ -7,57 +7,155 @@
7
7
  import { scanDescriptionForPoisoning, } from "./DescriptionPoisoningDetector.js";
8
8
  import { detectAnnotationDeception, isActionableConfidence, } from "./AnnotationDeceptionDetector.js";
9
9
  import { inferBehavior } from "./BehaviorInference.js";
10
+ /**
11
+ * Helper to resolve annotation value with fallback (Issue #150)
12
+ * Checks *Hint suffix first (MCP spec), then non-suffixed version as fallback
13
+ * This handles servers that use 'readOnly' instead of 'readOnlyHint'
14
+ *
15
+ * @param obj - The object to search for annotation properties
16
+ * @param hintKey - The MCP spec compliant key (e.g., 'readOnlyHint')
17
+ * @param fallbackKey - The non-suffixed fallback key (e.g., 'readOnly')
18
+ * @returns The boolean annotation value, or undefined if not found or not a boolean
19
+ */
20
+ function resolveAnnotationValue(obj, hintKey, fallbackKey) {
21
+ if (!obj)
22
+ return undefined;
23
+ // Priority: *Hint version (MCP spec)
24
+ if (obj[hintKey] !== undefined) {
25
+ const val = obj[hintKey];
26
+ if (typeof val === "boolean")
27
+ return val;
28
+ }
29
+ // Fallback: non-suffixed version (Issue #150)
30
+ if (obj[fallbackKey] !== undefined) {
31
+ const val = obj[fallbackKey];
32
+ if (typeof val === "boolean")
33
+ return val;
34
+ }
35
+ return undefined;
36
+ }
10
37
  /**
11
38
  * Extract annotations from a tool
12
39
  * Checks multiple sources in priority order: annotations object, direct properties, metadata
40
+ * Issue #150: Also checks non-suffixed property names (readOnly, destructive) as fallback
41
+ */
42
+ /**
43
+ * Global debug flag for annotation extraction (Issue #155)
44
+ * Set via setAnnotationDebugMode() when --debug-annotations flag is used
45
+ */
46
+ let annotationDebugMode = false;
47
+ /**
48
+ * Enable or disable annotation debug logging (Issue #155)
49
+ * Called by CLI when --debug-annotations flag is provided
50
+ */
51
+ export function setAnnotationDebugMode(enabled) {
52
+ annotationDebugMode = enabled;
53
+ }
54
+ /**
55
+ * Check if annotation debug mode is enabled
13
56
  */
57
+ export function isAnnotationDebugEnabled() {
58
+ return annotationDebugMode;
59
+ }
14
60
  export function extractAnnotations(tool) {
15
61
  const extendedTool = tool;
62
+ // Issue #155: Debug logging when --debug-annotations flag is enabled
63
+ if (annotationDebugMode) {
64
+ console.log("[DEBUG-ANNOTATIONS]", tool.name, "| keys:", Object.keys(tool), "| annotations:", JSON.stringify(extendedTool.annotations), "| direct.readOnlyHint:", extendedTool.readOnlyHint);
65
+ }
16
66
  // Priority 1: Check annotations object (MCP 2024-11 spec)
67
+ // Issue #150: Use resolveAnnotationValue to check both *Hint and non-suffixed versions
17
68
  if (extendedTool.annotations) {
18
- const hasAnnotations = extendedTool.annotations.readOnlyHint !== undefined ||
19
- extendedTool.annotations.destructiveHint !== undefined;
69
+ const annotationsObj = extendedTool.annotations;
70
+ const readOnlyValue = resolveAnnotationValue(annotationsObj, "readOnlyHint", "readOnly");
71
+ const destructiveValue = resolveAnnotationValue(annotationsObj, "destructiveHint", "destructive");
72
+ const hasAnnotations = readOnlyValue !== undefined || destructiveValue !== undefined;
20
73
  if (hasAnnotations) {
21
74
  return {
22
- readOnlyHint: extendedTool.annotations.readOnlyHint,
23
- destructiveHint: extendedTool.annotations.destructiveHint,
75
+ readOnlyHint: readOnlyValue,
76
+ destructiveHint: destructiveValue,
24
77
  title: extendedTool.annotations.title || extendedTool.title,
25
78
  description: tool.description,
26
- idempotentHint: extendedTool.annotations.idempotentHint,
27
- openWorldHint: extendedTool.annotations.openWorldHint,
79
+ idempotentHint: resolveAnnotationValue(annotationsObj, "idempotentHint", "idempotent"),
80
+ openWorldHint: resolveAnnotationValue(annotationsObj, "openWorldHint", "openWorld"),
28
81
  source: "mcp",
29
82
  };
30
83
  }
31
84
  }
32
85
  // Priority 2: Check direct properties
33
- if (extendedTool.readOnlyHint !== undefined ||
34
- extendedTool.destructiveHint !== undefined) {
86
+ // Issue #150: Use resolveAnnotationValue to check both *Hint and non-suffixed versions
87
+ const directObj = extendedTool;
88
+ const directReadOnly = resolveAnnotationValue(directObj, "readOnlyHint", "readOnly");
89
+ const directDestructive = resolveAnnotationValue(directObj, "destructiveHint", "destructive");
90
+ if (directReadOnly !== undefined || directDestructive !== undefined) {
35
91
  return {
36
- readOnlyHint: extendedTool.readOnlyHint,
37
- destructiveHint: extendedTool.destructiveHint,
92
+ readOnlyHint: directReadOnly,
93
+ destructiveHint: directDestructive,
38
94
  title: extendedTool.title,
39
95
  description: tool.description,
40
- idempotentHint: extendedTool.idempotentHint,
41
- openWorldHint: extendedTool.openWorldHint,
96
+ idempotentHint: resolveAnnotationValue(directObj, "idempotentHint", "idempotent"),
97
+ openWorldHint: resolveAnnotationValue(directObj, "openWorldHint", "openWorld"),
42
98
  source: "mcp",
43
99
  };
44
100
  }
45
101
  // Priority 3: Check metadata
102
+ // Issue #150: Use resolveAnnotationValue to check both *Hint and non-suffixed versions
46
103
  if (extendedTool.metadata) {
47
- const hasMetadataAnnotations = extendedTool.metadata.readOnlyHint !== undefined ||
48
- extendedTool.metadata.destructiveHint !== undefined;
104
+ const metadataObj = extendedTool.metadata;
105
+ const metaReadOnly = resolveAnnotationValue(metadataObj, "readOnlyHint", "readOnly");
106
+ const metaDestructive = resolveAnnotationValue(metadataObj, "destructiveHint", "destructive");
107
+ const hasMetadataAnnotations = metaReadOnly !== undefined || metaDestructive !== undefined;
49
108
  if (hasMetadataAnnotations) {
50
109
  return {
51
- readOnlyHint: extendedTool.metadata.readOnlyHint,
52
- destructiveHint: extendedTool.metadata.destructiveHint,
110
+ readOnlyHint: metaReadOnly,
111
+ destructiveHint: metaDestructive,
53
112
  title: extendedTool.metadata.title || extendedTool.title,
54
113
  description: tool.description,
55
- idempotentHint: extendedTool.metadata.idempotentHint,
56
- openWorldHint: extendedTool.metadata.openWorldHint,
114
+ idempotentHint: resolveAnnotationValue(metadataObj, "idempotentHint", "idempotent"),
115
+ openWorldHint: resolveAnnotationValue(metadataObj, "openWorldHint", "openWorld"),
116
+ source: "mcp",
117
+ };
118
+ }
119
+ }
120
+ // Priority 4: Check _meta object (MCP spec allows arbitrary data here)
121
+ // Issue #155: Some servers may store annotations in _meta
122
+ if (extendedTool._meta) {
123
+ const metaObj = extendedTool._meta;
124
+ const metaReadOnly = resolveAnnotationValue(metaObj, "readOnlyHint", "readOnly");
125
+ const metaDestructive = resolveAnnotationValue(metaObj, "destructiveHint", "destructive");
126
+ if (metaReadOnly !== undefined || metaDestructive !== undefined) {
127
+ return {
128
+ readOnlyHint: metaReadOnly,
129
+ destructiveHint: metaDestructive,
130
+ title: metaObj.title,
131
+ description: tool.description,
132
+ idempotentHint: resolveAnnotationValue(metaObj, "idempotentHint", "idempotent"),
133
+ openWorldHint: resolveAnnotationValue(metaObj, "openWorldHint", "openWorld"),
57
134
  source: "mcp",
58
135
  };
59
136
  }
60
137
  }
138
+ // Priority 5: Check annotations.hints (nested structure some servers use)
139
+ // Issue #155: Handle servers that nest hints inside annotations object
140
+ if (extendedTool.annotations) {
141
+ const hintsObj = extendedTool.annotations
142
+ .hints;
143
+ if (hintsObj) {
144
+ const hintsReadOnly = resolveAnnotationValue(hintsObj, "readOnlyHint", "readOnly");
145
+ const hintsDestructive = resolveAnnotationValue(hintsObj, "destructiveHint", "destructive");
146
+ if (hintsReadOnly !== undefined || hintsDestructive !== undefined) {
147
+ return {
148
+ readOnlyHint: hintsReadOnly,
149
+ destructiveHint: hintsDestructive,
150
+ title: extendedTool.annotations.title,
151
+ description: tool.description,
152
+ idempotentHint: resolveAnnotationValue(hintsObj, "idempotentHint", "idempotent"),
153
+ openWorldHint: resolveAnnotationValue(hintsObj, "openWorldHint", "openWorld"),
154
+ source: "mcp",
155
+ };
156
+ }
157
+ }
158
+ }
61
159
  return {
62
160
  title: extendedTool.title,
63
161
  description: tool.description,
@@ -16,7 +16,7 @@ export { analyzeDescription, hasReadOnlyIndicators, hasDestructiveIndicators, ha
16
16
  export { analyzeInputSchema, analyzeOutputSchema, hasBulkOperationIndicators, hasPaginationParameters, hasForceFlags, INPUT_READONLY_PATTERNS, INPUT_DESTRUCTIVE_PATTERNS, INPUT_WRITE_PATTERNS, OUTPUT_READONLY_PATTERNS, OUTPUT_DESTRUCTIVE_PATTERNS, OUTPUT_WRITE_PATTERNS, type JSONSchema, } from "./SchemaAnalyzer.js";
17
17
  export { detectArchitecture, hasDatabaseToolPatterns, extractDatabasesFromDependencies, type Tool as ArchitectureTool, type ArchitectureContext, } from "./ArchitectureDetector.js";
18
18
  export { type ClaudeInference, type EnhancedToolAnnotationResult, } from "./types.js";
19
- export { extractAnnotations, extractExtendedMetadata, extractToolParams, scanInputSchemaDescriptions, assessSingleTool, determineAnnotationStatus, calculateMetrics, type ExtractedAnnotations, type AlignmentMetricsResult, } from "./AlignmentChecker.js";
19
+ export { extractAnnotations, extractExtendedMetadata, extractToolParams, scanInputSchemaDescriptions, assessSingleTool, determineAnnotationStatus, calculateMetrics, setAnnotationDebugMode, isAnnotationDebugEnabled, type ExtractedAnnotations, type AlignmentMetricsResult, } from "./AlignmentChecker.js";
20
20
  export { generateExplanation, generateEnhancedExplanation, generateRecommendations, generateEnhancedRecommendations, } from "./ExplanationGenerator.js";
21
21
  export { emitAnnotationEvents, emitMismatchEvent } from "./EventEmitter.js";
22
22
  export { enhanceWithClaudeInference, createPatternBasedInference, } from "./ClaudeIntegration.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/annotations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,kCAAkC,EAClC,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,eAAe,GACrB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,aAAa,EACb,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC3B,qBAAqB,EACrB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,gCAAgC,EAChC,KAAK,IAAI,IAAI,gBAAgB,EAC7B,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,4BAA4B,GAClC,MAAM,SAAS,CAAC;AAIjB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,gBAAgB,EAChB,yBAAyB,EACzB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/annotations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,kCAAkC,EAClC,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,eAAe,GACrB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,aAAa,EACb,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC3B,qBAAqB,EACrB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,gCAAgC,EAChC,KAAK,IAAI,IAAI,gBAAgB,EAC7B,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,4BAA4B,GAClC,MAAM,SAAS,CAAC;AAKjB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,gBAAgB,EAChB,yBAAyB,EACzB,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC"}
@@ -20,7 +20,8 @@ export { analyzeInputSchema, analyzeOutputSchema, hasBulkOperationIndicators, ha
20
20
  export { detectArchitecture, hasDatabaseToolPatterns, extractDatabasesFromDependencies, } from "./ArchitectureDetector.js";
21
21
  // Issue #105: Alignment Checker
22
22
  // Issue #119: Added scanInputSchemaDescriptions for Challenge #15
23
- export { extractAnnotations, extractExtendedMetadata, extractToolParams, scanInputSchemaDescriptions, assessSingleTool, determineAnnotationStatus, calculateMetrics, } from "./AlignmentChecker.js";
23
+ // Issue #155: Added setAnnotationDebugMode for debug logging
24
+ export { extractAnnotations, extractExtendedMetadata, extractToolParams, scanInputSchemaDescriptions, assessSingleTool, determineAnnotationStatus, calculateMetrics, setAnnotationDebugMode, isAnnotationDebugEnabled, } from "./AlignmentChecker.js";
24
25
  // Issue #105: Explanation Generator
25
26
  export { generateExplanation, generateEnhancedExplanation, generateRecommendations, generateEnhancedRecommendations, } from "./ExplanationGenerator.js";
26
27
  // Issue #105: Event Emitter
@@ -1 +1 @@
1
- {"version":3,"file":"ConfidenceScorer.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/ConfidenceScorer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAmCD;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,CACjB,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,eAAe,EACxB,kBAAkB,CAAC,EAAE,2BAA2B,GAC/C,gBAAgB;IA4JnB;;;;;OAKG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO;IAOxE;;;;;OAKG;IACH,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;CAOtD"}
1
+ {"version":3,"file":"ConfidenceScorer.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/ConfidenceScorer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAmCD;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,CACjB,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,eAAe,EACxB,kBAAkB,CAAC,EAAE,2BAA2B,GAC/C,gBAAgB;IAgMnB;;;;;OAKG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO;IAOxE;;;;;OAKG;IACH,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;CAOtD"}