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
87
plugins/config-audit/tests/hooks/post-edit-verify.test.mjs
Normal file
87
plugins/config-audit/tests/hooks/post-edit-verify.test.mjs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const HOOK_PATH = resolve(import.meta.dirname, '../../hooks/scripts/post-edit-verify.mjs');
|
||||
|
||||
/**
|
||||
* Run the hook with given stdin input (string).
|
||||
* Short timeout — these tests should only exercise fast paths.
|
||||
*/
|
||||
async function runHook(inputStr, timeout = 10000) {
|
||||
try {
|
||||
const { stdout } = await execFileAsync('node', [HOOK_PATH], {
|
||||
input: inputStr,
|
||||
timeout,
|
||||
});
|
||||
return JSON.parse(stdout || '{}');
|
||||
} catch (err) {
|
||||
if (err.stdout) {
|
||||
try { return JSON.parse(err.stdout); } catch { /* ignore */ }
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// post-edit-verify hook — fast-path tests
|
||||
// Tests exercise the early-exit paths (non-config, missing file, invalid input).
|
||||
// Scanner execution paths are covered by scanner tests.
|
||||
// ========================================
|
||||
describe('post-edit-verify hook', () => {
|
||||
it('returns {} for non-config files', async () => {
|
||||
const result = await runHook(JSON.stringify({ file_path: '/tmp/some-random-file.js' }));
|
||||
assert.deepEqual(result, {});
|
||||
});
|
||||
|
||||
it('returns {} for nonexistent config files', async () => {
|
||||
const result = await runHook(JSON.stringify({ file_path: '/nonexistent/CLAUDE.md' }));
|
||||
assert.deepEqual(result, {});
|
||||
});
|
||||
|
||||
it('returns {} for empty input object', async () => {
|
||||
const result = await runHook(JSON.stringify({}));
|
||||
assert.deepEqual(result, {});
|
||||
});
|
||||
|
||||
it('returns {} for null file_path', async () => {
|
||||
const result = await runHook(JSON.stringify({ file_path: null }));
|
||||
assert.deepEqual(result, {});
|
||||
});
|
||||
|
||||
it('handles invalid JSON gracefully', async () => {
|
||||
const result = await runHook('not json at all');
|
||||
assert.deepEqual(result, {});
|
||||
});
|
||||
|
||||
it('handles empty stdin gracefully', async () => {
|
||||
const result = await runHook('');
|
||||
assert.deepEqual(result, {});
|
||||
});
|
||||
|
||||
it('exits quickly for non-config files', async () => {
|
||||
const start = Date.now();
|
||||
await runHook(JSON.stringify({ file_path: '/tmp/nothing.txt' }));
|
||||
const elapsed = Date.now() - start;
|
||||
// Non-config files exit before any scanner import — should be fast
|
||||
assert.ok(elapsed < 5000, `Hook took ${elapsed}ms for non-config file`);
|
||||
});
|
||||
|
||||
it('has correct shebang and is valid Node.js', async () => {
|
||||
const { readFile } = await import('node:fs/promises');
|
||||
const content = await readFile(HOOK_PATH, 'utf-8');
|
||||
assert.ok(content.startsWith('#!/usr/bin/env node'));
|
||||
assert.ok(content.includes('readFileSync'));
|
||||
assert.ok(content.includes('detectScanner'));
|
||||
});
|
||||
|
||||
it('uses cross-platform rules dir pattern (handles both / and \\)', async () => {
|
||||
const { readFile } = await import('node:fs/promises');
|
||||
const content = await readFile(HOOK_PATH, 'utf-8');
|
||||
// The regex should handle both Unix / and Windows \\ separators
|
||||
assert.ok(content.includes('[/\\\\]rules[/\\\\]'), 'RULES_DIR_PATTERN should match both / and \\\\');
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue