Skip to content

Commit e82d211

Browse files
hyperpolymathclaude
andcommitted
feat(panicbot): PA021 ProofDrift mapping + suppressed field on WeakPoint
Add PA021 rule mapping for the new ProofDrift weak point category (formal verification drift: sorry/Admitted/believe_me/oops/trustMe etc.). Fleet category: static-analysis/proof-drift. Confidence 0.92, Control tier. Add suppressed: bool field to WeakPoint (serde(default)) so panicbot can parse reports from panic-attack v2.1.0+ without breaking on older JSON. translate_all() filters suppressed=true findings — the logic engine marked them as likely false positives from defensive patterns. Full audit trail preserved in the raw report; only active findings reach fleet dispatch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent db51e9d commit e82d211

3 files changed

Lines changed: 29 additions & 1 deletion

File tree

bots/panicbot/src/translator.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! Core responsibility: map each `WeakPoint` from the scanner output into a
55
//! `Finding` struct with appropriate:
66
//! - Fleet category (e.g., "static-analysis/unsafe-code")
7-
//! - Rule ID (canonical PA001–PA020 pattern for dedup with Hypatia findings)
7+
//! - Rule ID (canonical PA001–PA021 pattern for dedup with Hypatia findings)
88
//! - Triangle tier (Eliminate / Substitute / Control)
99
//! - Confidence score (honest assessment of detection accuracy)
1010
//! - Fixability (whether automated remediation is possible)
@@ -223,6 +223,19 @@ pub fn category_mapping(category: &str) -> Option<CategoryMapping> {
223223
default_confidence: 0.65,
224224
fixability: Fixability::No,
225225
}),
226+
// PA021 — formal verification drift: banned proof escape hatches (sorry, Admitted,
227+
// believe_me, oops, trustMe, assert_total, %partial) or Julia mirror files that
228+
// substitute `@test x isa Y` assertions for formally-proven theorems.
229+
// Confidence is high because these keywords have essentially no false positives
230+
// in proof assistant files — they exist only to bypass the checker.
231+
"ProofDrift" => Some(CategoryMapping {
232+
fleet_category: "static-analysis/proof-drift",
233+
rule_id: "PA021",
234+
rule_name: "Formal verification drift",
235+
triangle_tier: TriangleTier::Control,
236+
default_confidence: 0.92,
237+
fixability: Fixability::No,
238+
}),
226239
_ => None,
227240
}
228241
}
@@ -435,6 +448,7 @@ mod tests {
435448
severity: "Critical".to_string(),
436449
description: "AWS_SECRET_KEY found in source".to_string(),
437450
recommended_attack: vec![],
451+
suppressed: false,
438452
};
439453
let config = PanicbotConfig::default();
440454
let finding = translate_weak_point(&wp, &config);
@@ -458,6 +472,7 @@ mod tests {
458472
severity: "Medium".to_string(),
459473
description: "Something new".to_string(),
460474
recommended_attack: vec![],
475+
suppressed: false,
461476
};
462477
let config = PanicbotConfig::default();
463478
let finding = translate_weak_point(&wp, &config);
@@ -476,6 +491,7 @@ mod tests {
476491
severity: "High".to_string(),
477492
description: "unsafe block".to_string(),
478493
recommended_attack: vec![],
494+
suppressed: false,
479495
};
480496
let config = PanicbotConfig {
481497
confidence_overrides: vec![crate::config::ConfidenceOverride {
@@ -497,13 +513,15 @@ mod tests {
497513
severity: "Low".to_string(),
498514
description: "low severity".to_string(),
499515
recommended_attack: vec![],
516+
suppressed: false,
500517
},
501518
WeakPoint {
502519
category: "CommandInjection".to_string(),
503520
location: None,
504521
severity: "Critical".to_string(),
505522
description: "critical severity".to_string(),
506523
recommended_attack: vec![],
524+
suppressed: false,
507525
},
508526
];
509527
let config = PanicbotConfig {
@@ -528,6 +546,7 @@ mod tests {
528546
severity: "High".to_string(),
529547
description: "fixable".to_string(),
530548
recommended_attack: vec![],
549+
suppressed: false,
531550
},
532551
&config,
533552
),
@@ -538,6 +557,7 @@ mod tests {
538557
severity: "High".to_string(),
539558
description: "not fixable".to_string(),
540559
recommended_attack: vec![],
560+
suppressed: false,
541561
},
542562
&config,
543563
),

bots/panicbot/tests/integration_test.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,34 +28,39 @@ fn mock_assail_report() -> AssailReport {
2828
severity: "High".to_string(),
2929
description: "3 unsafe blocks in FFI boundary".to_string(),
3030
recommended_attack: vec!["Memory".to_string()],
31+
suppressed: false,
3132
},
3233
WeakPoint {
3334
category: "HardcodedSecret".to_string(),
3435
location: Some("src/config.rs:15".to_string()),
3536
severity: "Critical".to_string(),
3637
description: "AWS_SECRET_ACCESS_KEY found in source code".to_string(),
3738
recommended_attack: vec![],
39+
suppressed: false,
3840
},
3941
WeakPoint {
4042
category: "PanicPath".to_string(),
4143
location: Some("src/handler.rs:87".to_string()),
4244
severity: "Medium".to_string(),
4345
description: "unwrap() on user-provided input".to_string(),
4446
recommended_attack: vec!["CPU".to_string()],
47+
suppressed: false,
4548
},
4649
WeakPoint {
4750
category: "RaceCondition".to_string(),
4851
location: Some("src/cache.rs:23".to_string()),
4952
severity: "High".to_string(),
5053
description: "Shared mutable state without synchronisation".to_string(),
5154
recommended_attack: vec!["Concurrency".to_string()],
55+
suppressed: false,
5256
},
5357
WeakPoint {
5458
category: "UncheckedError".to_string(),
5559
location: Some("src/db.rs:56".to_string()),
5660
severity: "Medium".to_string(),
5761
description: "Result ignored from database query".to_string(),
5862
recommended_attack: vec![],
63+
suppressed: false,
5964
},
6065
],
6166
statistics: serde_json::json!({"total_lines": 5000}),

bots/panicbot/tests/translator_test.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ fn weak_point(category: &str, severity: &str) -> WeakPoint {
2525
severity: severity.to_string(),
2626
description: format!("Test finding for {}", category),
2727
recommended_attack: vec![],
28+
suppressed: false,
2829
}
2930
}
3031

@@ -36,6 +37,7 @@ fn weak_point_at(category: &str, severity: &str, location: &str) -> WeakPoint {
3637
severity: severity.to_string(),
3738
description: format!("Test finding at {}", location),
3839
recommended_attack: vec![],
40+
suppressed: false,
3941
}
4042
}
4143

@@ -302,6 +304,7 @@ fn test_translate_metadata_includes_panic_attack_category() {
302304
severity: "Critical".to_string(),
303305
description: "os.system with user input".to_string(),
304306
recommended_attack: vec!["Memory".to_string(), "Concurrency".to_string()],
307+
suppressed: false,
305308
};
306309
let finding = translator::translate_weak_point(&wp, &config);
307310

0 commit comments

Comments
 (0)