Files
IronStorage/apple/TESTING.md

6.8 KiB

Apple mobile integration audit

This is the source-of-truth coverage and release-test checklist for the iPhone and Apple Watch milestone. Automated evidence is required on every change; a manual result is evidence only when the named device or simulator flow was actually exercised.

Coverage matrix

Area Implemented boundary Automated evidence Manual release evidence
Home tab, local history, and optional remote activity UIKit renders Rust MobileHomePage and typed Commit/Fetch/Pull/Push actions mobile_home unit tests, git_embedded, and crates/apple bridge tests Verify a clean local store first, then attach a disposable HTTPS remote and exercise refresh and all four actions, including expired application-token recovery
Passwords tab, navigation, view, and edit Rust supplies typed paths, fields, drafts, revisions, and mutations; UIKit presents them mobile_passwords, entry_documents, mobile_mutation, and mobile_authentication tests Open nested entries, edit/save/cancel, and confirm stale-edit recovery
Swipe move/copy/delete Rust plans destinations, collisions, dirty-editor handling, and commits; UIKit also exposes accessibility actions plans_destinations_collisions_hidden_paths_and_stale_revisions and authentication serialization tests Exercise swipe and VoiceOver alternatives; confirm destructive prompts
TOTP tab and sharing Rust discovers, caches, parses, selects, and generates OTP data mobile_totp, otp, and mobile_watch integration tests Discover entries, read a code, change Watch selection, and verify countdown
Preferences and biometric unlock Rust owns preference/authentication state; LocalAuthentication and Keychain remain isolated Apple adapters authentication_leases, secret_store, and mobile authentication tests Enroll once, then test match, cancel, rejection, and changed enrollment using the documented sequence below
GPG key QR transfer Rust frames, validates, reconstructs, authenticates, and atomically stores keys; UIKit only scans/displays frames mobile_key_transfer unit tests and crypto_compatibility Test public/private transfer, interruption, duplicates, and capture shielding
Watch synchronization Rust owns selected snapshots, pairing identity, revisions, replay rejection, receipts, and revocation replacement_snapshots_reject_replays_conflicts_and_pairing_changes On a paired device, verify background delivery, replacement, replay rejection, revoke, and pairing change
Watch display Rust owns OTP calculation, timing, and ready/empty/syncing/stale/locked/error presentation; SwiftUI renders it watch_runtime_generates_view_ready_totp_and_clears_secrets_when_locked plus ARM64 Watch target build Test offline and stale-snapshot behavior, wrist-down privacy, VoiceOver, Dynamic Type, and supported Watch sizes
Lifecycle and disclosure controls Rust drops protected state; UIKit/SwiftUI clear views, time-limit pasteboard values, and shield private QR/captured content authentication, presentation, TOTP, and Watch lifecycle tests; source audit in apple_mobile_audit Background/foreground, lock, screenshot/capture, pasteboard expiry, and protected-data loss
iPhone layouts and input Native UIKit navigation, tables, alerts, refresh controls, semantic text styles, and hardware-keyboard behavior iPhone simulator compile for the supported target Exercise supported iPhone sizes, largest Dynamic Type, VoiceOver, contrast, and hardware keyboard

The following are intentionally outside this milestone and must not be stubbed into the Apple apps: full CLI/TUI parity, command mode or command palette, SSH Git, non-TOTP Watch features, and production AutoFill behavior.

Security boundary audit

  • crates/storage owns repository access, parsing, Git, OTP, authentication, snapshot transfer, conflict handling, and secret policy.
  • The Apple Rust crates are mechanical UniFFI projections. Swift may collect input and call those APIs; it does not open a password-store repository, calculate OTP, parse snapshots, or launch processes.
  • Git URLs are rejected unless they use HTTPS before transport work. The Watch stores only the selected opaque snapshot in a passcode-protected, device-only Keychain item.
  • Apple production sources contain no logging calls. Secret values use typed redaction/zeroization in Rust; pasteboard values are removed after their Rust deadline; private QR and authenticated content are hidden during capture or lifecycle loss.
  • The iPhone and AutoFill privacy manifests declare in-container file metadata access (C617.1) and elapsed-time/timer use (35F9.1). The Watch manifest declares no required-reason API because its minimal Rust core does not open files or use a monotonic timer. No target declares tracking or developer data collection.
  • Face ID and camera access have purpose strings in project.yml. No custom entitlement is currently required: default signing supplies each target's application identifier and Keychain group, WatchConnectivity needs no added capability, and no App Group is used.

cargo test -p ironstorage --test apple_mobile_audit enforces the source and privacy-manifest parts of this review so those boundaries cannot silently regress.

Required automated gates

From the repository root:

cargo fmt --all -- --check
RUSTFLAGS="-D warnings" cargo check --workspace --all-targets
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

For Apple changes, regenerate the project and compile the exact affected iPhone and ARM64 Watch simulator targets. Confirm each built app bundle contains its own PrivacyInfo.xcprivacy.

Manual biometric sequence

Keep the existing booted simulator, app container, bundle identifier, and Face ID enrollment. For first setup only, choose Features > Face ID > Enrolled, enable Biometric Unlock in IronStorage, unlock one entry, and enter the GPG passphrase once. Do not toggle enrollment again during normal validation.

For each normal check, tap the entry's Unlock control first and then choose Features > Face ID > Matching Face. Verify cancellation and rejection without changing enrollment. A changed-enrollment check is destructive because biometryCurrentSet invalidates the protected Keychain item; run it only when the tester is ready to enter the passphrase again.

Manual evidence still required

Record the device model/OS, build commit, and pass/fail result for each manual row above. Simulator validation is required during implementation. The final distribution issue remains open until the approved App Store build is installed and verified on the paired physical iPhone and Apple Watch. Never overwrite that installation with a development-signed build, and do not describe a simulator build or an opened Xcode project as physical-device validation.