@bryan-thompson/inspector-assessment 1.35.0 → 1.35.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.
Files changed (31) hide show
  1. package/cli/build/__tests__/stage3-fix-validation.test.js +163 -0
  2. package/cli/build/__tests__/stage3-fixes.test.js +516 -0
  3. package/cli/build/lib/cli-parser.js +7 -0
  4. package/cli/build/lib/cli-parserSchemas.js +3 -0
  5. package/cli/build/lib/jsonl-events.js +3 -0
  6. package/cli/build/lib/result-output.js +8 -2
  7. package/cli/package.json +1 -1
  8. package/client/dist/assets/{OAuthCallback-DC1cIXHT.js → OAuthCallback-CUf6mvrP.js} +1 -1
  9. package/client/dist/assets/{OAuthDebugCallback-C3gqJjgQ.js → OAuthDebugCallback-DkfPOggR.js} +1 -1
  10. package/client/dist/assets/{index-Dn2w887x.js → index-uinVACY4.js} +4 -4
  11. package/client/dist/index.html +1 -1
  12. package/client/lib/lib/assessment/summarizer/AssessmentSummarizer.d.ts.map +1 -1
  13. package/client/lib/lib/assessment/summarizer/AssessmentSummarizer.js +14 -1
  14. package/client/lib/lib/assessment/summarizer/index.d.ts +4 -0
  15. package/client/lib/lib/assessment/summarizer/index.d.ts.map +1 -1
  16. package/client/lib/lib/assessment/summarizer/index.js +4 -0
  17. package/client/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.d.ts +36 -0
  18. package/client/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.d.ts.map +1 -0
  19. package/client/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.js +282 -0
  20. package/client/lib/lib/assessment/summarizer/stageBTypes.d.ts +154 -0
  21. package/client/lib/lib/assessment/summarizer/stageBTypes.d.ts.map +1 -0
  22. package/client/lib/lib/assessment/summarizer/stageBTypes.js +24 -0
  23. package/client/lib/lib/assessment/summarizer/types.d.ts +5 -0
  24. package/client/lib/lib/assessment/summarizer/types.d.ts.map +1 -1
  25. package/client/lib/lib/assessment/summarizer/types.js +1 -0
  26. package/client/lib/lib/moduleScoring.d.ts +2 -1
  27. package/client/lib/lib/moduleScoring.d.ts.map +1 -1
  28. package/client/lib/lib/moduleScoring.js +2 -1
  29. package/client/package.json +1 -1
  30. package/package.json +1 -1
  31. package/server/package.json +1 -1
@@ -222,6 +222,10 @@ export function parseArgs(argv) {
222
222
  // Issue #136: Auto-enable tiered output when results exceed token threshold
223
223
  options.autoTier = true;
224
224
  break;
225
+ case "--stage-b-verbose":
226
+ // Issue #137: Stage B enrichment for Claude semantic analysis
227
+ options.stageBVerbose = true;
228
+ break;
225
229
  case "--profile": {
226
230
  const profileValue = args[++i];
227
231
  if (!profileValue) {
@@ -392,6 +396,9 @@ Options:
392
396
  tiered: Directory with executive-summary.json, tool-summaries.json, tools/
393
397
  summary-only: Executive summary + tool summaries (no per-tool details)
394
398
  --auto-tier Auto-enable tiered output when results exceed 100K tokens
399
+ --stage-b-verbose Enable Stage B enrichment for Claude semantic analysis
400
+ Adds evidence samples, payload correlations, and confidence
401
+ breakdowns to tiered output (Tier 2 + Tier 3)
395
402
  --skip-modules <list> Skip specific modules (comma-separated)
396
403
  --only-modules <list> Run only specific modules (comma-separated)
397
404
  --json Output only JSON path (no console summary)
@@ -121,6 +121,9 @@ export const AssessmentOptionsSchema = z
121
121
  profile: AssessmentProfileNameSchema.optional(),
122
122
  logLevel: LogLevelSchema.optional(),
123
123
  listModules: z.boolean().optional(),
124
+ outputFormat: OutputFormatSchema.optional(),
125
+ autoTier: z.boolean().optional(),
126
+ stageBVerbose: z.boolean().optional(),
124
127
  })
125
128
  .refine((data) => !(data.profile && (data.skipModules?.length || data.onlyModules?.length)), {
126
129
  message: "--profile cannot be used with --skip-modules or --only-modules",
@@ -258,6 +258,9 @@ export function emitPhaseComplete(phase, duration) {
258
258
  /**
259
259
  * Emit tiered_output_generated event when tiered output files are created.
260
260
  * Includes paths and token estimates for each tier.
261
+ *
262
+ * NOTE: This function is duplicated in scripts/lib/jsonl-events.ts.
263
+ * Keep both implementations in sync. See TieredOutputEvent comment above.
261
264
  */
262
265
  export function emitTieredOutput(outputDir, outputFormat, tiers) {
263
266
  emitJSONL({
@@ -68,7 +68,10 @@ export function saveResults(serverName, results, options) {
68
68
  * @returns Path to output directory
69
69
  */
70
70
  export function saveTieredResults(serverName, results, options) {
71
- const summarizer = new AssessmentSummarizer();
71
+ // Issue #137: Pass stageBVerbose option to summarizer for Stage B enrichment
72
+ const summarizer = new AssessmentSummarizer({
73
+ stageBVerbose: options.stageBVerbose,
74
+ });
72
75
  // Determine output directory
73
76
  const defaultDir = `/tmp/inspector-full-assessment-${serverName}`;
74
77
  const outputDir = options.outputPath || defaultDir;
@@ -157,7 +160,10 @@ export function saveTieredResults(serverName, results, options) {
157
160
  * @returns Path to output directory
158
161
  */
159
162
  export function saveSummaryOnly(serverName, results, options) {
160
- const summarizer = new AssessmentSummarizer();
163
+ // Issue #137: Pass stageBVerbose option to summarizer for Stage B enrichment
164
+ const summarizer = new AssessmentSummarizer({
165
+ stageBVerbose: options.stageBVerbose,
166
+ });
161
167
  // Determine output directory
162
168
  const defaultDir = `/tmp/inspector-full-assessment-${serverName}`;
163
169
  const outputDir = options.outputPath || defaultDir;
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-cli",
3
- "version": "1.35.0",
3
+ "version": "1.35.1",
4
4
  "description": "CLI for the Enhanced MCP Inspector with assessment capabilities",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",
@@ -1,4 +1,4 @@
1
- import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-Dn2w887x.js";
1
+ import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-uinVACY4.js";
2
2
  const OAuthCallback = ({ onConnect }) => {
3
3
  const { toast } = useToast();
4
4
  const hasProcessedRef = reactExports.useRef(false);
@@ -1,4 +1,4 @@
1
- import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-Dn2w887x.js";
1
+ import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-uinVACY4.js";
2
2
  const OAuthDebugCallback = ({ onConnect }) => {
3
3
  reactExports.useEffect(() => {
4
4
  let isProcessed = false;
@@ -16373,7 +16373,7 @@ object({
16373
16373
  token_type_hint: string().optional()
16374
16374
  }).strip();
16375
16375
  const name = "@bryan-thompson/inspector-assessment-client";
16376
- const version$1 = "1.35.0";
16376
+ const version$1 = "1.35.1";
16377
16377
  const packageJson = {
16378
16378
  name,
16379
16379
  version: version$1
@@ -48920,7 +48920,7 @@ const useTheme = () => {
48920
48920
  [theme, setThemeWithSideEffect]
48921
48921
  );
48922
48922
  };
48923
- const version = "1.35.0";
48923
+ const version = "1.35.1";
48924
48924
  var [createTooltipContext] = createContextScope("Tooltip", [
48925
48925
  createPopperScope
48926
48926
  ]);
@@ -52515,13 +52515,13 @@ const App = () => {
52515
52515
  ) });
52516
52516
  if (window.location.pathname === "/oauth/callback") {
52517
52517
  const OAuthCallback = React.lazy(
52518
- () => __vitePreload(() => import("./OAuthCallback-DC1cIXHT.js"), true ? [] : void 0)
52518
+ () => __vitePreload(() => import("./OAuthCallback-CUf6mvrP.js"), true ? [] : void 0)
52519
52519
  );
52520
52520
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
52521
52521
  }
52522
52522
  if (window.location.pathname === "/oauth/callback/debug") {
52523
52523
  const OAuthDebugCallback = React.lazy(
52524
- () => __vitePreload(() => import("./OAuthDebugCallback-C3gqJjgQ.js"), true ? [] : void 0)
52524
+ () => __vitePreload(() => import("./OAuthDebugCallback-DkfPOggR.js"), true ? [] : void 0)
52525
52525
  );
52526
52526
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
52527
52527
  }
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/mcp.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>MCP Inspector</title>
8
- <script type="module" crossorigin src="/assets/index-Dn2w887x.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-uinVACY4.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-BoUA5OL1.css">
10
10
  </head>
11
11
  <body>
@@ -1 +1 @@
1
- {"version":3,"file":"AssessmentSummarizer.d.ts","sourceRoot":"","sources":["../../../../src/lib/assessment/summarizer/AssessmentSummarizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAEvB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,uBAAuB,EAE5B,KAAK,gBAAgB,EAEtB,MAAM,SAAS,CAAC;AAMjB;;;;;;;;;GASG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,GAAE,gBAAqB;IAQzC;;;;;;OAMG;IACH,wBAAwB,CAAC,OAAO,EAAE,sBAAsB,GAAG,gBAAgB;IA2B3E;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8C7B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAmDrC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAO9B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA2B7B;;;;;;OAMG;IACH,qBAAqB,CACnB,OAAO,EAAE,sBAAsB,GAC9B,uBAAuB;IAoC1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA8BxB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAgCjC;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAgCnC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;;;;;;OAOG;IACH,iBAAiB,CACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA2B1B;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,EAAE;CAG3D"}
1
+ {"version":3,"file":"AssessmentSummarizer.d.ts","sourceRoot":"","sources":["../../../../src/lib/assessment/summarizer/AssessmentSummarizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAEvB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,uBAAuB,EAE5B,KAAK,gBAAgB,EAEtB,MAAM,SAAS,CAAC;AAUjB;;;;;;;;;GASG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,GAAE,gBAAqB;IAQzC;;;;;;OAMG;IACH,wBAAwB,CAAC,OAAO,EAAE,sBAAsB,GAAG,gBAAgB;IA2B3E;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8C7B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAmDrC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAO9B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA2B7B;;;;;;OAMG;IACH,qBAAqB,CACnB,OAAO,EAAE,sBAAsB,GAC9B,uBAAuB;IAoC1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA8BxB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA0CjC;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAgCnC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;;;;;;OAOG;IACH,iBAAiB,CACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA0C1B;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,EAAE;CAG3D"}
@@ -11,6 +11,7 @@
11
11
  import { calculateModuleScore } from "../../moduleScoring.js";
12
12
  import { estimateTokens } from "./tokenEstimator.js";
13
13
  import { DEFAULT_SUMMARIZER_CONFIG, } from "./types.js";
14
+ import { buildToolSummaryStageBEnrichment, buildToolDetailStageBEnrichment, } from "./stageBEnrichmentBuilder.js";
14
15
  // ============================================================================
15
16
  // Assessment Summarizer Class
16
17
  // ============================================================================
@@ -303,6 +304,11 @@ export class AssessmentSummarizer {
303
304
  hasAnnotations: annotationInfo.hasAnnotations,
304
305
  annotationStatus: annotationInfo.status,
305
306
  };
307
+ // Issue #137: Add Stage B enrichment if enabled
308
+ if (this.config.stageBVerbose) {
309
+ const allTests = results.security?.promptInjectionTests ?? [];
310
+ summary.stageBEnrichment = buildToolSummaryStageBEnrichment(toolName, allTests, 3);
311
+ }
306
312
  summary.estimatedTokens = estimateTokens(summary);
307
313
  return summary;
308
314
  }
@@ -413,7 +419,7 @@ export class AssessmentSummarizer {
413
419
  const securityTests = this.getToolTests(toolName, results);
414
420
  const functionalityResult = results.functionality?.toolResults?.find((r) => r.toolName === toolName);
415
421
  const annotationResult = results.toolAnnotations?.toolResults?.find((r) => r.toolName === toolName);
416
- return {
422
+ const detail = {
417
423
  toolName,
418
424
  extractedAt: new Date().toISOString(),
419
425
  security: {
@@ -429,6 +435,13 @@ export class AssessmentSummarizer {
429
435
  annotations: annotationResult,
430
436
  }),
431
437
  };
438
+ // Issue #137: Add Stage B enrichment for Tier 3 if enabled
439
+ if (this.config.stageBVerbose) {
440
+ const allTests = results.security?.promptInjectionTests ?? [];
441
+ const aupViolations = results.aupCompliance?.violations;
442
+ detail.stageBEnrichment = buildToolDetailStageBEnrichment(toolName, allTests, annotationResult, aupViolations, 50);
443
+ }
444
+ return detail;
432
445
  }
433
446
  /**
434
447
  * Get all tool names for Tier 3 file generation.
@@ -5,11 +5,15 @@
5
5
  * LLM context windows.
6
6
  *
7
7
  * Issue #136: Tiered output strategy for large assessments
8
+ * Issue #137: Stage B enrichment for Claude semantic analysis
8
9
  *
9
10
  * @module assessment/summarizer
10
11
  */
11
12
  export type { OutputFormat, ToolRiskLevel, ExecutiveSummary, ToolSummary, ToolSummariesCollection, ToolDetailReference, TieredOutput, SummarizerConfig, } from "./types.js";
12
13
  export { DEFAULT_SUMMARIZER_CONFIG } from "./types.js";
14
+ export type { FindingEvidence, PayloadCorrelation, ToolSummaryStageBEnrichment, ToolDetailStageBEnrichment, StageBEnrichment, } from "./stageBTypes.js";
15
+ export { STAGE_B_ENRICHMENT_VERSION, DEFAULT_TIER2_MAX_SAMPLES, DEFAULT_TIER3_MAX_CORRELATIONS, MAX_RESPONSE_LENGTH, MAX_CONTEXT_WINDOW, } from "./stageBTypes.js";
16
+ export { buildToolSummaryStageBEnrichment, buildToolDetailStageBEnrichment, } from "./stageBEnrichmentBuilder.js";
13
17
  export { estimateTokens, estimateJsonFileTokens, shouldAutoTier, formatTokenEstimate, estimateSectionTokens, getTopSections, } from "./tokenEstimator.js";
14
18
  export { AssessmentSummarizer } from "./AssessmentSummarizer.js";
15
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/assessment/summarizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/assessment/summarizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAGpD,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,2BAA2B,EAC3B,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,8BAA8B,EAC9B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -5,10 +5,14 @@
5
5
  * LLM context windows.
6
6
  *
7
7
  * Issue #136: Tiered output strategy for large assessments
8
+ * Issue #137: Stage B enrichment for Claude semantic analysis
8
9
  *
9
10
  * @module assessment/summarizer
10
11
  */
11
12
  export { DEFAULT_SUMMARIZER_CONFIG } from "./types.js";
13
+ export { STAGE_B_ENRICHMENT_VERSION, DEFAULT_TIER2_MAX_SAMPLES, DEFAULT_TIER3_MAX_CORRELATIONS, MAX_RESPONSE_LENGTH, MAX_CONTEXT_WINDOW, } from "./stageBTypes.js";
14
+ // Stage B Enrichment Builders (Issue #137)
15
+ export { buildToolSummaryStageBEnrichment, buildToolDetailStageBEnrichment, } from "./stageBEnrichmentBuilder.js";
12
16
  // Token estimation utilities
13
17
  export { estimateTokens, estimateJsonFileTokens, shouldAutoTier, formatTokenEstimate, estimateSectionTokens, getTopSections, } from "./tokenEstimator.js";
14
18
  // Main summarizer class
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Stage B Enrichment Builder
3
+ *
4
+ * Functions to build Stage B enrichment data from assessment results.
5
+ * Extracts evidence, correlations, and confidence details for Claude
6
+ * semantic analysis.
7
+ *
8
+ * Issue #137: Stage A data enrichment for Stage B Claude analysis
9
+ *
10
+ * @module assessment/summarizer/stageBEnrichmentBuilder
11
+ */
12
+ import type { SecurityTestResult } from "../resultTypes.js";
13
+ import type { AUPViolation } from "../extendedTypes.js";
14
+ import type { EnhancedToolAnnotationResult } from "../../../services/assessment/modules/annotations/types.js";
15
+ import { type ToolSummaryStageBEnrichment, type ToolDetailStageBEnrichment } from "./stageBTypes.js";
16
+ /**
17
+ * Build Stage B enrichment for Tier 2 tool summaries.
18
+ *
19
+ * @param toolName - Name of the tool
20
+ * @param tests - Security test results for this tool
21
+ * @param maxSamples - Maximum evidence samples to include
22
+ * @returns Tool summary Stage B enrichment
23
+ */
24
+ export declare function buildToolSummaryStageBEnrichment(toolName: string, tests: SecurityTestResult[], maxSamples?: number): ToolSummaryStageBEnrichment;
25
+ /**
26
+ * Build Stage B enrichment for Tier 3 per-tool detail files.
27
+ *
28
+ * @param toolName - Name of the tool
29
+ * @param tests - Security test results for this tool
30
+ * @param annotationResult - Tool annotation result (if available)
31
+ * @param aupViolations - AUP violations for this tool (if any)
32
+ * @param maxCorrelations - Maximum correlations to include
33
+ * @returns Tool detail Stage B enrichment
34
+ */
35
+ export declare function buildToolDetailStageBEnrichment(toolName: string, tests: SecurityTestResult[], annotationResult?: EnhancedToolAnnotationResult, aupViolations?: AUPViolation[], maxCorrelations?: number): ToolDetailStageBEnrichment;
36
+ //# sourceMappingURL=stageBEnrichmentBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stageBEnrichmentBuilder.d.ts","sourceRoot":"","sources":["../../../../src/lib/assessment/summarizer/stageBEnrichmentBuilder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wDAAwD,CAAC;AAC3G,OAAO,EAGL,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAKhC,MAAM,eAAe,CAAC;AA6HvB;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,kBAAkB,EAAE,EAC3B,UAAU,GAAE,MAAkC,GAC7C,2BAA2B,CA6C7B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,kBAAkB,EAAE,EAC3B,gBAAgB,CAAC,EAAE,4BAA4B,EAC/C,aAAa,CAAC,EAAE,YAAY,EAAE,EAC9B,eAAe,GAAE,MAAuC,GACvD,0BAA0B,CA4I5B"}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Stage B Enrichment Builder
3
+ *
4
+ * Functions to build Stage B enrichment data from assessment results.
5
+ * Extracts evidence, correlations, and confidence details for Claude
6
+ * semantic analysis.
7
+ *
8
+ * Issue #137: Stage A data enrichment for Stage B Claude analysis
9
+ *
10
+ * @module assessment/summarizer/stageBEnrichmentBuilder
11
+ */
12
+ import { DEFAULT_TIER2_MAX_SAMPLES, DEFAULT_TIER3_MAX_CORRELATIONS, MAX_RESPONSE_LENGTH, MAX_CONTEXT_WINDOW, } from "./stageBTypes.js";
13
+ // ============================================================================
14
+ // Helper Functions
15
+ // ============================================================================
16
+ /**
17
+ * Truncate a string to a maximum length, adding ellipsis if truncated.
18
+ */
19
+ function truncate(str, maxLength) {
20
+ if (!str)
21
+ return "";
22
+ if (str.length <= maxLength)
23
+ return str;
24
+ return str.slice(0, maxLength - 3) + "...";
25
+ }
26
+ /**
27
+ * Map test result to classification.
28
+ */
29
+ function classifyTestResult(test) {
30
+ if (test.connectionError)
31
+ return "error";
32
+ if (test.testReliability === "failed")
33
+ return "error";
34
+ if (test.vulnerable)
35
+ return "vulnerable";
36
+ return "safe";
37
+ }
38
+ /**
39
+ * Convert SecurityTestResult to PayloadCorrelation.
40
+ */
41
+ function testToCorrelation(test) {
42
+ return {
43
+ inputPayload: truncate(test.payload, MAX_RESPONSE_LENGTH),
44
+ outputResponse: truncate(test.response, MAX_RESPONSE_LENGTH),
45
+ classification: classifyTestResult(test),
46
+ matchedPatterns: test.vulnerable ? [test.testName] : [],
47
+ toolName: test.toolName || "unknown",
48
+ testName: test.testName,
49
+ confidence: test.confidence,
50
+ };
51
+ }
52
+ /**
53
+ * Convert test result to finding evidence.
54
+ */
55
+ function testToEvidence(test) {
56
+ const contextSource = test.evidence || test.response;
57
+ const location = test.evidence
58
+ ? "evidence"
59
+ : test.response
60
+ ? "response"
61
+ : "unknown";
62
+ return {
63
+ raw: truncate(test.payload, MAX_RESPONSE_LENGTH),
64
+ context: truncate(contextSource, MAX_CONTEXT_WINDOW),
65
+ location,
66
+ };
67
+ }
68
+ /**
69
+ * Calculate confidence distribution from tests.
70
+ */
71
+ function calculateConfidenceBreakdown(tests) {
72
+ const breakdown = { high: 0, medium: 0, low: 0 };
73
+ for (const test of tests) {
74
+ if (test.vulnerable) {
75
+ const confidence = test.confidence || "medium";
76
+ breakdown[confidence]++;
77
+ }
78
+ }
79
+ return breakdown;
80
+ }
81
+ /**
82
+ * Calculate pattern distribution from tests.
83
+ */
84
+ function calculatePatternDistribution(tests) {
85
+ const distribution = {};
86
+ for (const test of tests) {
87
+ if (test.vulnerable) {
88
+ const pattern = test.testName;
89
+ distribution[pattern] = (distribution[pattern] || 0) + 1;
90
+ }
91
+ }
92
+ return distribution;
93
+ }
94
+ /**
95
+ * Find the highest risk test (most concerning vulnerability).
96
+ */
97
+ function findHighestRiskTest(tests) {
98
+ const vulnerableTests = tests.filter((t) => t.vulnerable);
99
+ if (vulnerableTests.length === 0)
100
+ return undefined;
101
+ // Prioritize by risk level, then by confidence
102
+ const riskOrder = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
103
+ const confidenceOrder = { high: 0, medium: 1, low: 2 };
104
+ return vulnerableTests.sort((a, b) => {
105
+ const riskDiff = (riskOrder[a.riskLevel] ?? 4) - (riskOrder[b.riskLevel] ?? 4);
106
+ if (riskDiff !== 0)
107
+ return riskDiff;
108
+ return ((confidenceOrder[a.confidence || "medium"] ?? 1) -
109
+ (confidenceOrder[b.confidence || "medium"] ?? 1));
110
+ })[0];
111
+ }
112
+ // ============================================================================
113
+ // Tier 2: Tool Summary Enrichment Builder
114
+ // ============================================================================
115
+ /**
116
+ * Build Stage B enrichment for Tier 2 tool summaries.
117
+ *
118
+ * @param toolName - Name of the tool
119
+ * @param tests - Security test results for this tool
120
+ * @param maxSamples - Maximum evidence samples to include
121
+ * @returns Tool summary Stage B enrichment
122
+ */
123
+ export function buildToolSummaryStageBEnrichment(toolName, tests, maxSamples = DEFAULT_TIER2_MAX_SAMPLES) {
124
+ // Filter to only tests for this tool
125
+ const toolTests = tests.filter((t) => t.toolName === toolName);
126
+ // Get vulnerable tests for evidence sampling
127
+ const vulnerableTests = toolTests.filter((t) => t.vulnerable);
128
+ // Sample evidence from highest-risk vulnerabilities
129
+ const sortedVulnerable = [...vulnerableTests].sort((a, b) => {
130
+ const riskOrder = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
131
+ return (riskOrder[a.riskLevel] ?? 4) - (riskOrder[b.riskLevel] ?? 4);
132
+ });
133
+ const sampleEvidence = sortedVulnerable
134
+ .slice(0, maxSamples)
135
+ .map(testToEvidence);
136
+ // Calculate confidence breakdown
137
+ const confidenceBreakdown = calculateConfidenceBreakdown(toolTests);
138
+ // Find highest risk correlation
139
+ const highestRiskTest = findHighestRiskTest(toolTests);
140
+ const highestRiskCorrelation = highestRiskTest
141
+ ? testToCorrelation(highestRiskTest)
142
+ : undefined;
143
+ // Calculate pattern distribution
144
+ const patternDistribution = calculatePatternDistribution(toolTests);
145
+ // Check for sanitization detection
146
+ const sanitizationDetected = toolTests.some((t) => t.sanitizationDetected);
147
+ // Check auth failure mode
148
+ const authTests = toolTests.filter((t) => t.authFailureMode);
149
+ const authFailureMode = authTests.length > 0 ? authTests[0].authFailureMode : undefined;
150
+ return {
151
+ sampleEvidence,
152
+ confidenceBreakdown,
153
+ highestRiskCorrelation,
154
+ patternDistribution,
155
+ sanitizationDetected: sanitizationDetected || undefined,
156
+ authFailureMode,
157
+ };
158
+ }
159
+ // ============================================================================
160
+ // Tier 3: Tool Detail Enrichment Builder
161
+ // ============================================================================
162
+ /**
163
+ * Build Stage B enrichment for Tier 3 per-tool detail files.
164
+ *
165
+ * @param toolName - Name of the tool
166
+ * @param tests - Security test results for this tool
167
+ * @param annotationResult - Tool annotation result (if available)
168
+ * @param aupViolations - AUP violations for this tool (if any)
169
+ * @param maxCorrelations - Maximum correlations to include
170
+ * @returns Tool detail Stage B enrichment
171
+ */
172
+ export function buildToolDetailStageBEnrichment(toolName, tests, annotationResult, aupViolations, maxCorrelations = DEFAULT_TIER3_MAX_CORRELATIONS) {
173
+ // Filter to only tests for this tool
174
+ const toolTests = tests.filter((t) => t.toolName === toolName);
175
+ // Build payload correlations (prioritize vulnerable, then errors, then safe)
176
+ const sortedTests = [...toolTests].sort((a, b) => {
177
+ if (a.vulnerable && !b.vulnerable)
178
+ return -1;
179
+ if (!a.vulnerable && b.vulnerable)
180
+ return 1;
181
+ if (a.connectionError && !b.connectionError)
182
+ return -1;
183
+ if (!a.connectionError && b.connectionError)
184
+ return 1;
185
+ return 0;
186
+ });
187
+ const payloadCorrelations = sortedTests
188
+ .slice(0, maxCorrelations)
189
+ .map(testToCorrelation);
190
+ // Pattern distribution
191
+ const patternDistribution = calculatePatternDistribution(toolTests);
192
+ // Build context windows from evidence
193
+ const contextWindows = {};
194
+ for (const test of toolTests.filter((t) => t.vulnerable && t.evidence)) {
195
+ const key = `${test.testName}:${test.payload.slice(0, 30)}`;
196
+ if (!contextWindows[key]) {
197
+ contextWindows[key] = truncate(test.evidence, MAX_CONTEXT_WINDOW);
198
+ }
199
+ }
200
+ // Calculate confidence details
201
+ const confidenceBreakdown = calculateConfidenceBreakdown(toolTests);
202
+ const totalVulnerable = confidenceBreakdown.high +
203
+ confidenceBreakdown.medium +
204
+ confidenceBreakdown.low;
205
+ const overallConfidence = totalVulnerable > 0
206
+ ? Math.round(((confidenceBreakdown.high * 100 +
207
+ confidenceBreakdown.medium * 70 +
208
+ confidenceBreakdown.low * 40) /
209
+ totalVulnerable /
210
+ 100) *
211
+ 100)
212
+ : 100; // 100% confidence if no vulnerabilities
213
+ const confidenceDetails = {
214
+ overall: overallConfidence,
215
+ byCategory: patternDistribution,
216
+ requiresManualReview: toolTests.filter((t) => t.requiresManualReview)
217
+ .length,
218
+ };
219
+ // Security details
220
+ const vulnerableCount = toolTests.filter((t) => t.vulnerable).length;
221
+ const safeCount = toolTests.filter((t) => !t.vulnerable && !t.connectionError).length;
222
+ const errorCount = toolTests.filter((t) => t.connectionError).length;
223
+ // Collect sanitization libraries
224
+ const sanitizationLibraries = [
225
+ ...new Set(toolTests.flatMap((t) => t.sanitizationLibraries || []).filter(Boolean)),
226
+ ];
227
+ // Auth bypass evidence
228
+ const authBypassTest = toolTests.find((t) => t.authBypassDetected);
229
+ const authBypassEvidence = authBypassTest?.authBypassEvidence;
230
+ const securityDetails = {
231
+ vulnerableCount,
232
+ safeCount,
233
+ errorCount,
234
+ sanitizationLibraries,
235
+ authBypassEvidence,
236
+ };
237
+ // Annotation details
238
+ let annotationDetails;
239
+ if (annotationResult) {
240
+ annotationDetails = {
241
+ hasAnnotations: annotationResult.hasAnnotations,
242
+ alignmentStatus: annotationResult.alignmentStatus,
243
+ inferredBehavior: annotationResult.inferredBehavior
244
+ ? {
245
+ expectedReadOnly: annotationResult.inferredBehavior.expectedReadOnly,
246
+ expectedDestructive: annotationResult.inferredBehavior.expectedDestructive,
247
+ reason: annotationResult.inferredBehavior.reason,
248
+ }
249
+ : undefined,
250
+ descriptionPoisoning: annotationResult.descriptionPoisoning
251
+ ? {
252
+ detected: annotationResult.descriptionPoisoning.detected,
253
+ patterns: annotationResult.descriptionPoisoning.patterns.map((p) => ({
254
+ name: p.name,
255
+ evidence: truncate(p.evidence, MAX_CONTEXT_WINDOW),
256
+ severity: p.severity,
257
+ })),
258
+ }
259
+ : undefined,
260
+ };
261
+ }
262
+ // AUP violations for this tool
263
+ const toolAupViolations = aupViolations
264
+ ?.filter((v) => v.location?.includes(toolName))
265
+ .map((v) => ({
266
+ pattern: v.pattern,
267
+ matchedText: truncate(v.matchedText, MAX_CONTEXT_WINDOW),
268
+ severity: v.severity,
269
+ location: v.location,
270
+ }));
271
+ return {
272
+ payloadCorrelations,
273
+ patternDistribution,
274
+ contextWindows,
275
+ confidenceDetails,
276
+ securityDetails,
277
+ annotationDetails,
278
+ aupViolations: toolAupViolations && toolAupViolations.length > 0
279
+ ? toolAupViolations
280
+ : undefined,
281
+ };
282
+ }