verifyos_cli/rules/
ats.rs1use crate::rules::core::{
2 AppStoreRule, ArtifactContext, RuleCategory, RuleError, RuleReport, RuleStatus, Severity,
3};
4
5pub struct AtsAuditRule;
6
7impl AppStoreRule for AtsAuditRule {
8 fn id(&self) -> &'static str {
9 "RULE_ATS_AUDIT"
10 }
11
12 fn name(&self) -> &'static str {
13 "ATS Exceptions Detected"
14 }
15
16 fn category(&self) -> RuleCategory {
17 RuleCategory::Ats
18 }
19
20 fn severity(&self) -> Severity {
21 Severity::Warning
22 }
23
24 fn recommendation(&self) -> &'static str {
25 "Remove ATS exceptions or scope them to specific domains with justification."
26 }
27
28 fn evaluate(&self, artifact: &ArtifactContext) -> Result<RuleReport, RuleError> {
29 let Some(plist) = artifact.info_plist else {
30 return Ok(RuleReport {
31 status: RuleStatus::Skip,
32 message: Some("Info.plist not found".to_string()),
33 evidence: None,
34 });
35 };
36
37 let Some(ats_dict) = plist.get_dictionary("NSAppTransportSecurity") else {
38 return Ok(RuleReport {
39 status: RuleStatus::Pass,
40 message: None,
41 evidence: None,
42 });
43 };
44
45 let mut issues = Vec::new();
46
47 if let Some(true) = ats_dict
48 .get("NSAllowsArbitraryLoads")
49 .and_then(|v| v.as_boolean())
50 {
51 issues.push("NSAllowsArbitraryLoads=true".to_string());
52 }
53
54 if let Some(true) = ats_dict
55 .get("NSAllowsArbitraryLoadsInWebContent")
56 .and_then(|v| v.as_boolean())
57 {
58 issues.push("NSAllowsArbitraryLoadsInWebContent=true".to_string());
59 }
60
61 if let Some(domains) = ats_dict
62 .get("NSExceptionDomains")
63 .and_then(|v| v.as_dictionary())
64 {
65 for (domain, config) in domains {
66 if let Some(true) = config
67 .as_dictionary()
68 .and_then(|d| d.get("NSExceptionAllowsInsecureHTTPLoads"))
69 .and_then(|v| v.as_boolean())
70 {
71 issues.push(format!("NSExceptionAllowsInsecureHTTPLoads for {domain}"));
72 }
73 }
74 }
75
76 if issues.is_empty() {
77 return Ok(RuleReport {
78 status: RuleStatus::Pass,
79 message: None,
80 evidence: None,
81 });
82 }
83
84 Ok(RuleReport {
85 status: RuleStatus::Fail,
86 message: Some("ATS exceptions detected".to_string()),
87 evidence: Some(issues.join("; ")),
88 })
89 }
90}