Skip to main content

ailint_core/rules/security/
tool_confirmation.rs

1//! AIL203 `tool-confirmation-required` — Ensure critical/destructive rules include "Wait for human confirmation" phrasing.
2//!
3//! See: `docs/rules/security/AIL203.md`
4
5use crate::parser::{DocumentContent, ParsedDocument};
6use crate::rules::security::{line_of_offset, AIL203};
7use crate::rules::{Rule, RuleContext, RuleId, Severity, Violation};
8
9/// AIL203 tool-confirmation-required: destructive actions need a confirmation step.
10#[derive(Debug, Default)]
11pub struct ToolConfirmationRequiredRule;
12
13impl Rule for ToolConfirmationRequiredRule {
14    fn id(&self) -> RuleId {
15        AIL203
16    }
17
18    fn default_severity(&self) -> Severity {
19        Severity::Error
20    }
21
22    fn run(&self, doc: &ParsedDocument, ctx: &RuleContext<'_>) -> Vec<Violation> {
23        match &doc.content {
24            DocumentContent::Markdown(_) | DocumentContent::Text => {}
25            _ => return Vec::new(),
26        };
27
28        let destructive_phrases = [
29            "delete data",
30            "rm -rf",
31            "drop table",
32            "truncate table",
33            "irreversible",
34            "destructive action",
35        ];
36        let confirmation_phrases = [
37            "ask",
38            "confirm",
39            "human",
40            "wait",
41            "permission",
42            "consent",
43            "approval",
44        ];
45
46        let lower_raw = doc.raw.to_lowercase();
47
48        let mut violations = Vec::new();
49        for d in &destructive_phrases {
50            if let Some(idx) = lower_raw.find(d) {
51                if !confirmation_phrases.iter().any(|c| lower_raw.contains(c)) {
52                    let line = line_of_offset(&doc.raw, idx);
53                    let mut v = Violation::new(
54                        AIL203,
55                        ctx.severity,
56                        doc.path.clone(),
57                        format!("Document describes destructive actions ('{}') but lacks confirmation constraints.", d),
58                    ).at(line, 1);
59                    v.fix_hint = Some("Include explicit phrasing like 'wait for human confirmation' or 'ask for permission' before destructive actions.".to_string());
60                    violations.push(v);
61
62                    break;
63                }
64            }
65        }
66
67        violations
68    }
69}