sshconfig_lint/rules/
mod.rs1pub mod basic;
2
3use crate::model::{Config, Finding};
4
5pub trait Rule {
7 fn name(&self) -> &'static str;
9 fn check(&self, config: &Config) -> Vec<Finding>;
11}
12
13pub fn run_all(config: &Config) -> Vec<Finding> {
15 let rules: Vec<Box<dyn Rule>> = vec![
16 Box::new(basic::DuplicateHost),
17 Box::new(basic::IdentityFileExists),
18 Box::new(basic::WildcardHostOrder),
19 Box::new(basic::DeprecatedWeakAlgorithms),
20 Box::new(basic::DuplicateDirectives),
21 ];
22
23 let mut findings = Vec::new();
24 for rule in &rules {
25 findings.extend(rule.check(config));
26 }
27 findings
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use crate::model::{Config, Finding, Item, Severity, Span};
34
35 struct DummyRule;
36 impl Rule for DummyRule {
37 fn name(&self) -> &'static str {
38 "dummy"
39 }
40 fn check(&self, _config: &Config) -> Vec<Finding> {
41 vec![Finding::new(
42 Severity::Info,
43 "dummy",
44 "TEST",
45 "this is a test",
46 Span::new(1),
47 )]
48 }
49 }
50
51 #[test]
52 fn trait_rule_returns_finding() {
53 let config = Config { items: vec![] };
54 let rule = DummyRule;
55 let findings = rule.check(&config);
56 assert_eq!(findings.len(), 1);
57 assert_eq!(findings[0].rule, "dummy");
58 }
59
60 #[test]
61 fn run_all_merges_findings() {
62 let config = Config { items: vec![] };
64 let findings = run_all(&config);
65 assert!(findings.is_empty());
67 }
68
69 #[test]
70 fn run_all_on_config_with_duplicates() {
71 let config = Config {
72 items: vec![
73 Item::HostBlock {
74 patterns: vec!["github.com".to_string()],
75 span: Span::new(1),
76 items: vec![],
77 },
78 Item::HostBlock {
79 patterns: vec!["github.com".to_string()],
80 span: Span::new(5),
81 items: vec![],
82 },
83 ],
84 };
85 let findings = run_all(&config);
86 assert!(findings.iter().any(|f| f.rule == "duplicate-host"));
87 }
88}