use proxywarden_lib::command_dto::CommandError; use proxywarden_lib::component_inventory::{ classify_component_candidates, BinaryIdentityEvidence, CandidateRole, ComponentCandidateProbe, InventoryAction, MarkerEvidence, ServiceEvidence, OWNERSHIP_MISMATCH, }; use proxywarden_lib::models::ComponentId; use proxywarden_lib::proxifyre_runtime::run_proxifyre_lifecycle_entrypoint; use proxywarden_lib::singbox_runtime::{ run_singbox_config_check_entrypoint, run_singbox_lifecycle_entrypoint, }; use std::cell::Cell; use std::path::PathBuf; #[test] fn foreign_component_blocks_real_proxifyre_lifecycle_runners_before_call() { let inventory = foreign_inventory(); for action in [ InventoryAction::Install, InventoryAction::Apply, InventoryAction::CheckBinary, InventoryAction::Start, InventoryAction::Stop, InventoryAction::ConfigureFirewall, InventoryAction::Update, InventoryAction::Uninstall, ] { let calls = Cell::new(0_u32); let result = run_proxifyre_lifecycle_entrypoint(&inventory, action, |_| { calls.set(calls.get() + 1); Ok::<_, CommandError>(()) }); assert_eq!(calls.get(), 0, "runner was called for {action:?}"); assert_eq!(result.unwrap_err().code, OWNERSHIP_MISMATCH); } } #[test] fn incomplete_component_blocks_real_singbox_process_service_and_delete_runners() { let inventory = incomplete_inventory(); for action in [ InventoryAction::Install, InventoryAction::Apply, InventoryAction::CheckBinary, InventoryAction::Start, InventoryAction::Stop, InventoryAction::Uninstall, ] { let calls = Cell::new(0_u32); let result = run_singbox_lifecycle_entrypoint(&inventory, action, |_| { calls.set(calls.get() + 1); Ok::<_, CommandError>(()) }); assert_eq!(calls.get(), 0, "runner was called for {action:?}"); assert!(result.is_err()); } let process_calls = Cell::new(0_u32); let result = run_singbox_config_check_entrypoint(&inventory, |_| { process_calls.set(process_calls.get() + 1); Ok::<_, CommandError>(()) }); assert!(result.is_err()); assert_eq!(process_calls.get(), 0, "sing-box checker was called"); } #[test] fn missing_component_allows_install_runner_only() { let inventory = classify_component_candidates(ComponentId::Singbox, Vec::new()); let calls = Cell::new(0_u32); run_singbox_lifecycle_entrypoint(&inventory, InventoryAction::Install, |candidate| { assert!(candidate.is_none()); calls.set(calls.get() + 1); Ok::<_, CommandError>(()) }) .expect("missing component should permit explicit install"); assert_eq!(calls.get(), 1); } fn foreign_inventory() -> proxywarden_lib::component_inventory::ComponentInventory { let root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\ProxiFyre"); classify_component_candidates( ComponentId::Proxyfier, vec![ComponentCandidateProbe { component_id: ComponentId::Proxyfier, role: CandidateRole::Current, root: root.clone(), root_exists: true, has_reparse_point: false, executable_path: Some(root.join("ProxiFyre.exe")), missing_files: Vec::new(), marker: MarkerEvidence::Valid, marker_required: true, binary_identity: BinaryIdentityEvidence::KnownPackage, binary_version: Some("2.4.0.0".to_string()), service: Some(ServiceEvidence { name: "ProxiFyreService".to_string(), status: "running".to_string(), path_name: Some(r#""C:\Foreign\ProxiFyre.exe" --service"#.to_string()), executable_path: Some(PathBuf::from(r"C:\Foreign\ProxiFyre.exe")), path_matches_candidate: false, binary_version: None, }), service_required: true, legacy_identity_complete: false, }], ) } fn incomplete_inventory() -> proxywarden_lib::component_inventory::ComponentInventory { let root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\sing-box"); classify_component_candidates( ComponentId::Singbox, vec![ComponentCandidateProbe { component_id: ComponentId::Singbox, role: CandidateRole::Current, root: root.clone(), root_exists: true, has_reparse_point: false, executable_path: Some(root.join("sing-box.exe")), missing_files: vec![root.join("ProxyWardenSingBox.exe")], marker: MarkerEvidence::NotRequired, marker_required: false, binary_identity: BinaryIdentityEvidence::Unknown, binary_version: None, service: None, service_required: true, legacy_identity_complete: false, }], ) }