#![forbid(unsafe_code)] use std::{fs, path::PathBuf}; fn workspace_file(path: &str) -> String { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .parent() .and_then(std::path::Path::parent) .expect("workspace root") .to_path_buf(); fs::read_to_string(root.join(path)).unwrap_or_else(|error| panic!("read {path}: {error}")) } #[test] fn apple_sources_preserve_the_mobile_security_boundary() { let app = workspace_file("apple/Sources/App/IronStorageApp.swift"); let watch = workspace_file("apple/Sources/Watch/IronStorageWatchApp.swift"); let autofill = workspace_file("apple/Sources/AutoFill/CredentialProviderViewController.swift"); let bridges = format!( "{}\n{}", workspace_file("crates/apple/src/lib.rs"), workspace_file("crates/watch-apple/src/lib.rs") ); for (name, source) in [ ("iPhone", app.as_str()), ("Watch", watch.as_str()), ("AutoFill", autofill.as_str()), ("Apple Rust bridges", bridges.as_str()), ] { for forbidden in [ "Process(", "NSTask", concat!("Command", "::new("), "posix_spawn(", ] { assert!(!source.contains(forbidden), "{name} launches {forbidden}"); } } for (name, source) in [ ("iPhone", app.as_str()), ("Watch", watch.as_str()), ("AutoFill", autofill.as_str()), ] { for forbidden in ["print(", "NSLog(", "Logger(", "os_log("] { assert!( !source.contains(forbidden), "{name} logs through {forbidden}" ); } } assert!(!app.contains("FileManager.default")); for forbidden in ["otpauth://", "HMAC", "SHA1", "SHA256", "SHA512", ".gpg-id"] { assert!( !watch.contains(forbidden), "Watch implements storage or OTP domain behavior: {forbidden}" ); } assert!(watch.contains("core.presentationAt")); assert!(watch.contains("SecItemCopyMatching")); assert!(app.contains("session.sendMessage(payload")); assert!(app.contains("session.transferUserInfo(payload)")); assert!(app.contains("session.outstandingUserInfoTransfers")); assert!( app.split_once("@main") .expect("iPhone app delegate") .0 .contains("UIApplication.didBecomeActiveNotification") ); assert!(watch.contains("didReceiveMessage message")); assert!(watch.contains("didReceiveUserInfo userInfo")); assert!(watch.contains("session.outstandingUserInfoTransfers")); assert!(watch.contains("session.transferUserInfo(acknowledgement)")); assert!( watch .split_once("func sceneBecameActive()") .expect("Watch foreground handler") .1 .split_once("func sceneBecameInactive()") .expect("Watch inactive handler") .0 .contains("receivedApplicationContext") ); assert!(watch.contains("applyAuthoritativeSnapshot")); } #[test] fn iphone_entry_editor_keeps_add_action_accessible_while_typing() { let app = workspace_file("apple/Sources/App/IronStorageApp.swift"); assert!(app.contains("navigationItem.rightBarButtonItems = [save, add]")); assert!(app.contains("tableView.keyboardDismissMode = .interactive")); assert!(app.contains("field.returnKeyType = .done")); assert!(app.contains("textField.resignFirstResponder()")); assert!(!app.contains("inputAccessoryView = keyboardToolbar")); } #[test] fn every_apple_bundle_has_an_audited_privacy_manifest() { let project = workspace_file("apple/project.yml"); for path in [ "Resources/App/PrivacyInfo.xcprivacy", "Resources/AutoFill/PrivacyInfo.xcprivacy", "Resources/Watch/PrivacyInfo.xcprivacy", ] { assert!(project.contains(path), "Xcode target omits {path}"); } for path in [ "apple/Resources/App/PrivacyInfo.xcprivacy", "apple/Resources/AutoFill/PrivacyInfo.xcprivacy", "apple/Resources/Watch/PrivacyInfo.xcprivacy", ] { let manifest = workspace_file(path); assert!(manifest.contains("NSPrivacyTracking\n\t")); assert!(manifest.contains("NSPrivacyCollectedDataTypes\n\t")); } let app = workspace_file("apple/Resources/App/PrivacyInfo.xcprivacy"); assert!(app.contains("NSPrivacyAccessedAPICategoryFileTimestamp")); assert!(app.contains("C617.1")); assert!(app.contains("NSPrivacyAccessedAPICategorySystemBootTime")); assert!(app.contains("35F9.1")); assert!(project.contains("NSFaceIDUsageDescription")); assert!(project.contains("NSCameraUsageDescription")); }