Skip to main content

xbp_analysis/adapters/
fix.rs

1//! Safe autofixes only — never rewrites recovery/retry/transaction logic.
2
3use crate::domain::types::Finding;
4use crate::domain::types::SourceFile;
5use crate::ports::inbound::{AppliedFix, FixService};
6use crate::ports::outbound::SourceWriter;
7use std::fs;
8use std::path::Path;
9
10/// Writes source files to disk.
11pub struct FsSourceWriter;
12
13impl SourceWriter for FsSourceWriter {
14    fn write(&self, path: &Path, content: &str) -> Result<(), String> {
15        fs::write(path, content).map_err(|e| e.to_string())
16    }
17}
18
19/// Only applies fixes marked as unambiguous and safe by rule metadata / fix_hint patterns.
20pub struct SafeFixApplier {
21    writer: Box<dyn SourceWriter>,
22}
23
24impl SafeFixApplier {
25    pub fn new(writer: Box<dyn SourceWriter>) -> Self {
26        Self { writer }
27    }
28
29    pub fn default_fs() -> Self {
30        Self::new(Box::new(FsSourceWriter))
31    }
32}
33
34impl FixService for SafeFixApplier {
35    fn apply_safe_fixes(
36        &self,
37        findings: &[Finding],
38        sources: &[(SourceFile, String)],
39    ) -> Result<Vec<AppliedFix>, String> {
40        let applied = Vec::new();
41        // Policy: refuse distributed / retry / transaction related rules always.
42        const FORBIDDEN: &[&str] = &[
43            "unbounded-retry",
44            "non-idempotent-retry",
45            "partial-commit",
46            "error-context-loss",
47            "unobserved-task-failure",
48            "missing-cleanup",
49        ];
50
51        for f in findings {
52            if FORBIDDEN.contains(&f.rule_id.as_str()) {
53                continue;
54            }
55            // Currently only document intent; real rewrites require explicit fix_hint
56            // patterns that are purely mechanical (none enabled by default).
57            let _ = (f, sources);
58        }
59        // No automatic rewrites of error propagation without explicit approval.
60        let _ = &self.writer;
61        Ok(applied)
62    }
63}