fix(orchestrator): refresh control_refs on existing findings during re-scan #228
@@ -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 refreshed_count = 0u32;
|
||||
let mut new_findings: Vec<Finding> = Vec::new();
|
||||
for mut finding in all_findings {
|
||||
finding.scan_run_id = Some(scan_run_id.to_string());
|
||||
@@ -293,8 +295,25 @@ impl PipelineOrchestrator {
|
||||
finding.id = result.inserted_id.as_object_id();
|
||||
new_findings.push(finding);
|
||||
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
|
||||
if !sbom_entries.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user