ktg-plugin-marketplace/plugins/config-audit/tests/scanners/scan-orchestrator.test.mjs

172 lines
7.7 KiB
JavaScript

import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { resolve, dirname, sep } from 'node:path';
import { fileURLToPath } from 'node:url';
import { isFixturePath, FIXTURE_DIR_NAMES, runAllScanners } from '../../scanners/scan-orchestrator.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PLUGIN_ROOT = resolve(__dirname, '../..');
const FIXTURES = resolve(__dirname, '../fixtures');
// ========================================
// isFixturePath
// ========================================
describe('isFixturePath', () => {
const target = '/repo';
it('matches tests/ subdirectory relative to target', () => {
assert.strictEqual(isFixturePath({ file: '/repo/tests/fixtures/CLAUDE.md' }, target), true);
});
it('matches examples/ subdirectory relative to target', () => {
assert.strictEqual(isFixturePath({ file: '/repo/examples/demo/settings.json' }, target), true);
});
it('matches __tests__/ subdirectory', () => {
assert.strictEqual(isFixturePath({ file: '/repo/__tests__/config/CLAUDE.md' }, target), true);
});
it('does not match production paths', () => {
assert.strictEqual(isFixturePath({ file: '/repo/CLAUDE.md' }, target), false);
assert.strictEqual(isFixturePath({ file: '/repo/plugins/config-audit/CLAUDE.md' }, target), false);
});
it('does not filter when target IS a fixture directory', () => {
// If we're scanning tests/fixtures/broken-project directly, its files should NOT be filtered
const fixtureTarget = '/repo/tests/fixtures/broken-project';
assert.strictEqual(
isFixturePath({ file: '/repo/tests/fixtures/broken-project/CLAUDE.md' }, fixtureTarget),
false,
'Files at the root of the scanned target should not be filtered'
);
});
it('falls back to path field', () => {
assert.strictEqual(isFixturePath({ path: '/repo/tests/broken/hooks.json' }, target), true);
});
it('falls back to location field', () => {
assert.strictEqual(isFixturePath({ location: '/repo/examples/bad.md' }, target), true);
});
it('returns false when file is null (GAP findings)', () => {
assert.strictEqual(isFixturePath({ file: null }, target), false);
});
it('returns false for empty finding (no file/path/location)', () => {
assert.strictEqual(isFixturePath({}, target), false);
});
it('returns false when file is outside target path', () => {
assert.strictEqual(isFixturePath({ file: '/other/tests/foo.md' }, target), false);
});
it('uses platform-native separator (path.sep)', () => {
// On macOS/Linux sep='/', on Windows sep='\\'
// This test verifies the function works with the native separator
const nativePath = `${target}${sep}tests${sep}fixtures${sep}CLAUDE.md`;
assert.strictEqual(isFixturePath({ file: nativePath }, target), true);
});
});
// ========================================
// FIXTURE_DIR_NAMES
// ========================================
describe('FIXTURE_DIR_NAMES', () => {
it('contains expected directory names', () => {
assert.ok(FIXTURE_DIR_NAMES.includes('tests'));
assert.ok(FIXTURE_DIR_NAMES.includes('examples'));
assert.ok(FIXTURE_DIR_NAMES.includes('__tests__'));
});
});
// ========================================
// runAllScanners — fixture filtering
// ========================================
describe('runAllScanners — fixture filtering', () => {
it('excludes fixture findings by default when scanning plugin root', async () => {
const env = await runAllScanners(PLUGIN_ROOT);
// The plugin has test fixtures in tests/fixtures/ — those should be filtered out
const allFindingFiles = env.scanners.flatMap(s => s.findings.map(f => f.file)).filter(Boolean);
const fixtureInResults = allFindingFiles.filter(f => f.includes('/tests/'));
assert.strictEqual(fixtureInResults.length, 0, 'No fixture findings should appear in scanner results');
});
it('stores excluded findings in env.fixture_findings', async () => {
const env = await runAllScanners(PLUGIN_ROOT);
// Plugin has intentionally broken fixtures — at least some findings should be excluded
if (env.fixture_findings) {
assert.ok(Array.isArray(env.fixture_findings));
assert.ok(env.fixture_findings.length > 0, 'Expected fixture findings to be captured');
// All fixture findings should have test/example paths
for (const f of env.fixture_findings) {
const p = f.file || f.path || f.location || '';
assert.ok(
p.includes('/tests/') || p.includes('/examples/'),
`Fixture finding path should contain /tests/ or /examples/: ${p}`
);
}
}
// Note: if no fixture findings exist (unlikely but possible), test still passes
});
it('includes fixture findings when filterFixtures is false', async () => {
const env = await runAllScanners(PLUGIN_ROOT, { filterFixtures: false });
assert.strictEqual(env.fixture_findings, undefined, 'No fixture_findings field when filtering disabled');
// Some findings should have test fixture paths
const allFindingFiles = env.scanners.flatMap(s => s.findings.map(f => f.file)).filter(Boolean);
const fixtureInResults = allFindingFiles.filter(f => f.includes('/tests/'));
assert.ok(fixtureInResults.length > 0, 'Fixture findings should be present when filtering disabled');
});
it('does not filter GAP findings (file is null)', async () => {
const env = await runAllScanners(PLUGIN_ROOT);
const gapScanner = env.scanners.find(s => s.scanner === 'GAP');
assert.ok(gapScanner, 'GAP scanner should be present');
// GAP findings have file: null — they should never be filtered
for (const f of gapScanner.findings) {
assert.strictEqual(f.file, null, 'GAP findings have null file and should not be filtered');
}
});
it('recalculates scanner counts after fixture filtering', async () => {
const env = await runAllScanners(PLUGIN_ROOT);
for (const scanner of env.scanners) {
// Verify counts match actual findings
const expected = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
for (const f of scanner.findings) {
if (expected[f.severity] !== undefined) expected[f.severity]++;
}
assert.deepStrictEqual(scanner.counts, expected,
`Scanner ${scanner.scanner}: counts should match actual findings after filtering`);
}
});
it('total_findings in aggregate excludes fixtures', async () => {
const withFilter = await runAllScanners(PLUGIN_ROOT, { filterFixtures: true });
const withoutFilter = await runAllScanners(PLUGIN_ROOT, { filterFixtures: false });
// With filter should have fewer or equal findings
assert.ok(
withFilter.aggregate.total_findings <= withoutFilter.aggregate.total_findings,
`Filtered total (${withFilter.aggregate.total_findings}) should be <= unfiltered (${withoutFilter.aggregate.total_findings})`
);
});
it('fixture filtering and suppression are independent', async () => {
// Both enabled (default)
const both = await runAllScanners(PLUGIN_ROOT, { filterFixtures: true, suppress: true });
// Only fixtures
const fixturesOnly = await runAllScanners(PLUGIN_ROOT, { filterFixtures: true, suppress: false });
// Only suppression
const suppressOnly = await runAllScanners(PLUGIN_ROOT, { filterFixtures: false, suppress: true });
// fixture_findings should be present in both fixture-filtered runs
if (both.fixture_findings) {
assert.ok(fixturesOnly.fixture_findings, 'fixture_findings should be present regardless of suppress flag');
}
// suppressed_findings should be present in both suppression-enabled runs (if any suppressions exist)
if (both.suppressed_findings) {
assert.ok(suppressOnly.suppressed_findings, 'suppressed_findings should be present regardless of filterFixtures flag');
}
});
});