feat: control-driven SAST — LUT + grounded LLM triage over tool findings #213
@@ -82,10 +82,7 @@ impl Scanner for SemgrepScanner {
|
||||
finding.file_path = Some(r.path);
|
||||
finding.line_number = Some(r.start.line);
|
||||
finding.code_snippet = Some(r.extra.lines);
|
||||
finding.cwe = r
|
||||
.extra
|
||||
.metadata
|
||||
.and_then(|m| m.get("cwe").and_then(|v| v.as_str()).map(|s| s.to_string()));
|
||||
finding.cwe = r.extra.metadata.as_ref().and_then(extract_cwe);
|
||||
finding
|
||||
})
|
||||
.collect();
|
||||
@@ -124,10 +121,34 @@ struct SemgrepExtra {
|
||||
metadata: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
/// semgrep emits `metadata.cwe` as a list of strings like
|
||||
/// `"CWE-798: Use of Hard-coded Credentials"` (occasionally a bare string). Take
|
||||
/// the first entry and normalise it to just the `CWE-NNN` id.
|
||||
fn extract_cwe(metadata: &serde_json::Value) -> Option<String> {
|
||||
let raw = metadata.get("cwe")?;
|
||||
let text = match raw {
|
||||
serde_json::Value::Array(items) => items.first()?.as_str()?,
|
||||
serde_json::Value::String(s) => s.as_str(),
|
||||
_ => return None,
|
||||
};
|
||||
let id = text.split(':').next().unwrap_or(text).trim();
|
||||
(!id.is_empty()).then(|| id.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn extract_cwe_handles_list_and_normalises() {
|
||||
let md = serde_json::json!({"cwe": ["CWE-798: Use of Hard-coded Credentials"]});
|
||||
assert_eq!(extract_cwe(&md).as_deref(), Some("CWE-798"));
|
||||
let bare = serde_json::json!({"cwe": "CWE-89"});
|
||||
assert_eq!(extract_cwe(&bare).as_deref(), Some("CWE-89"));
|
||||
let none = serde_json::json!({"severity": "ERROR"});
|
||||
assert_eq!(extract_cwe(&none), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_semgrep_output() {
|
||||
let json = r#"{
|
||||
|
||||
Reference in New Issue
Block a user