feat: initial open marketplace with llm-security, config-audit, ultraplan-local

This commit is contained in:
Kjell Tore Guttormsen 2026-04-06 18:47:49 +02:00
commit f93d6abdae
380 changed files with 65935 additions and 0 deletions

View file

@ -0,0 +1,288 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { diffEnvelopes, formatDiffReport } from '../../scanners/lib/diff-engine.mjs';
// --- Helpers ---
function makeFinding(scanner, title, severity = 'medium', file = null) {
return {
id: `CA-${scanner}-001`,
scanner,
severity,
title,
description: `Description for ${title}`,
file,
line: null,
evidence: null,
category: null,
recommendation: null,
autoFixable: false,
};
}
function makeScannerResult(scanner, findings) {
const counts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
for (const f of findings) {
if (counts[f.severity] !== undefined) counts[f.severity]++;
}
return {
scanner,
status: 'ok',
files_scanned: 3,
duration_ms: 10,
findings,
counts,
};
}
function makeEnvelope(scannerResults) {
const aggregate = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
let total = 0;
for (const r of scannerResults) {
for (const sev of Object.keys(aggregate)) {
aggregate[sev] += (r.counts[sev] || 0);
}
total += r.findings.length;
}
return {
meta: { target: '/test', timestamp: new Date().toISOString(), version: '2.0.0', tool: 'config-audit' },
scanners: scannerResults,
aggregate: { total_findings: total, counts: aggregate, risk_score: 0, risk_band: 'Low', verdict: 'PASS', scanners_ok: scannerResults.length, scanners_error: 0, scanners_skipped: 0 },
};
}
// ========================================
// diffEnvelopes
// ========================================
describe('diffEnvelopes', () => {
it('identifies new findings', () => {
const baseline = makeEnvelope([makeScannerResult('CML', [])]);
const current = makeEnvelope([
makeScannerResult('CML', [makeFinding('CML', 'New issue', 'high', 'CLAUDE.md')]),
]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.newFindings.length, 1);
assert.equal(diff.newFindings[0].title, 'New issue');
assert.equal(diff.resolvedFindings.length, 0);
});
it('identifies resolved findings', () => {
const baseline = makeEnvelope([
makeScannerResult('CML', [makeFinding('CML', 'Old issue', 'high', 'CLAUDE.md')]),
]);
const current = makeEnvelope([makeScannerResult('CML', [])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.resolvedFindings.length, 1);
assert.equal(diff.resolvedFindings[0].title, 'Old issue');
assert.equal(diff.newFindings.length, 0);
});
it('identifies unchanged findings', () => {
const f = makeFinding('CML', 'Persistent issue', 'medium', 'CLAUDE.md');
const baseline = makeEnvelope([makeScannerResult('CML', [f])]);
const current = makeEnvelope([makeScannerResult('CML', [{ ...f }])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.unchangedFindings.length, 1);
assert.equal(diff.newFindings.length, 0);
assert.equal(diff.resolvedFindings.length, 0);
});
it('detects moved findings (same title, different file)', () => {
const baseFinding = makeFinding('CML', 'Moved issue', 'high', 'old-file.md');
const currFinding = makeFinding('CML', 'Moved issue', 'high', 'new-file.md');
const baseline = makeEnvelope([makeScannerResult('CML', [baseFinding])]);
const current = makeEnvelope([makeScannerResult('CML', [currFinding])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.movedFindings.length, 1);
assert.equal(diff.movedFindings[0].from.file, 'old-file.md');
assert.equal(diff.movedFindings[0].to.file, 'new-file.md');
assert.equal(diff.newFindings.length, 0);
assert.equal(diff.resolvedFindings.length, 0);
});
it('calculates score delta', () => {
const baseline = makeEnvelope([
makeScannerResult('CML', [
makeFinding('CML', 'A', 'high', 'a.md'),
makeFinding('CML', 'B', 'high', 'a.md'),
makeFinding('CML', 'C', 'high', 'a.md'),
]),
]);
const current = makeEnvelope([makeScannerResult('CML', [])]);
const diff = diffEnvelopes(baseline, current);
assert.ok(diff.scoreChange.delta > 0, 'Score should improve when findings are resolved');
assert.equal(typeof diff.scoreChange.before.grade, 'string');
assert.equal(typeof diff.scoreChange.after.grade, 'string');
});
it('calculates area changes', () => {
const baseline = makeEnvelope([
makeScannerResult('CML', [makeFinding('CML', 'X', 'low', 'a.md')]),
makeScannerResult('SET', []),
]);
const current = makeEnvelope([
makeScannerResult('CML', []),
makeScannerResult('SET', [makeFinding('SET', 'Y', 'low', 'b.json')]),
]);
const diff = diffEnvelopes(baseline, current);
assert.ok(diff.areaChanges.length >= 2);
const cmlChange = diff.areaChanges.find(a => a.name === 'CLAUDE.md');
assert.ok(cmlChange, 'Should have CLAUDE.md area change');
assert.ok(cmlChange.delta > 0, 'CLAUDE.md should improve');
});
it('detects improving trend', () => {
const baseline = makeEnvelope([
makeScannerResult('CML', [
makeFinding('CML', 'A', 'high', 'a.md'),
makeFinding('CML', 'B', 'high', 'a.md'),
]),
]);
const current = makeEnvelope([makeScannerResult('CML', [])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.summary.trend, 'improving');
});
it('detects degrading trend', () => {
const baseline = makeEnvelope([makeScannerResult('CML', [])]);
const current = makeEnvelope([
makeScannerResult('CML', [
makeFinding('CML', 'A', 'high', 'a.md'),
makeFinding('CML', 'B', 'high', 'a.md'),
]),
]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.summary.trend, 'degrading');
});
it('detects stable trend (same findings)', () => {
const f = makeFinding('CML', 'Same', 'medium', 'a.md');
const baseline = makeEnvelope([makeScannerResult('CML', [f])]);
const current = makeEnvelope([makeScannerResult('CML', [{ ...f }])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.summary.trend, 'stable');
});
it('handles empty baseline', () => {
const baseline = makeEnvelope([]);
const current = makeEnvelope([
makeScannerResult('CML', [makeFinding('CML', 'New', 'low', 'a.md')]),
]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.newFindings.length, 1);
assert.equal(diff.resolvedFindings.length, 0);
assert.equal(diff.summary.totalBefore, 0);
});
it('handles identical envelopes (all unchanged)', () => {
const f1 = makeFinding('CML', 'Issue A', 'medium', 'a.md');
const f2 = makeFinding('SET', 'Issue B', 'low', 'b.json');
const baseline = makeEnvelope([
makeScannerResult('CML', [f1]),
makeScannerResult('SET', [f2]),
]);
const current = makeEnvelope([
makeScannerResult('CML', [{ ...f1 }]),
makeScannerResult('SET', [{ ...f2 }]),
]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.unchangedFindings.length, 2);
assert.equal(diff.newFindings.length, 0);
assert.equal(diff.resolvedFindings.length, 0);
assert.equal(diff.movedFindings.length, 0);
assert.equal(diff.summary.trend, 'stable');
});
it('summary has correct counts', () => {
const baseline = makeEnvelope([
makeScannerResult('CML', [
makeFinding('CML', 'Keep', 'low', 'a.md'),
makeFinding('CML', 'Resolve', 'high', 'b.md'),
]),
]);
const current = makeEnvelope([
makeScannerResult('CML', [
makeFinding('CML', 'Keep', 'low', 'a.md'),
makeFinding('CML', 'Brand new', 'medium', 'c.md'),
]),
]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.summary.totalBefore, 2);
assert.equal(diff.summary.totalAfter, 2);
assert.equal(diff.summary.newCount, 1);
assert.equal(diff.summary.resolvedCount, 1);
});
it('handles findings with null file gracefully', () => {
const f = makeFinding('CML', 'No file', 'info', null);
const baseline = makeEnvelope([makeScannerResult('CML', [f])]);
const current = makeEnvelope([makeScannerResult('CML', [{ ...f }])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.unchangedFindings.length, 1);
});
it('multiple findings with same key are matched correctly', () => {
const f1 = makeFinding('CML', 'Duplicate', 'low', 'a.md');
const f2 = makeFinding('CML', 'Duplicate', 'low', 'a.md');
const baseline = makeEnvelope([makeScannerResult('CML', [f1, f2])]);
const current = makeEnvelope([makeScannerResult('CML', [{ ...f1 }])]);
const diff = diffEnvelopes(baseline, current);
assert.equal(diff.unchangedFindings.length, 1);
assert.equal(diff.resolvedFindings.length, 1);
});
});
// ========================================
// formatDiffReport
// ========================================
describe('formatDiffReport', () => {
it('returns a non-empty string', () => {
const diff = diffEnvelopes(makeEnvelope([]), makeEnvelope([]));
const report = formatDiffReport(diff);
assert.ok(report.length > 0);
assert.equal(typeof report, 'string');
});
it('contains header', () => {
const diff = diffEnvelopes(makeEnvelope([]), makeEnvelope([]));
const report = formatDiffReport(diff);
assert.ok(report.includes('Config-Audit Drift Report'));
});
it('shows trend', () => {
const baseline = makeEnvelope([
makeScannerResult('CML', [makeFinding('CML', 'X', 'high', 'a.md')]),
]);
const current = makeEnvelope([makeScannerResult('CML', [])]);
const diff = diffEnvelopes(baseline, current);
const report = formatDiffReport(diff);
assert.ok(report.includes('Improving'));
});
it('lists new findings', () => {
const baseline = makeEnvelope([makeScannerResult('CML', [])]);
const current = makeEnvelope([
makeScannerResult('CML', [makeFinding('CML', 'Fresh issue', 'high', 'x.md')]),
]);
const diff = diffEnvelopes(baseline, current);
const report = formatDiffReport(diff);
assert.ok(report.includes('Fresh issue'));
assert.ok(report.includes('New findings'));
});
});