From 76260acc76ea8d20825ac220e16d15db694bd72d Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar Date: Wed, 11 Mar 2026 16:04:35 +0100 Subject: [PATCH] fix: prevent duplicate issue creation across repo delete/re-add Search all issue states (not just open) in Gitea tracker to find existing issues. Add title-based fallback search in addition to fingerprint search, so issues are found even if body format changed. Co-Authored-By: Claude Opus 4.6 --- compliance-agent/src/pipeline/orchestrator.rs | 46 +++++++++++-------- compliance-agent/src/trackers/gitea.rs | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/compliance-agent/src/pipeline/orchestrator.rs b/compliance-agent/src/pipeline/orchestrator.rs index 82fa5e8..8a6e40c 100644 --- a/compliance-agent/src/pipeline/orchestrator.rs +++ b/compliance-agent/src/pipeline/orchestrator.rs @@ -684,30 +684,36 @@ impl PipelineOrchestrator { let mut created = 0u32; for finding in actionable { - // Check if an issue already exists for this fingerprint - match tracker - .find_existing_issue(owner, tracker_repo_name, &finding.fingerprint) - .await - { - Ok(Some(existing)) => { - tracing::debug!( - "[{repo_id}] Issue already exists for {}: {}", - finding.fingerprint, - existing.external_url - ); - continue; - } - Ok(None) => {} - Err(e) => { - tracing::warn!("[{repo_id}] Failed to search for existing issue: {e}"); - // Continue and try to create anyway - } - } - let title = format!( "[{}] {}: {}", finding.severity, finding.scanner, finding.title ); + + // Check if an issue already exists by fingerprint first, then by title + let mut found_existing = false; + for search_term in [&finding.fingerprint, &title] { + match tracker + .find_existing_issue(owner, tracker_repo_name, search_term) + .await + { + Ok(Some(existing)) => { + tracing::debug!( + "[{repo_id}] Issue already exists for '{}': {}", + search_term, + existing.external_url + ); + found_existing = true; + break; + } + Ok(None) => {} + Err(e) => { + tracing::warn!("[{repo_id}] Failed to search for existing issue: {e}"); + } + } + } + if found_existing { + continue; + } let body = format_issue_body(finding); let labels = vec![ format!("severity:{}", finding.severity), diff --git a/compliance-agent/src/trackers/gitea.rs b/compliance-agent/src/trackers/gitea.rs index 4e8cc20..8d3debb 100644 --- a/compliance-agent/src/trackers/gitea.rs +++ b/compliance-agent/src/trackers/gitea.rs @@ -183,7 +183,7 @@ impl IssueTracker for GiteaTracker { fingerprint: &str, ) -> Result, CoreError> { let url = self.api_url(&format!( - "/repos/{owner}/{repo}/issues?type=issues&state=open&q={fingerprint}" + "/repos/{owner}/{repo}/issues?type=issues&state=all&q={fingerprint}" )); let resp = self