mod heuristic;
mod null;
use std::sync::Arc;
use async_trait::async_trait;
use systemprompt_models::wire::canonical::{CanonicalRequest, CanonicalResponse};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Severity {
Low,
Medium,
High,
}
impl Severity {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
}
}
}
#[derive(Debug, Clone)]
pub struct Finding {
pub phase: &'static str,
pub severity: Severity,
pub category: String,
pub excerpt: Option<String>,
pub scanner: &'static str,
}
#[async_trait]
pub trait SafetyScanner: Send + Sync {
fn name(&self) -> &'static str;
async fn scan_request(&self, req: &CanonicalRequest) -> Vec<Finding>;
async fn scan_response_final(&self, response: &CanonicalResponse) -> Vec<Finding>;
}
#[derive(Debug, Clone, Copy)]
pub struct SafetyScannerRegistration {
pub name: &'static str,
pub factory: fn() -> Arc<dyn SafetyScanner>,
}
inventory::collect!(SafetyScannerRegistration);
#[macro_export]
macro_rules! register_safety_scanner {
($factory:expr, name = $name:expr $(,)?) => {
::inventory::submit! {
$crate::SafetyScannerRegistration {
name: $name,
factory: || ::std::sync::Arc::new($factory()),
}
}
};
}
pub use heuristic::HeuristicScanner;
pub use null::NullScanner;