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