init
This commit is contained in:
225
.opencode/plugin/scout-block/tests/test-monorepo-scenarios.cjs
Executable file
225
.opencode/plugin/scout-block/tests/test-monorepo-scenarios.cjs
Executable file
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* test-monorepo-scenarios.cjs - Integration tests for monorepo patterns
|
||||
*
|
||||
* THIS IS THE CRITICAL TEST FILE FOR THE BUG FIX!
|
||||
* Tests that subfolder blocked directories (node_modules, dist, etc.)
|
||||
* are properly blocked in monorepo structures.
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
const hookPath = path.join(__dirname, '..', '..', 'scout-block.cjs');
|
||||
|
||||
const scenarios = [
|
||||
// === THE BUG CASES - These MUST be BLOCKED ===
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'ls packages/web/node_modules' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] ls subfolder node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'cd apps/api/node_modules' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] cd subfolder node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'cat packages/shared/node_modules/lodash/index.js' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] cat file in subfolder node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Read', tool_input: { file_path: 'packages/web/node_modules/react/package.json' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] Read subfolder node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Grep', tool_input: { pattern: 'export', path: 'packages/web/node_modules' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] Grep in subfolder node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Glob', tool_input: { pattern: 'packages/web/node_modules/**/*.js' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] Glob subfolder node_modules'
|
||||
},
|
||||
|
||||
// === Deep nesting (also bug cases) ===
|
||||
{
|
||||
input: { tool_name: 'Read', tool_input: { file_path: 'a/b/c/d/node_modules/pkg/index.js' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] Deep nested node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'ls packages/web/dist' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] ls subfolder dist'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'cat apps/api/build/server.js' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: '[BUG FIX] cat subfolder build'
|
||||
},
|
||||
|
||||
// === Root level blocking (should still work) ===
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'ls node_modules' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: 'ls root node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Read', tool_input: { file_path: 'node_modules/lodash/index.js' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: 'Read root node_modules'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'cat .git/config' } },
|
||||
expected: 'BLOCKED',
|
||||
desc: 'cat .git file'
|
||||
},
|
||||
|
||||
// === Build commands - MUST be ALLOWED ===
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'npm run build' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'npm run build'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'pnpm build' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'pnpm build'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'yarn build' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'yarn build'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'npm test' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'npm test'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'npm install' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'npm install'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'pnpm --filter web run build' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'pnpm filter build'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'npx tsc' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'npx tsc'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'jest --coverage' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'jest with flags'
|
||||
},
|
||||
|
||||
// === Safe operations - MUST be ALLOWED ===
|
||||
{
|
||||
input: { tool_name: 'Read', tool_input: { file_path: 'packages/web/src/App.tsx' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'Read safe path'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'ls packages/web/src' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'ls safe path'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Grep', tool_input: { pattern: 'import', path: 'src' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'Grep in src'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Glob', tool_input: { pattern: '**/*.ts' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'Glob all .ts files'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'find packages -name "*.json" | head' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'find without blocked dirs'
|
||||
},
|
||||
|
||||
// === Edge cases - names containing blocked words but NOT the dirs ===
|
||||
{
|
||||
input: { tool_name: 'Read', tool_input: { file_path: 'my-node_modules-project/file.js' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'node_modules in project name'
|
||||
},
|
||||
{
|
||||
input: { tool_name: 'Bash', tool_input: { command: 'ls build-tools' } },
|
||||
expected: 'ALLOWED',
|
||||
desc: 'build- prefix directory'
|
||||
},
|
||||
];
|
||||
|
||||
console.log('Testing monorepo scenarios (scout-block integration)...\n');
|
||||
console.log('Hook path:', hookPath, '\n');
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const scenario of scenarios) {
|
||||
try {
|
||||
execSync(`node "${hookPath}"`, {
|
||||
input: JSON.stringify(scenario.input),
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
});
|
||||
// Exit 0 = ALLOWED
|
||||
const actual = 'ALLOWED';
|
||||
const success = actual === scenario.expected;
|
||||
if (success) {
|
||||
console.log(`\x1b[32m✓\x1b[0m ${scenario.desc}: ${actual}`);
|
||||
passed++;
|
||||
} else {
|
||||
console.log(`\x1b[31m✗\x1b[0m ${scenario.desc}: expected ${scenario.expected}, got ${actual}`);
|
||||
failed++;
|
||||
}
|
||||
} catch (error) {
|
||||
// Exit 2 = BLOCKED
|
||||
const actual = error.status === 2 ? 'BLOCKED' : `ERROR(${error.status})`;
|
||||
const success = actual === scenario.expected;
|
||||
if (success) {
|
||||
console.log(`\x1b[32m✓\x1b[0m ${scenario.desc}: ${actual}`);
|
||||
passed++;
|
||||
} else {
|
||||
console.log(`\x1b[31m✗\x1b[0m ${scenario.desc}: expected ${scenario.expected}, got ${actual}`);
|
||||
if (error.stderr) {
|
||||
console.log(` stderr: ${error.stderr.toString().trim().split('\n')[0]}`);
|
||||
}
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nResults: ${passed} passed, ${failed} failed`);
|
||||
|
||||
// Highlight if any bug fix cases failed
|
||||
const bugFixFailed = scenarios.filter(s => s.desc.includes('[BUG FIX]')).some(s => {
|
||||
try {
|
||||
execSync(`node "${hookPath}"`, {
|
||||
input: JSON.stringify(s.input),
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
});
|
||||
return s.expected === 'BLOCKED'; // Should have been blocked but wasn't
|
||||
} catch (error) {
|
||||
return error.status !== 2 && s.expected === 'BLOCKED';
|
||||
}
|
||||
});
|
||||
|
||||
if (bugFixFailed) {
|
||||
console.log('\n\x1b[31mWARNING: Some bug fix test cases failed!\x1b[0m');
|
||||
console.log('The subfolder blocking bug has NOT been fixed properly.');
|
||||
}
|
||||
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
Reference in New Issue
Block a user