From ed057d2127aacd104f05bb395267736b2e519e26 Mon Sep 17 00:00:00 2001 From: Adam Bronte Date: Wed, 25 Feb 2026 11:58:13 -0800 Subject: [PATCH 1/2] add support for coverity --- src/scanners/parsers/coverity.rs | 62 ++++++++++++++++++++++++++++++++ src/scanners/parsers/mod.rs | 16 ++++----- 2 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 src/scanners/parsers/coverity.rs diff --git a/src/scanners/parsers/coverity.rs b/src/scanners/parsers/coverity.rs new file mode 100644 index 0000000..1d3f5d7 --- /dev/null +++ b/src/scanners/parsers/coverity.rs @@ -0,0 +1,62 @@ +use super::{ParseResult, ScanParser}; +use crate::log::debug; +use quick_xml::events::Event; +use quick_xml::Reader; + +pub struct CoverityParser; + +impl ScanParser for CoverityParser { + fn detect(&self, input: &str) -> bool { + input.contains("xmlns:cov=\"http://coverity.com\"") + } + + fn parse(&self, input: &str) -> Option { + debug("Detected coverity schema"); + + let mut paths = Vec::new(); + let mut reader = Reader::from_str(input); + let mut buf = Vec::new(); + + loop { + match reader.read_event_into(&mut buf) { + Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) => { + let is_merged_defect = e.name().as_ref() == b"cov:mergedDefect" + || e.name().as_ref() == b"mergedDefect"; + if is_merged_defect { + for attr in e.attributes() { + if let Ok(attr) = attr { + if attr.key.as_ref() == b"file" { + if let Ok(file_path) = std::str::from_utf8(attr.value.as_ref()) + { + let clean_path = file_path + .trim_start_matches('/') + .trim_start_matches('\\'); + if !clean_path.is_empty() { + paths.push(clean_path.to_string()); + } + } + } + } + } + } + } + Ok(Event::Eof) => break, + Err(e) => { + eprintln!("Error parsing XML: {}", e); + return None; + } + _ => {} + } + buf.clear(); + } + + Some(ParseResult { + paths, + scanner: "coverity".to_string(), + }) + } + + fn scanner_name(&self) -> &str { + "coverity" + } +} diff --git a/src/scanners/parsers/mod.rs b/src/scanners/parsers/mod.rs index 414d0f6..8311935 100644 --- a/src/scanners/parsers/mod.rs +++ b/src/scanners/parsers/mod.rs @@ -8,9 +8,9 @@ pub struct ParseResult { pub trait ScanParser { fn detect(&self, input: &str) -> bool; - + fn parse(&self, input: &str) -> Option; - + #[allow(dead_code)] fn scanner_name(&self) -> &str; } @@ -27,16 +27,17 @@ impl ScanParserFactory { Box::new(checkmarx::CheckmarxCliParser), Box::new(checkmarx::CheckmarxWebParser), Box::new(checkmarx::CheckmarxXmlParser), + Box::new(coverity::CoverityParser), ]; - + Self { parsers } } - + #[allow(dead_code)] pub fn find_parser(&self, input: &str) -> Option<&Box> { self.parsers.iter().find(|parser| parser.detect(input)) } - + pub fn parse_scan_data(&self, input: &str) -> Result { for parser in &self.parsers { if parser.detect(input) { @@ -46,7 +47,7 @@ impl ScanParserFactory { } } } - + crate::log::debug("Couldn't detect what kind of report this is."); Err("Unsupported scan report format. Please check if your scanner is supported. Supported formats: JSON (Semgrep, SARIF, Checkmarx), XML (Checkmarx).".to_string()) } @@ -55,5 +56,4 @@ impl ScanParserFactory { pub mod semgrep; pub mod sarif; pub mod checkmarx; - - +pub mod coverity; From b2f74924d978af031ddeb3a0952a7b0c2d31ca27 Mon Sep 17 00:00:00 2001 From: Adam Bronte Date: Thu, 26 Feb 2026 11:08:26 -0800 Subject: [PATCH 2/2] version bump --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 335e329..f0d1271 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,7 +311,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "corgea" -version = "1.7.2" +version = "1.8.0" dependencies = [ "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index 02bfeee..5ee85bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "corgea" -version = "1.7.2" +version = "1.8.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html