@bryan-thompson/inspector-assessment-cli 1.20.2 → 1.20.3
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/build/assess-full.js +28 -5
- package/build/lib/jsonl-events.js +157 -0
- package/package.json +1 -1
package/build/assess-full.js
CHANGED
|
@@ -25,6 +25,7 @@ import { generatePolicyComplianceReport } from "../../client/lib/services/assess
|
|
|
25
25
|
import { compareAssessments } from "../../client/lib/lib/assessmentDiffer.js";
|
|
26
26
|
import { formatDiffAsMarkdown } from "../../client/lib/lib/reportFormatters/DiffReportFormatter.js";
|
|
27
27
|
import { AssessmentStateManager } from "./assessmentState.js";
|
|
28
|
+
import { emitServerConnected, emitToolDiscovered, emitToolsDiscoveryComplete, emitAssessmentComplete, emitTestBatch, emitVulnerabilityFound, emitAnnotationMissing, emitAnnotationMisaligned, emitAnnotationReviewRecommended, } from "./lib/jsonl-events.js";
|
|
28
29
|
/**
|
|
29
30
|
* Load server configuration from Claude Code's MCP settings
|
|
30
31
|
*/
|
|
@@ -293,18 +294,17 @@ async function runFullAssessment(options) {
|
|
|
293
294
|
console.log("✅ Server config loaded");
|
|
294
295
|
}
|
|
295
296
|
const client = await connectToServer(serverConfig);
|
|
297
|
+
emitServerConnected(options.serverName, serverConfig.transport || "stdio");
|
|
296
298
|
if (!options.jsonOnly) {
|
|
297
299
|
console.log("✅ Connected to MCP server");
|
|
298
300
|
}
|
|
299
301
|
const response = await client.listTools();
|
|
300
302
|
const tools = response.tools || [];
|
|
301
|
-
//
|
|
302
|
-
// Format: TOOL_DISCOVERED:name|description|param1,param2,... (works even with --json flag)
|
|
303
|
+
// Emit JSONL tool discovery events for audit-worker parsing
|
|
303
304
|
for (const tool of tools) {
|
|
304
|
-
|
|
305
|
-
const params = Object.keys(tool.inputSchema?.properties || {}).join(",");
|
|
306
|
-
console.error(`TOOL_DISCOVERED:${tool.name}|${description}|${params}`);
|
|
305
|
+
emitToolDiscovered(tool);
|
|
307
306
|
}
|
|
307
|
+
emitToolsDiscoveryComplete(tools.length);
|
|
308
308
|
if (!options.jsonOnly) {
|
|
309
309
|
console.log(`🔧 Found ${tools.length} tool${tools.length !== 1 ? "s" : ""}`);
|
|
310
310
|
}
|
|
@@ -483,12 +483,32 @@ async function runFullAssessment(options) {
|
|
|
483
483
|
})),
|
|
484
484
|
};
|
|
485
485
|
};
|
|
486
|
+
// Progress callback to emit JSONL events for real-time monitoring
|
|
487
|
+
const onProgress = (event) => {
|
|
488
|
+
if (event.type === "test_batch") {
|
|
489
|
+
emitTestBatch(event.module, event.completed, event.total, event.batchSize, event.elapsed);
|
|
490
|
+
}
|
|
491
|
+
else if (event.type === "vulnerability_found") {
|
|
492
|
+
emitVulnerabilityFound(event.tool, event.pattern, event.confidence, event.evidence, event.riskLevel, event.requiresReview, event.payload);
|
|
493
|
+
}
|
|
494
|
+
else if (event.type === "annotation_missing") {
|
|
495
|
+
emitAnnotationMissing(event.tool, event.title, event.description, event.parameters, event.inferredBehavior);
|
|
496
|
+
}
|
|
497
|
+
else if (event.type === "annotation_misaligned") {
|
|
498
|
+
emitAnnotationMisaligned(event.tool, event.title, event.description, event.parameters, event.field, event.actual, event.expected, event.confidence, event.reason);
|
|
499
|
+
}
|
|
500
|
+
else if (event.type === "annotation_review_recommended") {
|
|
501
|
+
emitAnnotationReviewRecommended(event.tool, event.title, event.description, event.parameters, event.field, event.actual, event.inferred, event.confidence, event.isAmbiguous, event.reason);
|
|
502
|
+
}
|
|
503
|
+
// module_started and module_complete are handled by orchestrator directly
|
|
504
|
+
};
|
|
486
505
|
const context = {
|
|
487
506
|
serverName: options.serverName,
|
|
488
507
|
tools,
|
|
489
508
|
callTool: createCallToolWrapper(client),
|
|
490
509
|
config,
|
|
491
510
|
sourceCodePath: options.sourceCodePath,
|
|
511
|
+
onProgress,
|
|
492
512
|
...sourceFiles,
|
|
493
513
|
// New capability assessment data
|
|
494
514
|
resources,
|
|
@@ -502,6 +522,9 @@ async function runFullAssessment(options) {
|
|
|
502
522
|
console.log("");
|
|
503
523
|
}
|
|
504
524
|
const results = await orchestrator.runFullAssessment(context);
|
|
525
|
+
// Emit assessment complete event
|
|
526
|
+
const defaultOutputPath = `/tmp/inspector-full-assessment-${options.serverName}.json`;
|
|
527
|
+
emitAssessmentComplete(results.overallStatus, results.totalTestsRun, results.executionTime, options.outputPath || defaultOutputPath);
|
|
505
528
|
await client.close();
|
|
506
529
|
return results;
|
|
507
530
|
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL Event Emission Helpers for CLI
|
|
3
|
+
*
|
|
4
|
+
* These functions emit structured JSONL events to stderr for real-time
|
|
5
|
+
* machine parsing during CLI assessment runs.
|
|
6
|
+
*
|
|
7
|
+
* This is a CLI-local version that imports from the built client lib
|
|
8
|
+
* to avoid rootDir conflicts in TypeScript compilation.
|
|
9
|
+
*/
|
|
10
|
+
import { INSPECTOR_VERSION } from "../../../client/lib/lib/moduleScoring.js";
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Core Functions
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Emit a JSONL event to stderr for real-time machine parsing.
|
|
16
|
+
* Automatically includes version field for compatibility checking.
|
|
17
|
+
*/
|
|
18
|
+
export function emitJSONL(event) {
|
|
19
|
+
console.error(JSON.stringify({ ...event, version: INSPECTOR_VERSION }));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Emit server_connected event after successful connection.
|
|
23
|
+
*/
|
|
24
|
+
export function emitServerConnected(serverName, transport) {
|
|
25
|
+
emitJSONL({ event: "server_connected", serverName, transport });
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract parameter metadata from tool input schema.
|
|
29
|
+
*/
|
|
30
|
+
export function extractToolParams(schema) {
|
|
31
|
+
if (!schema || typeof schema !== "object")
|
|
32
|
+
return [];
|
|
33
|
+
const s = schema;
|
|
34
|
+
if (!s.properties || typeof s.properties !== "object")
|
|
35
|
+
return [];
|
|
36
|
+
const required = new Set(Array.isArray(s.required) ? s.required : []);
|
|
37
|
+
const properties = s.properties;
|
|
38
|
+
return Object.entries(properties).map(([name, prop]) => {
|
|
39
|
+
const param = {
|
|
40
|
+
name,
|
|
41
|
+
type: prop.type || "any",
|
|
42
|
+
required: required.has(name),
|
|
43
|
+
};
|
|
44
|
+
if (prop.description) {
|
|
45
|
+
param.description = prop.description;
|
|
46
|
+
}
|
|
47
|
+
return param;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Emit tool_discovered event for each tool found.
|
|
52
|
+
*/
|
|
53
|
+
export function emitToolDiscovered(tool) {
|
|
54
|
+
const params = extractToolParams(tool.inputSchema);
|
|
55
|
+
emitJSONL({
|
|
56
|
+
event: "tool_discovered",
|
|
57
|
+
name: tool.name,
|
|
58
|
+
description: tool.description || null,
|
|
59
|
+
params,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Emit tools_discovery_complete event after all tools discovered.
|
|
64
|
+
*/
|
|
65
|
+
export function emitToolsDiscoveryComplete(count) {
|
|
66
|
+
emitJSONL({ event: "tools_discovery_complete", count });
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Emit assessment_complete event at the end of assessment.
|
|
70
|
+
*/
|
|
71
|
+
export function emitAssessmentComplete(overallStatus, totalTests, executionTime, outputPath) {
|
|
72
|
+
emitJSONL({
|
|
73
|
+
event: "assessment_complete",
|
|
74
|
+
overallStatus,
|
|
75
|
+
totalTests,
|
|
76
|
+
executionTime,
|
|
77
|
+
outputPath,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Emit test_batch event during assessment for real-time progress.
|
|
82
|
+
*/
|
|
83
|
+
export function emitTestBatch(module, completed, total, batchSize, elapsed) {
|
|
84
|
+
emitJSONL({
|
|
85
|
+
event: "test_batch",
|
|
86
|
+
module,
|
|
87
|
+
completed,
|
|
88
|
+
total,
|
|
89
|
+
batchSize,
|
|
90
|
+
elapsed,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Emit vulnerability_found event when security testing detects issues.
|
|
95
|
+
*/
|
|
96
|
+
export function emitVulnerabilityFound(tool, pattern, confidence, evidence, riskLevel, requiresReview, payload) {
|
|
97
|
+
emitJSONL({
|
|
98
|
+
event: "vulnerability_found",
|
|
99
|
+
tool,
|
|
100
|
+
pattern,
|
|
101
|
+
confidence,
|
|
102
|
+
evidence,
|
|
103
|
+
riskLevel,
|
|
104
|
+
requiresReview,
|
|
105
|
+
...(payload && { payload }),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Emit annotation_missing event when a tool lacks required annotations.
|
|
110
|
+
*/
|
|
111
|
+
export function emitAnnotationMissing(tool, title, description, parameters, inferredBehavior) {
|
|
112
|
+
emitJSONL({
|
|
113
|
+
event: "annotation_missing",
|
|
114
|
+
tool,
|
|
115
|
+
...(title && { title }),
|
|
116
|
+
...(description && { description }),
|
|
117
|
+
parameters,
|
|
118
|
+
inferredBehavior,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Emit annotation_misaligned event when actual annotations contradict inferred behavior.
|
|
123
|
+
*/
|
|
124
|
+
export function emitAnnotationMisaligned(tool, title, description, parameters, field, actual, expected, confidence, reason) {
|
|
125
|
+
emitJSONL({
|
|
126
|
+
event: "annotation_misaligned",
|
|
127
|
+
tool,
|
|
128
|
+
...(title && { title }),
|
|
129
|
+
...(description && { description }),
|
|
130
|
+
parameters,
|
|
131
|
+
field,
|
|
132
|
+
actual,
|
|
133
|
+
expected,
|
|
134
|
+
confidence,
|
|
135
|
+
reason,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Emit annotation_review_recommended event for ambiguous patterns.
|
|
140
|
+
* This indicates human review is suggested but no automated penalty applied.
|
|
141
|
+
* Used for patterns like store_*, queue_*, cache_* where behavior varies.
|
|
142
|
+
*/
|
|
143
|
+
export function emitAnnotationReviewRecommended(tool, title, description, parameters, field, actual, inferred, confidence, isAmbiguous, reason) {
|
|
144
|
+
emitJSONL({
|
|
145
|
+
event: "annotation_review_recommended",
|
|
146
|
+
tool,
|
|
147
|
+
...(title && { title }),
|
|
148
|
+
...(description && { description }),
|
|
149
|
+
parameters,
|
|
150
|
+
field,
|
|
151
|
+
actual,
|
|
152
|
+
inferred,
|
|
153
|
+
confidence,
|
|
154
|
+
isAmbiguous,
|
|
155
|
+
reason,
|
|
156
|
+
});
|
|
157
|
+
}
|
package/package.json
CHANGED