mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
- Implemented final verification tests for contentPattern to validate behavior with empty strings, dangerous patterns, and normal patterns. - Created glob pattern matching tests to verify regex conversion and matching functionality. - Developed infinite loop risk tests using Worker threads to isolate potential blocking operations. - Introduced optimized contentPattern tests to validate improvements in the findMatches function. - Added verification tests to assess the effectiveness of contentPattern optimizations. - Conducted safety tests for contentPattern to identify edge cases and potential vulnerabilities. - Implemented unrestricted loop tests to analyze infinite loop risks without match limits. - Developed tests for zero-width pattern detection logic to ensure proper handling of dangerous regex patterns.
174 lines
5.1 KiB
JavaScript
174 lines
5.1 KiB
JavaScript
/**
|
||
* contentPattern 无限循环风险测试
|
||
* 使用 Worker 隔离环境,防止主线程卡死
|
||
*/
|
||
|
||
import { Worker } from 'worker_threads';
|
||
import { fileURLToPath } from 'url';
|
||
import { dirname, join } from 'path';
|
||
|
||
const __filename = fileURLToPath(import.meta.url);
|
||
const __dirname = dirname(__filename);
|
||
|
||
// 测试函数代码
|
||
const workerCode = `
|
||
function findMatches(content, pattern) {
|
||
try {
|
||
const regex = new RegExp(pattern, 'gm');
|
||
const matches = [];
|
||
let match;
|
||
let iterations = 0;
|
||
const MAX_ITERATIONS = 1000;
|
||
|
||
while ((match = regex.exec(content)) !== null && matches.length < 10) {
|
||
iterations++;
|
||
if (iterations > MAX_ITERATIONS) {
|
||
return { error: 'Exceeded max iterations - possible infinite loop', iterations };
|
||
}
|
||
const lineStart = content.lastIndexOf('\\n', match.index) + 1;
|
||
const lineEnd = content.indexOf('\\n', match.index);
|
||
const line = content.substring(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
|
||
matches.push(line.substring(0, 200));
|
||
}
|
||
return { matches, iterations };
|
||
} catch (error) {
|
||
return { error: error.message };
|
||
}
|
||
};
|
||
|
||
self.on('message', ({ content, pattern }) => {
|
||
const result = findMatches(content, pattern);
|
||
self.postMessage(result);
|
||
});
|
||
`;
|
||
|
||
async function testInfiniteLoop(content, pattern, testName, timeout = 2000) {
|
||
console.log(`\n测试: ${testName}`);
|
||
console.log(`模式: "${pattern}"`);
|
||
|
||
// 创建临时 worker
|
||
const blob = new Blob([workerCode], { type: 'application/javascript' });
|
||
const workerUrl = URL.createObjectURL(blob);
|
||
|
||
try {
|
||
const worker = new Worker(workerUrl);
|
||
|
||
const result = await new Promise((resolve) => {
|
||
const timer = setTimeout(() => {
|
||
worker.terminate();
|
||
resolve({ error: 'TIMEOUT - Infinite loop detected!', timeout: true });
|
||
}, timeout);
|
||
|
||
worker.once('message', (data) => {
|
||
clearTimeout(timer);
|
||
worker.terminate();
|
||
resolve(data);
|
||
});
|
||
|
||
worker.once('error', (error) => {
|
||
clearTimeout(timer);
|
||
worker.terminate();
|
||
resolve({ error: error.message });
|
||
});
|
||
|
||
worker.postMessage({ content, pattern });
|
||
});
|
||
|
||
URL.revokeObjectURL(workerUrl);
|
||
|
||
if (result.error) {
|
||
if (result.timeout) {
|
||
console.log(`❌ 超时 - 检测到无限循环!`);
|
||
return { hasInfiniteLoop: true };
|
||
} else {
|
||
console.log(`⚠️ 错误: ${result.error}`);
|
||
return { hasInfiniteLoop: false, error: result.error };
|
||
}
|
||
} else {
|
||
console.log(`✅ 结果: ${result.matches?.length || 0} 个匹配, ${result.iterations} 次迭代`);
|
||
return { hasInfiniteLoop: false, iterations: result.iterations };
|
||
}
|
||
} catch (error) {
|
||
console.log(`❌ 异常: ${error.message}`);
|
||
return { hasInfiniteLoop: false, error: error.message };
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
console.log('=== contentPattern 无限循环风险测试 ===\n');
|
||
console.log('⚠️ 危险测试将在 Worker 中运行,2秒超时\n');
|
||
|
||
const tests = [
|
||
{
|
||
name: '正常模式',
|
||
content: 'Line 1\nLine 2\nLine 3',
|
||
pattern: 'Line',
|
||
expected: '正常'
|
||
},
|
||
{
|
||
name: '空字符串模式(危险)',
|
||
content: 'Line 1\nLine 2\nLine 3',
|
||
pattern: '',
|
||
expected: '无限循环'
|
||
},
|
||
{
|
||
name: '零宽匹配(危险)',
|
||
content: 'abc\ndef\nghi',
|
||
pattern: 'x*', // 匹配 0 个或多个 x
|
||
expected: '无限循环'
|
||
},
|
||
{
|
||
name: '或运算符空匹配(危险)',
|
||
content: 'some text',
|
||
pattern: 'a|', // 匹配 'a' 或空
|
||
expected: '无限循环'
|
||
},
|
||
{
|
||
name: 'ReDoS 攻击(危险)',
|
||
content: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab',
|
||
pattern: '(a+)+b',
|
||
expected: '超时'
|
||
},
|
||
{
|
||
name: '正常匹配',
|
||
content: 'TODO fix this\nTODO fix that',
|
||
pattern: 'TODO',
|
||
expected: '正常'
|
||
}
|
||
];
|
||
|
||
const results = [];
|
||
|
||
for (const test of tests) {
|
||
const result = await testInfiniteLoop(test.content, test.pattern, test.name, 2000);
|
||
results.push({ ...test, result });
|
||
}
|
||
|
||
console.log(`\n${'='.repeat(60)}`);
|
||
console.log('\n测试结果汇总:\n');
|
||
|
||
const infiniteLoopCount = results.filter(r => r.result.hasInfiniteLoop).length;
|
||
const timeoutCount = results.filter(r => r.result.error?.includes('TIMEOUT')).length;
|
||
|
||
results.forEach((r, i) => {
|
||
const status = r.result.hasInfiniteLoop ? '❌ 无限循环' :
|
||
r.result.error?.includes('TIMEOUT') ? '⏱️ 超时' :
|
||
r.result.error ? '⚠️ 错误' : '✅ 正常';
|
||
console.log(`${i + 1}. ${r.name.padEnd(30)} ${status}`);
|
||
if (r.result.iterations) {
|
||
console.log(` 迭代次数: ${r.result.iterations}`);
|
||
}
|
||
});
|
||
|
||
console.log(`\n总结:`);
|
||
console.log(`- 无限循环风险: ${infiniteLoopCount} 个`);
|
||
console.log(`- 超时风险: ${timeoutCount} 个`);
|
||
console.log(`- 正常工作: ${results.length - infiniteLoopCount - timeoutCount} 个`);
|
||
|
||
if (infiniteLoopCount > 0 || timeoutCount > 0) {
|
||
console.log(`\n⚠️ contentPattern 存在严重的无限循环和 ReDoS 风险!`);
|
||
}
|
||
}
|
||
|
||
main().catch(console.error);
|