pub mod brules;
mod cert_c;
use crate::analyze::cfg::FunctionCfg;
use crate::analyze::context::ProjectContext;
use crate::analyze::value_range::RangeAnalysisResult;
use std::collections::HashMap;
use tree_sitter::Node;
pub trait CertRule {
fn rule_id(&self) -> &'static str;
fn description(&self) -> &'static str;
fn severity(&self) -> crate::manifest::Severity;
fn category(&self) -> crate::manifest::RuleCategory;
fn cert_id(&self) -> &'static str;
fn check(&self, node: &Node, source: &str) -> Vec<RuleViolation> {
let mut violations = Vec::new();
self.scan(node, source, &mut violations);
violations
}
fn scan(&self, _node: &Node, _source: &str, _violations: &mut Vec<RuleViolation>) {
unreachable!("scan() has no implementation; this rule should override check() instead")
}
fn check_with_cfg(
&self,
node: &Node,
source: &str,
_cfg: Option<&FunctionCfg>,
) -> Vec<RuleViolation> {
self.check(node, source)
}
fn set_project_context(&self, _context: &ProjectContext) {}
fn set_function_cfgs(&self, _cfgs: &HashMap<usize, FunctionCfg>) {}
fn applies_to_file(&self, _file_path: &str) -> bool {
true
}
fn set_vra_results(&self, _results: &HashMap<usize, RangeAnalysisResult>) {}
fn needs_vra(&self) -> bool {
false
}
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct RuleViolation {
pub rule_id: String,
pub severity: crate::manifest::Severity,
pub message: String,
pub file_path: String,
pub line: usize,
pub column: usize,
pub suggestion: Option<String>,
#[doc(hidden)]
pub requires_manual_review: Option<bool>,
}
impl Default for RuleViolation {
fn default() -> Self {
Self {
rule_id: String::new(),
severity: crate::manifest::Severity::Low,
message: String::new(),
file_path: String::new(),
line: 0,
column: 0,
suggestion: None,
requires_manual_review: None,
}
}
}
impl RuleViolation {
pub fn needs_manual_review(&self) -> bool {
self.requires_manual_review.unwrap_or(false)
}
}
pub struct RuleRegistry {
rules: Vec<Box<dyn CertRule>>,
}
impl Default for RuleRegistry {
fn default() -> Self {
Self::new()
}
}
pub fn get_rule_description(registry: &RuleRegistry, rule_id: &str) -> String {
if let Some(rule) = registry.get_rule(rule_id) {
rule.description().to_string()
} else {
"Unknown rule".to_string()
}
}