verifyos_cli/rules/
entitlements.rs1use crate::parsers::macho_parser::MachOExecutable;
2use crate::rules::core::{AppStoreRule, ArtifactContext, RuleError, RuleResult, Severity};
3
4#[derive(Debug, thiserror::Error, miette::Diagnostic)]
5pub enum EntitlementsError {
6 #[error("Failed to parse Mach-O executable for entitlements")]
7 #[diagnostic(
8 code(verifyos::entitlements::parse_failure),
9 help("The executable could not be parsed as a valid Mach-O binary.")
10 )]
11 ParseFailure,
12
13 #[error("App contains `get-task-allow` entitlement")]
14 #[diagnostic(
15 code(verifyos::entitlements::debug_build),
16 help("The `get-task-allow` entitlement is present and set to true. This indicates a debug build which will be rejected by the App Store.")
17 )]
18 DebugEntitlement,
19
20 #[error("Mach-O Parsing Error: {0}")]
21 #[diagnostic(code(verifyos::entitlements::macho_error))]
22 MachO(#[from] crate::parsers::macho_parser::MachOError),
23}
24
25pub struct EntitlementsMismatchRule;
26
27impl AppStoreRule for EntitlementsMismatchRule {
28 fn id(&self) -> &'static str {
29 "RULE_ENTITLEMENTS_MISMATCH"
30 }
31
32 fn name(&self) -> &'static str {
33 "Entitlements Mismatch"
34 }
35
36 fn severity(&self) -> Severity {
37 Severity::Error
38 }
39
40 fn evaluate(&self, artifact: &ArtifactContext) -> Result<RuleResult, RuleError> {
41 let app_name = artifact
42 .app_bundle_path
43 .file_name()
44 .and_then(|n| n.to_str())
45 .unwrap_or("")
46 .trim_end_matches(".app");
47
48 let executable_path = artifact.app_bundle_path.join(app_name);
49
50 if executable_path.exists() {
51 let macho =
52 MachOExecutable::from_file(&executable_path).map_err(EntitlementsError::MachO)?;
53
54 if let Some(entitlements_xml) = macho.entitlements {
55 let plist = crate::parsers::plist_reader::InfoPlist::from_bytes(
57 entitlements_xml.as_bytes(),
58 )
59 .map_err(|_| EntitlementsError::ParseFailure)?;
60
61 if let Some(true) = plist.get_bool("get-task-allow") {
63 return Err(RuleError::Entitlements(EntitlementsError::DebugEntitlement));
64 }
65 }
66 }
67
68 Ok(RuleResult { success: true })
69 }
70}