verifyos_cli/core/
engine.rs1use crate::parsers::plist_reader::{InfoPlist, PlistError};
2use crate::parsers::zip_extractor::{extract_ipa, ExtractionError};
3use crate::rules::core::{AppStoreRule, ArtifactContext, RuleError, RuleResult, Severity};
4use std::path::Path;
5
6#[derive(Debug, thiserror::Error)]
7pub enum OrchestratorError {
8 #[error("Extraction failed: {0}")]
9 Extraction(#[from] ExtractionError),
10 #[error("Failed to parse Info.plist: {0}")]
11 PlistParse(#[from] PlistError),
12 #[error("Could not locate App Bundle (.app) inside IPAPayload")]
13 AppBundleNotFound,
14}
15
16pub struct EngineResult {
17 pub rule_id: &'static str,
18 pub rule_name: &'static str,
19 pub severity: Severity,
20 pub result: Result<RuleResult, RuleError>,
21}
22
23pub struct Engine {
24 rules: Vec<Box<dyn AppStoreRule>>,
25}
26
27impl Engine {
28 pub fn new() -> Self {
29 Self { rules: Vec::new() }
30 }
31
32 pub fn register_rule(&mut self, rule: Box<dyn AppStoreRule>) {
33 self.rules.push(rule);
34 }
35
36 pub fn run<P: AsRef<Path>>(&self, ipa_path: P) -> Result<Vec<EngineResult>, OrchestratorError> {
37 let extracted_ipa = extract_ipa(ipa_path)?;
38
39 let app_bundle_path = extracted_ipa
40 .get_app_bundle_path()
41 .map_err(|e| OrchestratorError::Extraction(ExtractionError::Io(e)))?
42 .ok_or(OrchestratorError::AppBundleNotFound)?;
43
44 let info_plist_path = app_bundle_path.join("Info.plist");
45 let info_plist = if info_plist_path.exists() {
46 Some(InfoPlist::from_file(&info_plist_path)?)
47 } else {
48 None
49 };
50
51 let context = ArtifactContext {
52 app_bundle_path: &app_bundle_path,
53 info_plist: info_plist.as_ref(),
54 };
55
56 let mut results = Vec::new();
57
58 for rule in &self.rules {
59 let res = rule.evaluate(&context);
60 results.push(EngineResult {
61 rule_id: rule.id(),
62 rule_name: rule.name(),
63 severity: rule.severity(),
64 result: res,
65 });
66 }
67
68 Ok(results)
69 }
70}
71
72impl Default for Engine {
73 fn default() -> Self {
74 Self::new()
75 }
76}