feat(scanner): add --benchmark mode to attack-simulator with structured reporting
This commit is contained in:
parent
e2c8924074
commit
0765a5595e
2 changed files with 164 additions and 0 deletions
69
plugins/llm-security/tests/scanners/benchmark.test.mjs
Normal file
69
plugins/llm-security/tests/scanners/benchmark.test.mjs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// benchmark.test.mjs — Tests for --benchmark mode in attack-simulator.mjs
|
||||
// Verifies: flag parsing, report schema, block rates are valid numbers
|
||||
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolve } from 'node:path';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { formatBenchmarkJson } from '../../scanners/attack-simulator.mjs';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const SIMULATOR = resolve(__dirname, '../../scanners/attack-simulator.mjs');
|
||||
|
||||
function run(args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
execFile('node', [SIMULATOR, ...args], { timeout: 120_000 }, (err, stdout, stderr) => {
|
||||
resolve({ err, stdout, stderr, code: err?.code ?? 0 });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('attack-simulator --benchmark', () => {
|
||||
it('--benchmark --json produces valid JSON with required fields', async () => {
|
||||
const { stdout } = await run(['--benchmark', '--json']);
|
||||
const d = JSON.parse(stdout);
|
||||
|
||||
// Meta fields
|
||||
assert.ok(d.meta, 'Should have meta');
|
||||
assert.ok(d.meta.timestamp, 'Should have timestamp');
|
||||
assert.ok(d.meta.version, 'Should have version');
|
||||
assert.ok(d.meta.node_version, 'Should have node_version');
|
||||
assert.equal(typeof d.meta.scenarios_total, 'number');
|
||||
|
||||
// Summary fields
|
||||
assert.ok(d.summary, 'Should have summary');
|
||||
assert.equal(typeof d.summary.block_rate, 'number');
|
||||
assert.ok(d.summary.block_rate >= 0 && d.summary.block_rate <= 1, 'block_rate should be 0-1');
|
||||
assert.equal(typeof d.summary.adaptive_block_rate, 'number');
|
||||
assert.ok(d.summary.adaptive_block_rate >= 0 && d.summary.adaptive_block_rate <= 1);
|
||||
assert.equal(typeof d.summary.total_blocked, 'number');
|
||||
assert.equal(typeof d.summary.total_bypassed, 'number');
|
||||
|
||||
// Categories
|
||||
assert.ok(d.categories, 'Should have categories');
|
||||
assert.equal(typeof d.categories, 'object');
|
||||
|
||||
// Methodology
|
||||
assert.ok(d.methodology, 'Should have methodology string');
|
||||
assert.equal(typeof d.methodology, 'string');
|
||||
});
|
||||
|
||||
it('formatBenchmarkJson returns valid structure from mock data', () => {
|
||||
const mockFixed = [
|
||||
{ id: 'S01', name: 'test', category: 'secrets', passed: true, detail: '' },
|
||||
{ id: 'S02', name: 'test2', category: 'secrets', passed: false, detail: 'gap' },
|
||||
];
|
||||
const mockAdaptive = [
|
||||
{ scenarioId: 'S01', mutation: 'homoglyph', round: 2, bypassed: true },
|
||||
];
|
||||
const result = formatBenchmarkJson(mockFixed, mockAdaptive, 1000);
|
||||
|
||||
assert.equal(result.meta.mode, 'benchmark');
|
||||
assert.equal(result.summary.block_rate, 0.5);
|
||||
assert.equal(typeof result.summary.adaptive_block_rate, 'number');
|
||||
assert.ok(result.categories.secrets);
|
||||
assert.equal(result.categories.secrets.scenarios, 2);
|
||||
assert.equal(result.categories.secrets.blocked, 1);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue