feat(agent): wire control triage into the scan pipeline (end-to-end SAST)
CI / Check (push) Skipped
CI / Check (pull_request) Successful in 5m59s
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
CI / Check (push) Skipped
CI / Check (pull_request) Successful in 5m59s
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
After the deterministic tools run, the orchestrator's new control_triage stage stamps each finding with the compliance control(s) it is evidence for and flags control false positives. triage_repo_findings builds control specs from the ingested OSCAL catalog, reads a code window per finding, and runs ControlTriage (control-map LUT -> grounded judge). Adds Finding.control_refs (serde default); the ground gate stamps it. Opt-in via BREAKPILOT_BASE_URL. 2 region tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f712ba1e60
commit
075a4cb81b
@@ -96,8 +96,8 @@ pub fn ground(
|
||||
finding.line_number = Some(line);
|
||||
finding.code_snippet = Some(snippet.to_string());
|
||||
finding.confidence = Some(verdict.confidence);
|
||||
// Carry the control reference (a dedicated field lands with the dashboard slice).
|
||||
finding.rule_id = Some(spec.control_id.clone());
|
||||
// Carry the control reference on the finding.
|
||||
finding.control_refs = vec![spec.control_id.clone()];
|
||||
Some(finding)
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ mod tests {
|
||||
let f = ground(&spec(), ®ion(), &v, "repo").expect("should ground");
|
||||
assert_eq!(f.line_number, Some(11)); // 2nd line of a region starting at 10
|
||||
assert_eq!(f.cwe.as_deref(), Some("CWE-798")); // fell back to the spec default
|
||||
assert_eq!(f.rule_id.as_deref(), Some("cra-ai-8")); // control ref carried
|
||||
assert_eq!(f.control_refs, vec!["cra-ai-8".to_string()]); // control ref carried
|
||||
assert_eq!(f.file_path.as_deref(), Some("src/auth.py"));
|
||||
assert_eq!(f.code_snippet.as_deref(), Some("PASSWORD = \"admin123\""));
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ pub struct Finding {
|
||||
pub triage_rationale: Option<String>,
|
||||
/// Developer feedback on finding quality
|
||||
pub developer_feedback: Option<String>,
|
||||
/// Compliance control ids this finding is evidence for (stamped by control
|
||||
/// triage against the `control-map` LUT). Empty when unmapped.
|
||||
#[serde(default)]
|
||||
pub control_refs: Vec<String>,
|
||||
#[serde(with = "super::serde_helpers::bson_datetime")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
#[serde(with = "super::serde_helpers::bson_datetime")]
|
||||
@@ -118,6 +122,7 @@ impl Finding {
|
||||
triage_action: None,
|
||||
triage_rationale: None,
|
||||
developer_feedback: None,
|
||||
control_refs: Vec::new(),
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user