- VERSION file as authoritative version source - export.mjs reads VERSION with package.json fallback - bw-ota.ps1 DryRun mode for safe testing - auto-setup.ps1 bumped to v3.2.0 (Phase 8 OTA)
92 lines
3.2 KiB
JavaScript
92 lines
3.2 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* PoC H4: 新增 sensitive-paths 规则与生产流水的兼容性
|
||
*
|
||
* 验证:
|
||
* - 新 3 条 ai-delivery-pipeline 规则能正确匹配目标路径
|
||
* - 不会误伤其他正常文件
|
||
* - rules-compiled.json 已包含新规则
|
||
* - hook 内部(持有 bypass token)可绕过保护写入 staging/
|
||
*/
|
||
'use strict';
|
||
|
||
const fs = require('fs');
|
||
const os = require('os');
|
||
const path = require('path');
|
||
|
||
const ROOT = path.join(__dirname, '..', '..');
|
||
const SANDBOX = path.join(ROOT, 'ai-delivery-pipeline', '_poc-sandbox');
|
||
const SP = path.join(ROOT, 'hooks', 'rules', 'sensitive-paths.json');
|
||
const COMPILED = path.join(ROOT, 'hooks', 'rules', 'rules-compiled.json');
|
||
|
||
function loadPatterns() {
|
||
const sp = JSON.parse(fs.readFileSync(SP, 'utf8'));
|
||
return sp.patterns.map(p => ({ re: new RegExp(p.regex, p.flags || ''), reason: p.reason }));
|
||
}
|
||
|
||
function matches(patterns, p) {
|
||
const hits = patterns.filter(x => x.re.test(p));
|
||
return hits.map(h => h.reason);
|
||
}
|
||
|
||
function main() {
|
||
fs.mkdirSync(SANDBOX, { recursive: true });
|
||
const patterns = loadPatterns();
|
||
|
||
// 应命中的路径 (true positive)
|
||
const shouldHit = [
|
||
'C:/Users/leesu/.claude/ai-delivery-pipeline/staging/session-x/foo.ts',
|
||
'C:\\Users\\leesu\\.claude\\ai-delivery-pipeline\\quarantine\\bad.ts',
|
||
'/c/Users/leesu/.claude/ai-delivery-pipeline/delivery/ok.ts',
|
||
];
|
||
// 不应命中的路径 (true negative)
|
||
const shouldMiss = [
|
||
'C:/Users/leesu/projects/mybiobb.com/src/app/page.tsx',
|
||
'C:/Users/leesu/.claude/skills/developer-expert/SKILL.md',
|
||
'/home/user/ai-delivery-pipeline/staging/foo.ts', // 不在 .claude/ 下
|
||
'C:/Users/leesu/.claude/ai-delivery-pipeline/README.md', // 根目录 README 不匹配 staging/
|
||
];
|
||
|
||
const hitResults = shouldHit.map(p => {
|
||
const reasons = matches(patterns, p);
|
||
const passed = reasons.length > 0;
|
||
return { path: p, expected: 'hit', reasons, pass: passed };
|
||
});
|
||
const missResults = shouldMiss.map(p => {
|
||
const reasons = matches(patterns, p);
|
||
const passed = reasons.length === 0;
|
||
return { path: p, expected: 'miss', reasons, pass: passed };
|
||
});
|
||
|
||
// rules-compiled 是否包含新规则
|
||
const compiled = fs.readFileSync(COMPILED, 'utf8');
|
||
const compiledHas = compiled.includes('ai-delivery-pipeline');
|
||
|
||
const allTests = [...hitResults, ...missResults];
|
||
const pass = allTests.filter(r => r.pass).length;
|
||
const total = allTests.length;
|
||
|
||
const report = {
|
||
hypothesis: 'H4 · sensitive-paths 新规则兼容性',
|
||
platform: os.platform() + ' ' + os.release(),
|
||
timestamp: new Date().toISOString(),
|
||
rulesCompiledHasNewRules: compiledHas,
|
||
truePositives: hitResults,
|
||
trueNegatives: missResults,
|
||
stats: { total, pass, failed: total - pass },
|
||
verdict: {
|
||
rulesActive: compiledHas,
|
||
precisionOk: missResults.every(r => r.pass),
|
||
recallOk: hitResults.every(r => r.pass),
|
||
pass: pass === total && compiledHas,
|
||
},
|
||
recommendation: pass === total && compiledHas
|
||
? '✅ 新规则精确匹配, 不误伤, 已进 rules-compiled; 可进入冲刺 3 实施'
|
||
: '❌ 有误判, 需调整 regex',
|
||
};
|
||
fs.writeFileSync(path.join(SANDBOX, 'h4-report.json'), JSON.stringify(report, null, 2), 'utf8');
|
||
console.log(JSON.stringify(report, null, 2));
|
||
}
|
||
|
||
main();
|