6.7 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, remote activity, pull-to-refresh | UIKit renders Rust MobileHomePage and typed Commit/Fetch/Pull/Push actions |
mobile_home unit tests, git_embedded, and crates/apple bridge tests |
Exercise refresh and all four actions against a disposable HTTPS remote, 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/storageowns 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. Alternative-distribution entitlements belong to the final distribution issue.
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. Physical paired-Watch deployment and WatchConnectivity testing are
currently skipped by project direction, so issues closed without that evidence
must carry the untested label. Do not describe a simulator build or an opened
Xcode project as device validation.