Compare commits

...
Author SHA1 Message Date
Sharang ParnerkarandClaude Opus 4.8 731f84d2e5 fix(orchestrator): refresh control_refs on PLC re-scans
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
run_plc_scan's persist block was insert-only, so a PLC re-scan never
updated control_refs on findings first seen before the semantic mapping
pass ran (or before it was enabled) — mappings could only be picked up by
deleting and re-adding the target. Port the refresh branch run_pipeline
already has (#228): when a finding already exists and now carries
control_refs, $set them onto the existing row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 18:40:12 +02:00
@@ -625,6 +625,7 @@ impl PipelineOrchestrator {
); );
let mut new_count = 0u32; let mut new_count = 0u32;
let mut refreshed_count = 0u32;
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());
if self if self
@@ -636,8 +637,27 @@ impl PipelineOrchestrator {
{ {
self.db.findings().insert_one(&finding).await?; self.db.findings().insert_one(&finding).await?;
new_count += 1; new_count += 1;
} else if !finding.control_refs.is_empty() {
// Re-scan refresh: mirror run_pipeline — persist newly-computed
// control_refs onto a PLC finding first seen before the semantic
// pass ran. The insert path alone never would, so without this a
// PLC re-scan can only pick up mappings via a delete + re-add.
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!(
target_id,
"Refreshed control_refs on {refreshed_count} existing PLC findings"
);
}
if !all_sbom.is_empty() { if !all_sbom.is_empty() {
if let Err(e) = self if let Err(e) = self