fix(orchestrator): refresh control_refs on existing findings during re-scan
CI / Check (push) Skipped
CI / Check (pull_request) Successful in 5m40s
CI / Detect Changes (pull_request) Skipped
CI / Deploy Agent (pull_request) Skipped
CI / Deploy Dashboard (pull_request) Skipped
CI / Deploy Docs (pull_request) Skipped
CI / Deploy MCP (pull_request) Skipped
CI / Check (push) Skipped
CI / Check (pull_request) Successful in 5m40s
CI / Detect Changes (pull_request) Skipped
CI / Deploy Agent (pull_request) Skipped
CI / Deploy Dashboard (pull_request) Skipped
CI / Deploy Docs (pull_request) Skipped
CI / Deploy MCP (pull_request) Skipped
The dedup loop only inserted first-seen findings; re-scans skipped existing fingerprints entirely, so control_refs (re)computed by the mapping passes were discarded. A finding first seen before control mapping was enabled/tuned would therefore never gain its control mappings without being deleted + re-added. Now: existing findings whose re-scan produced non-empty control_refs get updated in place ($set control_refs). Guarded on non-empty so a run where mapping didn't run (breakpilot unreachable) can't wipe existing refs. New findings unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ea516cc054
commit
6af84c5216
@@ -277,8 +277,10 @@ impl PipelineOrchestrator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dedup against existing findings and insert new ones
|
// Dedup against existing findings: insert first-seen ones, and refresh the
|
||||||
|
// control mappings on ones we've seen before.
|
||||||
let mut new_count = 0u32;
|
let mut new_count = 0u32;
|
||||||
|
let mut refreshed_count = 0u32;
|
||||||
let mut new_findings: Vec<Finding> = Vec::new();
|
let mut new_findings: Vec<Finding> = Vec::new();
|
||||||
for mut finding in all_findings {
|
for mut finding in all_findings {
|
||||||
finding.scan_run_id = Some(scan_run_id.to_string());
|
finding.scan_run_id = Some(scan_run_id.to_string());
|
||||||
@@ -293,8 +295,25 @@ impl PipelineOrchestrator {
|
|||||||
finding.id = result.inserted_id.as_object_id();
|
finding.id = result.inserted_id.as_object_id();
|
||||||
new_findings.push(finding);
|
new_findings.push(finding);
|
||||||
new_count += 1;
|
new_count += 1;
|
||||||
|
} else if !finding.control_refs.is_empty() {
|
||||||
|
// Re-scan refresh: a mapping pass (newly enabled or tuned) computed
|
||||||
|
// control_refs for a finding first seen before mapping ran. Persist
|
||||||
|
// them onto the existing row — the insert path alone never would.
|
||||||
|
self.db
|
||||||
|
.findings()
|
||||||
|
.update_one(
|
||||||
|
doc! { "fingerprint": &finding.fingerprint },
|
||||||
|
doc! { "$set": { "control_refs": finding.control_refs.clone() } },
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
refreshed_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if refreshed_count > 0 {
|
||||||
|
tracing::info!(
|
||||||
|
"[{repo_id}] Refreshed control_refs on {refreshed_count} existing findings"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove stale SBOM entries for this repo before reinserting
|
// Remove stale SBOM entries for this repo before reinserting
|
||||||
if !sbom_entries.is_empty() {
|
if !sbom_entries.is_empty() {
|
||||||
|
|||||||
Reference in New Issue
Block a user