pub mod auditors;
pub mod consensus;
pub mod providers;
use crate::core::Severity;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct AiAuditorConfig {
pub provider: String,
pub model: String,
pub temperature: f64,
pub max_tokens: u32,
pub min_confidence: f64,
pub api_key: Option<String>,
pub ollama_endpoint: Option<String>,
pub full_audit: bool,
}
impl Default for AiAuditorConfig {
fn default() -> Self {
Self {
provider: "openai".into(),
model: "gpt-5".into(),
temperature: 0.1,
max_tokens: 4000,
min_confidence: 0.5,
api_key: None,
ollama_endpoint: None,
full_audit: false,
}
}
}
#[derive(Debug, Clone)]
pub struct AuditContext {
pub source_code: String,
pub file_name: String,
pub compiler_version: String,
pub additional: HashMap<String, String>,
}
impl AuditContext {
pub fn new(source_code: &str, file_name: &str, compiler_version: &str) -> Self {
Self {
source_code: source_code.to_owned(),
file_name: file_name.to_owned(),
compiler_version: compiler_version.to_owned(),
additional: HashMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct AuditorFinding {
pub title: String,
pub description: String,
pub confidence: f64,
pub severity: Severity,
pub suggestion: String,
pub line_numbers: Vec<usize>,
pub category: String,
}
#[derive(Debug, Clone)]
pub struct ConsensusFinding {
pub auditor: String,
pub domain: String,
pub finding: AuditorFinding,
pub cross_validated: bool,
}
pub fn consensus_to_core_finding(cf: &ConsensusFinding, file_name: &str) -> crate::core::Finding {
use crate::core::FindingBuilder;
let line = cf.finding.line_numbers.first().copied();
FindingBuilder::default()
.id(&format!("AI-{:04}", rand_id()))
.title(&cf.finding.title)
.description(&format!(
"[AI {}] {} (confidence: {:.0}%){}",
cf.auditor,
cf.finding.description,
cf.finding.confidence * 100.0,
if cf.cross_validated {
" [cross-validated]"
} else {
""
}
))
.severity(cf.finding.severity)
.file(file_name)
.location(line.unwrap_or(0), 0)
.code(&format!(
"AI-auditor '{}' ({}) — {}",
cf.auditor, cf.domain, cf.finding.title
))
.recommendation(&cf.finding.suggestion)
.category(&cf.finding.category)
.build()
}
fn rand_id() -> u16 {
use std::time::{SystemTime, UNIX_EPOCH};
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.subsec_nanos();
(nanos % 9999) as u16
}
pub use auditors::*;
pub use consensus::*;
pub use providers::*;