#20 git-forensics' reflog force-push detector had a redundant bare 'reset' term subsuming 'reset:', so any commit subject containing 'reset' tripped it; removed. #22 diff-engine's per-current moved-fallback greedily consumed a baseline candidate a later byte-exact match needed (mislabeling unchanged as new/moved on duplicate fingerprints); a global exact pass now runs before the moved-fallback. #54 memory-poisoning double-reported a 64+ char hex token as both base64 and hex; the base64 check now skips pure-hex tokens. #56 SARIF output hardcoded driver.version 6.0.0 because the orchestrator called toSARIF() without a version; it now passes the real plugin version from package.json. #50 the VS Code known-malicious blocklist was empty with no explanation (unlike the JetBrains file's 'empty by design' note); added a matching blocklist_note. Suite 2004/0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TcQyMTQfyrsAapaCMPxTtQ
127 lines
4.1 KiB
JavaScript
127 lines
4.1 KiB
JavaScript
// ide-extension-data.test.mjs — Unit tests for knowledge-file loaders.
|
|
//
|
|
// Verifies loadTopJetBrains, loadJetBrainsBlocklist behavior + cache
|
|
// discipline shared with VS Code loaders.
|
|
|
|
import { describe, it, beforeEach } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { resolve, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import {
|
|
loadTopJetBrains,
|
|
loadJetBrainsBlocklist,
|
|
loadTopVSCode,
|
|
loadVSCodeBlocklist,
|
|
normalizeId,
|
|
_resetCache,
|
|
} from '../../scanners/lib/ide-extension-data.mjs';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
describe('loadTopJetBrains', () => {
|
|
beforeEach(() => _resetCache());
|
|
|
|
it('returns >= 40 canonical xmlIds', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
assert.ok(Array.isArray(ids));
|
|
assert.ok(
|
|
ids.length >= 40,
|
|
`expected >= 40 entries, got ${ids.length}`,
|
|
);
|
|
});
|
|
|
|
it('returns lowercased trimmed entries (normalizeId applied)', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
for (const id of ids) {
|
|
assert.equal(id, id.toLowerCase(), `not lowercased: ${id}`);
|
|
assert.equal(id, id.trim(), `not trimmed: ${id}`);
|
|
assert.notEqual(id, '', 'empty entry found');
|
|
}
|
|
});
|
|
|
|
it('includes bundled JetBrains xmlIds', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
assert.ok(
|
|
ids.includes('com.intellij.java'),
|
|
'missing com.intellij.java',
|
|
);
|
|
assert.ok(
|
|
ids.includes('org.jetbrains.kotlin'),
|
|
'missing org.jetbrains.kotlin',
|
|
);
|
|
});
|
|
|
|
it('includes the legitimate-typo "lombook plugin" xmlId', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
assert.ok(
|
|
ids.includes('lombook plugin'),
|
|
'missing "lombook plugin" — canonical xmlId for Lombok integration',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('loadJetBrainsBlocklist', () => {
|
|
beforeEach(() => _resetCache());
|
|
|
|
it('returns an empty array (empty by design)', async () => {
|
|
const bl = await loadJetBrainsBlocklist();
|
|
assert.ok(Array.isArray(bl));
|
|
assert.equal(
|
|
bl.length,
|
|
0,
|
|
'blocklist should be empty by design in v6.6.0',
|
|
);
|
|
});
|
|
|
|
it('does not throw on repeated invocation', async () => {
|
|
await assert.doesNotReject(() => loadJetBrainsBlocklist());
|
|
await assert.doesNotReject(() => loadJetBrainsBlocklist());
|
|
});
|
|
});
|
|
|
|
describe('cache sanity', () => {
|
|
beforeEach(() => _resetCache());
|
|
|
|
it('calling loadTopJetBrains then loadJetBrainsBlocklist does not throw', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
const bl = await loadJetBrainsBlocklist();
|
|
assert.ok(Array.isArray(ids) && ids.length > 0);
|
|
assert.ok(Array.isArray(bl));
|
|
});
|
|
|
|
it('second loadTopJetBrains call returns same data (cache hit)', async () => {
|
|
const a = await loadTopJetBrains();
|
|
const b = await loadTopJetBrains();
|
|
assert.deepEqual(a, b);
|
|
});
|
|
|
|
it('VS Code loaders still work alongside JetBrains loaders', async () => {
|
|
const jb = await loadTopJetBrains();
|
|
const vs = await loadTopVSCode();
|
|
assert.ok(jb.length >= 40);
|
|
assert.ok(Array.isArray(vs));
|
|
});
|
|
});
|
|
|
|
// #50 (v7.8.3): the VS Code knowledge file has an empty blocklist like the
|
|
// JetBrains one, but lacked the explicit "empty by design" note — making the
|
|
// empty list read as an oversight. Pin the data/doc consistency here.
|
|
describe('top-vscode-extensions.json metadata (#50)', () => {
|
|
const KNOWLEDGE_PATH = resolve(__dirname, '../../knowledge/top-vscode-extensions.json');
|
|
|
|
it('parses as valid JSON', () => {
|
|
assert.doesNotThrow(() => JSON.parse(readFileSync(KNOWLEDGE_PATH, 'utf8')));
|
|
});
|
|
|
|
it('has a blocklist_note documenting the empty-by-design blocklist', () => {
|
|
const data = JSON.parse(readFileSync(KNOWLEDGE_PATH, 'utf8'));
|
|
assert.ok(Array.isArray(data.blocklist), 'blocklist should be an array');
|
|
assert.equal(data.blocklist.length, 0, 'blocklist is empty by design');
|
|
assert.equal(
|
|
typeof data._meta.blocklist_note, 'string',
|
|
'_meta.blocklist_note should document the empty-by-design state (like top-jetbrains-plugins.json)',
|
|
);
|
|
assert.match(data._meta.blocklist_note, /empty by design/i);
|
|
});
|
|
});
|