feat: initial open marketplace with llm-security, config-audit, ultraplan-local
This commit is contained in:
commit
f93d6abdae
380 changed files with 65935 additions and 0 deletions
199
plugins/config-audit/tests/lib/suppression.test.mjs
Normal file
199
plugins/config-audit/tests/lib/suppression.test.mjs
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { join } from 'node:path';
|
||||
import { writeFile, mkdir, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import {
|
||||
loadSuppressions,
|
||||
parseIgnoreFile,
|
||||
applySuppressions,
|
||||
formatSuppressionSummary,
|
||||
} from '../../scanners/lib/suppression.mjs';
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
function makeFinding(id, scanner, severity = 'medium') {
|
||||
return {
|
||||
id,
|
||||
scanner,
|
||||
severity,
|
||||
title: `Finding ${id}`,
|
||||
description: `Description for ${id}`,
|
||||
file: null,
|
||||
line: null,
|
||||
evidence: null,
|
||||
category: null,
|
||||
recommendation: null,
|
||||
autoFixable: false,
|
||||
};
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// parseIgnoreFile
|
||||
// ========================================
|
||||
describe('parseIgnoreFile', () => {
|
||||
it('parses exact finding IDs', () => {
|
||||
const result = parseIgnoreFile('CA-CML-001\nCA-SET-003');
|
||||
assert.equal(result.length, 2);
|
||||
assert.equal(result[0].pattern, 'CA-CML-001');
|
||||
assert.equal(result[1].pattern, 'CA-SET-003');
|
||||
});
|
||||
|
||||
it('parses glob patterns', () => {
|
||||
const result = parseIgnoreFile('CA-GAP-*');
|
||||
assert.equal(result.length, 1);
|
||||
assert.equal(result[0].pattern, 'CA-GAP-*');
|
||||
});
|
||||
|
||||
it('skips comments and empty lines', () => {
|
||||
const content = `# This is a comment
|
||||
CA-CML-001
|
||||
|
||||
# Another comment
|
||||
|
||||
CA-SET-002`;
|
||||
const result = parseIgnoreFile(content);
|
||||
assert.equal(result.length, 2);
|
||||
});
|
||||
|
||||
it('extracts inline comments', () => {
|
||||
const result = parseIgnoreFile('CA-HKV-003 # Known timeout in CI');
|
||||
assert.equal(result.length, 1);
|
||||
assert.equal(result[0].pattern, 'CA-HKV-003');
|
||||
assert.equal(result[0].comment, 'Known timeout in CI');
|
||||
});
|
||||
|
||||
it('returns empty array for empty content', () => {
|
||||
const result = parseIgnoreFile('');
|
||||
assert.deepEqual(result, []);
|
||||
});
|
||||
|
||||
it('returns empty array for comment-only content', () => {
|
||||
const result = parseIgnoreFile('# Just comments\n# Nothing else');
|
||||
assert.deepEqual(result, []);
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// applySuppressions
|
||||
// ========================================
|
||||
describe('applySuppressions', () => {
|
||||
it('filters exact match', () => {
|
||||
const findings = [
|
||||
makeFinding('CA-CML-001', 'CML'),
|
||||
makeFinding('CA-CML-002', 'CML'),
|
||||
];
|
||||
const suppressions = [{ pattern: 'CA-CML-001', comment: '' }];
|
||||
const { active, suppressed } = applySuppressions(findings, suppressions);
|
||||
|
||||
assert.equal(active.length, 1);
|
||||
assert.equal(active[0].id, 'CA-CML-002');
|
||||
assert.equal(suppressed.length, 1);
|
||||
assert.equal(suppressed[0].id, 'CA-CML-001');
|
||||
});
|
||||
|
||||
it('filters glob pattern CA-SET-*', () => {
|
||||
const findings = [
|
||||
makeFinding('CA-SET-001', 'SET'),
|
||||
makeFinding('CA-SET-002', 'SET'),
|
||||
makeFinding('CA-CML-001', 'CML'),
|
||||
];
|
||||
const suppressions = [{ pattern: 'CA-SET-*', comment: '' }];
|
||||
const { active, suppressed } = applySuppressions(findings, suppressions);
|
||||
|
||||
assert.equal(active.length, 1);
|
||||
assert.equal(active[0].id, 'CA-CML-001');
|
||||
assert.equal(suppressed.length, 2);
|
||||
});
|
||||
|
||||
it('returns all active when no suppressions', () => {
|
||||
const findings = [makeFinding('CA-CML-001', 'CML')];
|
||||
const { active, suppressed } = applySuppressions(findings, []);
|
||||
|
||||
assert.equal(active.length, 1);
|
||||
assert.equal(suppressed.length, 0);
|
||||
});
|
||||
|
||||
it('returns all active when suppressions is null', () => {
|
||||
const findings = [makeFinding('CA-CML-001', 'CML')];
|
||||
const { active, suppressed } = applySuppressions(findings, null);
|
||||
|
||||
assert.equal(active.length, 1);
|
||||
assert.equal(suppressed.length, 0);
|
||||
});
|
||||
|
||||
it('handles empty findings list', () => {
|
||||
const suppressions = [{ pattern: 'CA-CML-*', comment: '' }];
|
||||
const { active, suppressed } = applySuppressions([], suppressions);
|
||||
|
||||
assert.equal(active.length, 0);
|
||||
assert.equal(suppressed.length, 0);
|
||||
});
|
||||
|
||||
it('applies multiple suppression patterns', () => {
|
||||
const findings = [
|
||||
makeFinding('CA-CML-001', 'CML'),
|
||||
makeFinding('CA-SET-001', 'SET'),
|
||||
makeFinding('CA-GAP-001', 'GAP'),
|
||||
];
|
||||
const suppressions = [
|
||||
{ pattern: 'CA-CML-001', comment: '' },
|
||||
{ pattern: 'CA-GAP-*', comment: '' },
|
||||
];
|
||||
const { active, suppressed } = applySuppressions(findings, suppressions);
|
||||
|
||||
assert.equal(active.length, 1);
|
||||
assert.equal(active[0].id, 'CA-SET-001');
|
||||
assert.equal(suppressed.length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// formatSuppressionSummary
|
||||
// ========================================
|
||||
describe('formatSuppressionSummary', () => {
|
||||
it('formats correct count and groups', () => {
|
||||
const suppressed = [
|
||||
makeFinding('CA-GAP-001', 'GAP'),
|
||||
makeFinding('CA-GAP-002', 'GAP'),
|
||||
makeFinding('CA-HKV-003', 'HKV'),
|
||||
];
|
||||
const summary = formatSuppressionSummary(suppressed);
|
||||
|
||||
assert.ok(summary.includes('3 finding(s) suppressed'));
|
||||
assert.ok(summary.includes('CA-GAP-*'));
|
||||
assert.ok(summary.includes('CA-HKV-*'));
|
||||
});
|
||||
|
||||
it('returns zero message for empty array', () => {
|
||||
assert.equal(formatSuppressionSummary([]), '0 findings suppressed');
|
||||
});
|
||||
|
||||
it('returns zero message for null', () => {
|
||||
assert.equal(formatSuppressionSummary(null), '0 findings suppressed');
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// loadSuppressions
|
||||
// ========================================
|
||||
describe('loadSuppressions', () => {
|
||||
const tmpDir = join(tmpdir(), `config-audit-suppress-test-${Date.now()}`);
|
||||
|
||||
it('returns empty when no .config-audit-ignore exists', async () => {
|
||||
const result = await loadSuppressions('/nonexistent/path');
|
||||
assert.deepEqual(result.suppressions, []);
|
||||
assert.equal(result.source, 'none');
|
||||
});
|
||||
|
||||
it('loads from project directory', async () => {
|
||||
await mkdir(tmpDir, { recursive: true });
|
||||
await writeFile(join(tmpDir, '.config-audit-ignore'), 'CA-GAP-*\nCA-CML-001\n');
|
||||
|
||||
const result = await loadSuppressions(tmpDir);
|
||||
assert.equal(result.suppressions.length, 2);
|
||||
assert.equal(result.source, 'project');
|
||||
|
||||
await rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue