Files
IronStorage/apple/TESTING.md
Chili Palmer a3da9fda69
Some checks failed
Dependency security audit / rustsec (push) Has been cancelled
Complete SSH transport release audit (#118)
2026-08-25 22:07:47 +02:00

96 lines
7.2 KiB
Markdown

# 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 UI, non-TOTP Watch features, and production AutoFill behavior. The Apple
Rust bridge explicitly compiles storage without the optional `ssh` feature;
typed SSH configuration therefore fails as unsupported before any connection
until a future Apple target opts in.
The cross-target and artifact evidence for this exclusion is maintained in
`../docs/ssh-transport-audit.md`.
## 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.
- The shipped Apple bridge rejects non-HTTPS Git transport before connection;
the shared typed storage model may still parse SSH configuration. 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:
```sh
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.