@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.
- package/cli/build/__tests__/stage3-fix-validation.test.js +163 -0
- package/cli/build/__tests__/stage3-fixes.test.js +516 -0
- package/cli/build/lib/cli-parser.js +7 -0
- package/cli/build/lib/cli-parserSchemas.js +3 -0
- package/cli/build/lib/jsonl-events.js +3 -0
- package/cli/build/lib/result-output.js +8 -2
- package/cli/package.json +1 -1
- package/client/dist/assets/{OAuthCallback-DC1cIXHT.js → OAuthCallback-CUf6mvrP.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-C3gqJjgQ.js → OAuthDebugCallback-DkfPOggR.js} +1 -1
- package/client/dist/assets/{index-Dn2w887x.js → index-uinVACY4.js} +4 -4
- package/client/dist/index.html +1 -1
- package/client/lib/lib/assessment/summarizer/AssessmentSummarizer.d.ts.map +1 -1
- package/client/lib/lib/assessment/summarizer/AssessmentSummarizer.js +14 -1
- package/client/lib/lib/assessment/summarizer/index.d.ts +4 -0
- package/client/lib/lib/assessment/summarizer/index.d.ts.map +1 -1
- package/client/lib/lib/assessment/summarizer/index.js +4 -0
- package/client/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.d.ts +36 -0
- package/client/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.d.ts.map +1 -0
- package/client/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.js +282 -0
- package/client/lib/lib/assessment/summarizer/stageBTypes.d.ts +154 -0
- package/client/lib/lib/assessment/summarizer/stageBTypes.d.ts.map +1 -0
- package/client/lib/lib/assessment/summarizer/stageBTypes.js +24 -0
- package/client/lib/lib/assessment/summarizer/types.d.ts +5 -0
- package/client/lib/lib/assessment/summarizer/types.d.ts.map +1 -1
- package/client/lib/lib/assessment/summarizer/types.js +1 -0
- package/client/lib/lib/moduleScoring.d.ts +2 -1
- package/client/lib/lib/moduleScoring.d.ts.map +1 -1
- package/client/lib/lib/moduleScoring.js +2 -1
- package/client/package.json +1 -1
- package/package.json +1 -1
- 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
|
-
|
|
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
|
-
|
|
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,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-
|
|
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);
|
package/client/dist/assets/{OAuthDebugCallback-C3gqJjgQ.js → OAuthDebugCallback-DkfPOggR.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-
|
|
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.
|
|
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.
|
|
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-
|
|
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-
|
|
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
|
}
|
package/client/dist/index.html
CHANGED
|
@@ -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-
|
|
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;
|
|
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
|
-
|
|
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
|
|
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
|
+
}
|