mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-07-02 03:25:49 +02:00
feat: use structured outputs for vuln agent exploitation queues (#267)
* feat: add structured outputs for vuln agent exploitation queues Use Claude Agent SDK's native outputFormat to get schema-validated JSON queue data from vulnerability analysis agents instead of relying on save-deliverable tool calls for queue files. - Add Zod schemas for all 5 vuln types (injection, xss, auth, ssrf, authz) - Thread outputFormat through SDK call chain (executor → message handlers) - Write structured_output to disk as queue JSON before validation - Handle error_max_structured_output_retries as retryable failure - Update vuln prompts to use structured output for queues - Keep save-deliverable for markdown deliverables (unchanged) * fix: correct structured output schema conversion for Claude Agent SDK Use draft-07 target for z.toJSONSchema() instead of the default draft-2020-12, which the SDK's AJV validator doesn't support. Update pipeline-testing prompts to use structured output instead of raw JSON responses. * refactor: remove save-deliverable references for queues in vuln prompts Queues are now captured via structured outputs, so vuln agents no longer need to use save-deliverable for queue JSON. Removes references to "structured response/output" phrasing and aligns all prompts to use consistent "exploitation queue" terminology. * refactor: remove queue support from save-deliverable Queues are now produced via structured outputs, so save-deliverable no longer needs queue-related code. Removes queue enum values, filename mappings, JSON validation, and updates all prompt tool descriptions to match the simplified CLI interface. * fix: instruct vuln agents to save deliverable before exploitation queue The structured output tool terminates the agent session when called. Agents were calling it before saving their deliverable markdown, causing output validation failures and unnecessary retries. * refactor: remove explicit exploitation queue output instructions from vuln prompts The Claude Agent SDK automatically captures structured output on the last turn when outputFormat is set. Prompts explicitly telling agents to produce the queue caused them to call StructuredOutput mid-session, conflicting with the SDK mechanism and silently dropping the output. Removed exploitation_queue_requirements sections and queue references from conclusion triggers. Added note that the queue is captured automatically. Updated Your Output to point to the deliverable markdown.
This commit is contained in:
@@ -9,17 +9,15 @@
|
||||
/**
|
||||
* save-deliverable CLI
|
||||
*
|
||||
* Standalone script to save deliverable files with validation.
|
||||
* Replaces the MCP save_deliverable tool.
|
||||
* Standalone script to save deliverable files.
|
||||
*
|
||||
* Usage:
|
||||
* node save-deliverable.js --type INJECTION_QUEUE --content '{"vulnerabilities": [...]}'
|
||||
* node save-deliverable.js --type INJECTION_ANALYSIS --file-path deliverables/injection_analysis_deliverable.md
|
||||
*/
|
||||
|
||||
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { DELIVERABLE_FILENAMES, type DeliverableType, isQueueType } from '../types/deliverables.js';
|
||||
import { DELIVERABLE_FILENAMES, type DeliverableType } from '../types/deliverables.js';
|
||||
|
||||
// === Argument Parsing ===
|
||||
|
||||
@@ -51,49 +49,6 @@ function parseArgs(argv: string[]): ParsedArgs {
|
||||
return args;
|
||||
}
|
||||
|
||||
// === Queue Validation ===
|
||||
|
||||
interface ValidationResult {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
function validateQueueJson(content: string): ValidationResult {
|
||||
try {
|
||||
const parsed = JSON.parse(content) as unknown;
|
||||
|
||||
if (typeof parsed !== 'object' || parsed === null) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid queue structure: Expected an object. Got: ${typeof parsed}`,
|
||||
};
|
||||
}
|
||||
|
||||
const obj = parsed as Record<string, unknown>;
|
||||
|
||||
if (!('vulnerabilities' in obj)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid queue structure: Missing 'vulnerabilities' property. Expected: {"vulnerabilities": [...]}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (!Array.isArray(obj.vulnerabilities)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid queue structure: 'vulnerabilities' must be an array. Expected: {"vulnerabilities": [...]}`,
|
||||
};
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// === File Operations ===
|
||||
|
||||
function saveDeliverableFile(targetDir: string, filename: string, content: string): string {
|
||||
@@ -165,22 +120,11 @@ function main(): void {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 3. Validate queue types
|
||||
let validated = false;
|
||||
if (isQueueType(args.type)) {
|
||||
const validation = validateQueueJson(content);
|
||||
if (!validation.valid) {
|
||||
console.log(JSON.stringify({ status: 'error', message: validation.message, retryable: true }));
|
||||
process.exit(1);
|
||||
}
|
||||
validated = true;
|
||||
}
|
||||
|
||||
// 4. Save the file
|
||||
// 3. Save the file
|
||||
try {
|
||||
const targetDir = process.cwd();
|
||||
const filepath = saveDeliverableFile(targetDir, filename, content);
|
||||
console.log(JSON.stringify({ status: 'success', filepath, validated }));
|
||||
console.log(JSON.stringify({ status: 'success', filepath }));
|
||||
} catch (error) {
|
||||
const msg = error instanceof Error ? error.message : String(error);
|
||||
console.log(JSON.stringify({ status: 'error', message: `Failed to save: ${msg}`, retryable: true }));
|
||||
|
||||
Reference in New Issue
Block a user