fix: persist repaired exclusions
This commit is contained in:
+6
-1
@@ -272,7 +272,7 @@ export async function deduplicateWithAI(findings) {
|
|||||||
/**
|
/**
|
||||||
* 讀取排除問題檔案(從來源分支的 cloned repoDir 中的 EXCLUSIONS_PATH)
|
* 讀取排除問題檔案(從來源分支的 cloned repoDir 中的 EXCLUSIONS_PATH)
|
||||||
*/
|
*/
|
||||||
export function loadExclusions(workspace, repoState = null) {
|
export function loadExclusions(workspace, repoState = null, mirrorWorkspace = null) {
|
||||||
const fullPath = path.join(workspace, EXCLUSIONS_PATH);
|
const fullPath = path.join(workspace, EXCLUSIONS_PATH);
|
||||||
if (!fs.existsSync(fullPath)) {
|
if (!fs.existsSync(fullPath)) {
|
||||||
warn(`排除問題檔案不存在,視為空: ${fullPath}`);
|
warn(`排除問題檔案不存在,視為空: ${fullPath}`);
|
||||||
@@ -302,6 +302,11 @@ export function loadExclusions(workspace, repoState = null) {
|
|||||||
line(`檔案資訊: bytes=${stat.size} mtime=${formatFileTime(stat.mtimeMs)} raw=${rawCount} normalized=${exclusions.length} path=${path.relative(workspace, fullPath) || fullPath}`);
|
line(`檔案資訊: bytes=${stat.size} mtime=${formatFileTime(stat.mtimeMs)} raw=${rawCount} normalized=${exclusions.length} path=${path.relative(workspace, fullPath) || fullPath}`);
|
||||||
if (sourceFormat !== 'array') {
|
if (sourceFormat !== 'array') {
|
||||||
writeCanonicalExclusions(fullPath, normalizedSource);
|
writeCanonicalExclusions(fullPath, normalizedSource);
|
||||||
|
if (mirrorWorkspace && path.resolve(mirrorWorkspace) !== path.resolve(workspace)) {
|
||||||
|
const mirrorPath = path.join(mirrorWorkspace, EXCLUSIONS_PATH);
|
||||||
|
fs.mkdirSync(path.dirname(mirrorPath), { recursive: true });
|
||||||
|
writeCanonicalExclusions(mirrorPath, normalizedSource);
|
||||||
|
}
|
||||||
line(`排除問題格式已修正為頂層陣列: source=${sourceFormat} -> array`);
|
line(`排除問題格式已修正為頂層陣列: source=${sourceFormat} -> array`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -60,6 +60,28 @@ describe('findings exclusions', () => {
|
|||||||
assert.ok(logs.some(line => line.includes('排除問題格式已修正為頂層陣列: source=exclusions -> array')));
|
assert.ok(logs.some(line => line.includes('排除問題格式已修正為頂層陣列: source=exclusions -> array')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('mirrors repaired exclusions into the workspace root when requested', () => {
|
||||||
|
const repoRoot = path.join(workspace, 'repo');
|
||||||
|
const mirrorRoot = path.join(workspace, 'workspace');
|
||||||
|
const repoFullPath = path.join(repoRoot, EXCLUSIONS_PATH);
|
||||||
|
const mirrorFullPath = path.join(mirrorRoot, EXCLUSIONS_PATH);
|
||||||
|
fs.mkdirSync(path.dirname(repoFullPath), { recursive: true });
|
||||||
|
fs.mkdirSync(path.dirname(mirrorFullPath), { recursive: true });
|
||||||
|
fs.writeFileSync(repoFullPath, JSON.stringify({
|
||||||
|
exclusions: [
|
||||||
|
{ location: 'README.md:12', suggestion: 'keep' },
|
||||||
|
],
|
||||||
|
}, null, 2));
|
||||||
|
|
||||||
|
const exclusions = loadExclusions(repoRoot, null, mirrorRoot);
|
||||||
|
const mirror = JSON.parse(fs.readFileSync(mirrorFullPath, 'utf8'));
|
||||||
|
|
||||||
|
assert.equal(exclusions.length, 1);
|
||||||
|
assert.ok(Array.isArray(mirror));
|
||||||
|
assert.equal(mirror[0].location, 'README.md:12');
|
||||||
|
assert.equal(mirror[0].suggestion, 'keep');
|
||||||
|
});
|
||||||
|
|
||||||
it('applies exclusions loaded from wrapper format', () => {
|
it('applies exclusions loaded from wrapper format', () => {
|
||||||
const findings = [
|
const findings = [
|
||||||
{ location: 'entrypoint.sh:180', role: 'Maya', suggestion: 'keep' },
|
{ location: 'entrypoint.sh:180', role: 'Maya', suggestion: 'keep' },
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@ async function main() {
|
|||||||
ok(`Step3 去重完成: ${mergedFindings.length} -> ${sorted.length} 筆 (critical=${sorted.filter(f=>f.level==='critical').length} warning=${sorted.filter(f=>f.level==='warning').length} info=${sorted.filter(f=>f.level==='info').length})`);
|
ok(`Step3 去重完成: ${mergedFindings.length} -> ${sorted.length} 筆 (critical=${sorted.filter(f=>f.level==='critical').length} warning=${sorted.filter(f=>f.level==='warning').length} info=${sorted.filter(f=>f.level==='info').length})`);
|
||||||
|
|
||||||
step('Step4', 'AI 排除問題過濾');
|
step('Step4', 'AI 排除問題過濾');
|
||||||
const exclusions = loadExclusions(repoDir || WORKSPACE, repoState);
|
const exclusions = loadExclusions(repoDir || WORKSPACE, repoState, WORKSPACE);
|
||||||
const ruleFiltered = applyExclusions(sorted, exclusions);
|
const ruleFiltered = applyExclusions(sorted, exclusions);
|
||||||
const filtered = await filterFalsePositivesWithAI(ruleFiltered, exclusions);
|
const filtered = await filterFalsePositivesWithAI(ruleFiltered, exclusions);
|
||||||
ok(`Step4 完成: findings total=${filtered.length}`);
|
ok(`Step4 完成: findings total=${filtered.length}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user