ailint_core/rules/security/
mod.rs1pub mod prompt_injection;
5pub mod sensitive_data;
6pub mod tool_confirmation;
7pub mod unrestricted_tool;
8
9pub use prompt_injection::NoPromptInjectionMarkerRule;
10pub use sensitive_data::NoSensitiveDataInInstructionsRule;
11pub use tool_confirmation::ToolConfirmationRequiredRule;
12pub use unrestricted_tool::NoUnrestrictedToolGrantRule;
13
14use crate::rules::{Rule, RuleId};
15
16pub const AIL200: RuleId = RuleId::new(200, "no-prompt-injection-marker");
18pub const AIL201: RuleId = RuleId::new(201, "no-unrestricted-tool-grant");
20pub const AIL202: RuleId = RuleId::new(202, "no-sensitive-data-in-instructions");
22pub const AIL203: RuleId = RuleId::new(203, "tool-confirmation-required");
24
25pub fn all_rules() -> Vec<Box<dyn Rule>> {
27 vec![
28 Box::new(NoPromptInjectionMarkerRule),
29 Box::new(NoUnrestrictedToolGrantRule),
30 Box::new(NoSensitiveDataInInstructionsRule),
31 Box::new(ToolConfirmationRequiredRule),
32 ]
33}
34
35pub(crate) fn line_of_offset(raw: &str, offset: usize) -> usize {
37 let cap = offset.min(raw.len());
38 raw.as_bytes()[..cap]
39 .iter()
40 .filter(|&&b| b == b'\n')
41 .count()
42 + 1
43}
44
45pub(crate) fn line_containing(raw: &str, offset: usize) -> String {
47 let bytes = raw.as_bytes();
48 let cap = offset.min(bytes.len());
49 let start = bytes[..cap]
50 .iter()
51 .rposition(|&b| b == b'\n')
52 .map(|i| i + 1)
53 .unwrap_or(0);
54 let end = bytes[cap..]
55 .iter()
56 .position(|&b| b == b'\n')
57 .map(|i| cap + i)
58 .unwrap_or(bytes.len());
59 raw[start..end].trim().to_string()
60}
61
62pub(crate) fn truncate_chars(s: &str, max: usize) -> String {
64 if s.chars().count() <= max {
65 return s.to_string();
66 }
67 s.chars().take(max).collect()
68}