sysknife_daemon/actions/
apparmor.rs1use super::{command_mechanism, ActionSpec};
18use sysknife_types::RiskLevel;
19
20pub fn specs() -> Vec<ActionSpec> {
26 vec![
27 apparmor_status(),
28 apparmor_enforce("/etc/apparmor.d/usr.bin.firefox"),
29 apparmor_complain("/etc/apparmor.d/usr.bin.firefox"),
30 ]
31}
32
33pub fn apparmor_status() -> ActionSpec {
41 ActionSpec {
42 action_name: "AppArmorStatus",
43 mechanism: command_mechanism("sudo", ["aa-status"]),
44 risk_level: RiskLevel::Low,
45 reboot_required: false,
46 rollback_available: false,
47 }
48}
49
50pub fn apparmor_enforce(profile_path: &str) -> ActionSpec {
59 ActionSpec {
60 action_name: "AppArmorEnforce",
61 mechanism: command_mechanism("sudo", ["aa-enforce", "--", profile_path]),
62 risk_level: RiskLevel::High,
63 reboot_required: false,
64 rollback_available: false,
65 }
66}
67
68pub fn apparmor_complain(profile_path: &str) -> ActionSpec {
79 ActionSpec {
80 action_name: "AppArmorComplain",
81 mechanism: command_mechanism("sudo", ["aa-complain", "--", profile_path]),
82 risk_level: RiskLevel::High,
83 reboot_required: false,
84 rollback_available: false,
85 }
86}
87
88#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::actions::ActionMechanism;
96
97 fn extract_args(spec: &ActionSpec) -> (&'static str, Vec<String>) {
98 match &spec.mechanism {
99 ActionMechanism::Command { program, args } => (*program, args.clone()),
100 _ => panic!("expected Command mechanism"),
101 }
102 }
103
104 #[test]
107 fn apparmor_status_action_name() {
108 assert_eq!(apparmor_status().action_name, "AppArmorStatus");
109 }
110
111 #[test]
112 fn apparmor_status_risk_is_low() {
113 assert_eq!(apparmor_status().risk_level, RiskLevel::Low);
114 }
115
116 #[test]
117 fn apparmor_status_argv() {
118 let spec = apparmor_status();
119 let (prog, args) = extract_args(&spec);
120 assert_eq!(prog, "sudo");
121 let a: Vec<&str> = args.iter().map(String::as_str).collect();
122 assert_eq!(a, vec!["aa-status"]);
123 }
124
125 #[test]
128 fn apparmor_enforce_action_name() {
129 assert_eq!(
130 apparmor_enforce("/etc/apparmor.d/usr.bin.firefox").action_name,
131 "AppArmorEnforce"
132 );
133 }
134
135 #[test]
136 fn apparmor_enforce_risk_is_high() {
137 assert_eq!(
138 apparmor_enforce("/etc/apparmor.d/usr.bin.firefox").risk_level,
139 RiskLevel::High
140 );
141 }
142
143 #[test]
144 fn apparmor_enforce_argv() {
145 let profile = "/etc/apparmor.d/usr.bin.firefox";
146 let spec = apparmor_enforce(profile);
147 let (prog, args) = extract_args(&spec);
148 assert_eq!(prog, "sudo");
149 let a: Vec<&str> = args.iter().map(String::as_str).collect();
150 assert_eq!(a, vec!["aa-enforce", "--", profile]);
151 }
152
153 #[test]
156 fn apparmor_complain_action_name() {
157 assert_eq!(
158 apparmor_complain("/etc/apparmor.d/usr.bin.firefox").action_name,
159 "AppArmorComplain"
160 );
161 }
162
163 #[test]
164 fn apparmor_complain_risk_is_high() {
165 assert_eq!(
168 apparmor_complain("/etc/apparmor.d/usr.bin.firefox").risk_level,
169 RiskLevel::High
170 );
171 }
172
173 #[test]
174 fn apparmor_complain_argv() {
175 let profile = "/etc/apparmor.d/usr.bin.nginx";
176 let spec = apparmor_complain(profile);
177 let (prog, args) = extract_args(&spec);
178 assert_eq!(prog, "sudo");
179 let a: Vec<&str> = args.iter().map(String::as_str).collect();
180 assert_eq!(a, vec!["aa-complain", "--", profile]);
181 }
182
183 #[test]
184 fn enforce_uses_aa_enforce_not_aa_complain() {
185 let spec = apparmor_enforce("/etc/apparmor.d/test");
186 let (_, args) = extract_args(&spec);
187 let a: Vec<&str> = args.iter().map(String::as_str).collect();
188 assert!(a.contains(&"aa-enforce"));
189 assert!(!a.contains(&"aa-complain"));
190 }
191
192 #[test]
193 fn complain_uses_aa_complain_not_aa_enforce() {
194 let spec = apparmor_complain("/etc/apparmor.d/test");
195 let (_, args) = extract_args(&spec);
196 let a: Vec<&str> = args.iter().map(String::as_str).collect();
197 assert!(a.contains(&"aa-complain"));
198 assert!(!a.contains(&"aa-enforce"));
199 }
200
201 #[test]
204 fn specs_covers_all_action_names() {
205 let expected = ["AppArmorStatus", "AppArmorEnforce", "AppArmorComplain"];
206 let spec_names: Vec<&str> = specs().iter().map(|s| s.action_name).collect();
207 for name in &expected {
208 assert!(spec_names.contains(name), "specs() missing {name}");
209 }
210 }
211}