Files
IronStorage/docs/android/parity.md
T
hugo b54636b7bc
Android ARM verification / rust (push) Failing after 50m14s
Android ARM verification / android (push) Failing after 8s
Dependency security audit / rustsec (push) Failing after 23s
Complete Android parity and security audit (#111)
2026-10-15 13:40:50 +02:00

95 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Android parity and issue ownership
Contract for [#88](https://git.rfc1437.de/hugo/IronStorage/issues/88), reviewed
2026-10-15 against apple/Sources/App/IronStorageApp.swift,
apple/Sources/AutoFill/CredentialProviderViewController.swift, crates/apple/src/lib.rs,
and crates/storage/src/mobile*.rs. See [architecture.md](architecture.md) for
support, dependency, security and update policy.
**Status:** implementation issues #89–#110 are delivered. The #111 audit
maps each capability to current Android components and executable checks below.
[audit.md](audit.md) records current results, dependency decisions and explicit
runtime limits. Test names identify coverage; opt-in tests need separate runtime
evidence and are not counted as exercised by a normal suite.
Every implementation issue linked here belongs to milestone 23.
## Current iPhone and shared-mobile capabilities
| Existing capability / source | Owning Rust API/module | Android presentation / approved API | Implementation and required evidence |
| --- | --- | --- | --- |
| Five destinations: Home, Passwords, Search, TOTP, Preferences; loading/empty/ready/locked/error fixtures (AppContext, ShellViewController) | mobile::MobileShell, MobileTab, MobileShellState; config selected tab | `ShellScreen / ShellViewModel / MainActivity` | #89/#91/#102; shell fixtures, startup, back/navigation and recreation; **Checks:** ShellScreenTest, AdaptiveShellTest, Tier2WindowTest, HingeWindowTest |
| Local-first setup, generated/imported key, passphrase confirmation, staged QR import (SetupChoiceViewController, LocalSetupViewController) | mobile_onboarding::MobileOnboardingOperation, crypto; mobile_key_transfer import | `OnboardingScreen / NativeOnboardingRepository` | #95/#106; real local init, key export/import, canceled/failed setup rollback; **Checks:** OnboardingScreenTest; Rust mobile_onboarding::android::tests |
| Optional HTTPS clone, server/account/token, repository/branch discovery; attach remote to local store (OnboardingViewController) | mobile_onboarding::{MobileOnboardingRequest, MobileOnboardingOperation}; git/config/secret_store | `OnboardingScreen and SettingsScreen HTTPS actions` | #95; TLS/auth/branch/cancel/offline errors; repository remote authority; **Checks:** OnboardingScreenTest; Rust onboarding and git TLS/auth/remote-authority tests |
| Home history, ahead/behind, local/remote change status, commit activity (ShellViewController, MobileCommitActivityViewController) | mobile_home::MobileHomePage/Operation and git | `HomeScreen / NativeHomeRepository` | #97; summaries and stale/error state, Git identity, author/history; **Checks:** HomeScreenTest; Rust mobile_home and tests/git_embedded.rs |
| Commit, Fetch, Pull, Push and pull-then-push Sync | mobile_home::MobileHomeOperation; git sync/merge/conflicts/signing | `HomeScreen typed actions and progress` | #97; pull failure prevents push, conflict/data-loss cases and signing; **Checks:** HomeScreenTest; Rust mobile_home::android_tests and Git conflict/cancellation tests |
| Directory hierarchy, breadcrumbs, folder and entry rows (PasswordDirectoryViewController) | mobile_passwords::MobilePasswordPage/Row/RowKind; repository/read | `PasswordScreen / NativePasswordRepository` | #96; deep tree, empty/error, keyboard and size changes; **Checks:** PasswordScreenTest, NativeEntryViewerTest, NativeTreeMutationTest |
| Password-store name search (PasswordSearchViewController) | mobile_passwords::MobilePasswordPage::search | `SearchScreen / NativeSearchRepository` | #101; large-store responsiveness and canceled/stale results; **Checks:** SearchScreenTest; Rust mobile_passwords and large-store native instrumentation |
| Unlock entry, explicit user activity, timeout, manual/background lock; shared entry/TOTP/editor lease (LockedPasswordViewController, AppContext) | mobile_authentication::MobileAuthentication; authentication generation/leases | `AuthenticationControls / AndroidKeystoreAdapter / MainActivity lifecycle` | #93/#98/#100; wrong passphrase, cancel, expiry, generation race, changed enrollment and process death; **Checks:** AuthenticationScreenTest, opt-in AuthenticationLeaseTest, AndroidKeystoreTest; tests/authentication_leases.rs |
| Structured fields/sections, masked secrets, explicit reveal/select/copy; OTP field diagnostics (MobileEntryFieldCell) | mobile_entry::MobileEntryPage/Field; mobile_authentication::{entry_page,reveal_entry_field,copy_entry_field} | `EntryViewer / NativePasswordRepository` | #99/#100; no pre-unlock values, relock clears all views, copy expiry/ownership; **Checks:** EntryViewerTest, NativeEntryViewerTest, NativeOtpPresentationTest; tests/entry_documents.rs |
| Create entry/folder, structured multiline editing, add/remove/reorder fields, dirty discard confirmation (MobileEntryEditorViewController) | mobile_entry::MobileEntryDraft; mobile_authentication editor session/create/save/discard; write | `EntryEditorScreen / NativeEditorRepository` | #103; actual encrypted saves, conflict tokens, interrupted saves and dirty navigation; **Checks:** EntryEditorScreenTest, NativeEntryViewerTest; Rust editor conflict/checkpoint/atomic-save tests |
| Password length/generation and replacement | generate; mobile_entry::MobileEntryDraft::generate_password | `EntryEditorScreen generator controls` | #103; Rust validation and unbiased generated value; no Kotlin generator; **Checks:** EntryEditorScreenTest; tests/password_generation.rs |
| OTP URI input, camera/image import, review before Save (OtpImportViewController; TOTP Add action) | mobile_entry::MobileEntryDraft::add_otp_image; document/otp/presentation | `EntryEditorScreen / QrCameraPane / AndroidQrCamera` | #103/#106/#107; URI/image/scan parity, invalid/oversized input, cancel; no payload parsing in Kotlin; **Checks:** EntryEditorScreenTest, AndroidQrCameraTest; Rust qr and tests/otp.rs |
| Move/copy/delete entries and folders, destination browse, overwrite and dirty-editor handling (PasswordMutationCoordinator) | mobile_mutation::MobileMutationService/Plan/Request; mutation | `MutationDialog / NativePasswordRepository` | #108; revisions, destination conflicts, recipient reencryption and rollback; **Checks:** MutationWorkflowTest, NativeTreeMutationTest; tests/tree_mutations.rs and recipient_policy.rs |
| TOTP discovery catalog, incremental progress, warm cache, refresh, cancel/resume, cached search (TotpListViewController) | mobile_totp discovery/catalog/operation; mobile_authentication cached/search APIs | `TotpScreen / NativeTotpRepository` | #90/#110; [discovery behavior and evidence](totp-discovery.md), cold/warm/change/add/remove/corrupt/wrong-store/concurrent-change tests; **Checks:** TotpDiscoveryFixtureTest, NativeTotpDiscoveryTest, NativeTotpPerformanceTest; tests/mobile_totp.rs |
| TOTP rows, large detail code, countdown/expiry, copying (TotpDetailViewController, TotpCodeView) | mobile_totp::MobileOtpCodePresentation; otp; mobile_authentication::{presented_otp_code,copy_presented_otp_code,advance_presented_hotp} | `TotpScreen / OtpCodeView / EntryViewer` | #107/#100; [OTP behavior and evidence](otp.md), RFC vectors, boundary countdown, stale callback/relock and clipboard; **Checks:** TotpScreenTest, NativeOtpPresentationTest; Rust OTP boundary/relock/HOTP tests |
| Repository/server identity, local-only/add-remote Settings, token replace/remove (PreferencesViewController, TokenUpdateViewController) | mobile_authentication::MobilePreferences; mobile_onboarding::replace_configured_application_token; config/secret_store | `SettingsScreen / NativeSettingsRepository` | #104/#95; no token display; protected replacement/removal and offline operation; **Checks:** SettingsScreenTest; Rust preference/token and Android onboarding tests |
| Key identity/fingerprint, GPG recovery import and public/private QR export (KeyImportScannerViewController, KeyExportListViewController, KeyQrExportViewController) | mobile_key_transfer::{MobileKeyTransferService,MobileKeyTransferImport}; crypto/presentation | `SettingsScreen key transfer / QrCameraPane / AndroidQrCamera` | #106/#104; multi-frame order/duplicates/interruption, bounded frames, private export authorization and camera denial; **Checks:** SettingsScreenTest, AndroidQrCameraTest; Rust mobile_key_transfer frame/order/cancel/authorization tests |
| Inactivity timeout, biometric enable/disable, Lock Now, appearance and Git commit name/email | mobile_authentication preference setters, git_identity; config | `SettingsScreen / AuthenticationControls / ApplicationTheme` | #98/#104; persistent settings, validation, Keystore enrollment/recovery and lease revocation; **Checks:** SettingsScreenTest, NativeEntryViewerTest, opt-in AuthenticationLeaseTest; Rust authenticated preference tests |
| AutoFill extension boundary (current iPhone controller is empty), shared identity/access domain and Android provider requirement | mobile_credentials; mobile_authentication provider request/select/fill/save APIs | `IronCredentialProviderService / IronAutofillService / CredentialSelectionActivity` | #109; typed caller/site identity, non-secret candidates, explicit selection/auth, forged/stale requests, permissions and cross-process lifetime; **Checks:** ProviderIntentSecurityTest, CredentialSelectionScreenTest, NativeCredentialProviderTest; provider-client OS journeys |
| Camera permissions, private paths, secret-store mechanics, clipboard, scene/process events, screen privacy | Rust repository/config/secret_store/authentication/presentation; platform callbacks contain facts only | `AndroidSecretClipboard / ProtectedInput / ProtectedPresentation / MainActivity` | #90/#93/#98/#100; backup inspection, sandbox paths, pressure/update, screen/clipboard/lifecycle tests; **Checks:** PresentationSecurityTest, BackupPolicyTest, AndroidQrCameraTest; Rust secret-store and editor recovery tests |
| Accessible labels/actions, large text, keyboard, responsive layout and localization | Typed Rust state/actions; UI accessibility is Kotlin | `Compose semantics/resources / HingeSafeLayout / HingeSafeAlertDialog` | #105; measured keyboard/TalkBack/large-font/multi-window/RTL/rotation coverage; **Checks:** Tier2WindowTest, HingeWindowTest; hardening.md records manual accessibility and exact performance evidence |
| Watch pairing/install state in Settings; TOTP Watch selection, snapshots, receipts, transfer and watchOS detail | mobile_watch; shared bridge's explicit `watch` feature enabled only by crates/apple | Absent from Android records and UI (#91) | Deliberate Watch-only exclusion; no unsupported placeholder controls or Wear implementation |
Name search matches current mobile behavior; CLI/TUI decrypted grep is not an
iPhone parity claim. Android has no separate filesystem-based search. The
shared core's recipient/signing rules, pass/pass-otp format, HOTP counter safety,
Git failure semantics and secret-redaction requirements remain binding wherever
an Android workflow invokes them; platform presentation may not replace them.
Current iPhone camera adapters pass OS-decoded QR bytes. Android #106 supplies bounded Y-plane/stride/orientation facts through the
shared native contract; storage decodes and reassembles the transfer. See
[key-transfer.md](key-transfer.md) for interruption/security behavior and evidence.
The external-credential matching/grant API is implemented in `mobile_credentials`
and `mobile_authentication`; both Android providers delegate to it.
## Complete milestone issue-to-layer map
Links identify the live issues by number and a concise description. Ordering follows the user's label
priority, then numeric order; do not substitute a dependency from another
milestone. This list gives ownership, not permission to skip acceptance criteria.
| Issue | Owning layer | Approved implementation/API and completion gate |
| --- | --- | --- |
| [#88 Architecture/support/dependency policy](https://git.rfc1437.de/hugo/IronStorage/issues/88) | Repository architecture decision | This ADR and parity/owner matrix; review against current sources |
| [#89 Gradle scaffold/module boundaries](https://git.rfc1437.de/hugo/IronStorage/issues/89) | Android build/app/core/platform/bridge modules | Kotlin DSL/catalog/wrapper, Compose/Hilt/KSP, source/dependency gates, all shell fixtures; clean debug APK |
| [#90 Private paths/config/cache/backup](https://git.rfc1437.de/hugo/IronStorage/issues/90) | crates/storage plus Android path adapter | Context roots/capabilities, atomic layout/migrations, backup rules; Rust and sandbox/update tests |
| [#91 Platform-neutral mobile contract](https://git.rfc1437.de/hugo/IronStorage/issues/91) | crates/storage and shared UniFFI bridge | Typed semantic actions/icons, opt-in Watch data, platform callbacks, shared Swift/Kotlin inventory tests |
| [#92 Native Rust/UniFFI packaging](https://git.rfc1437.de/hugo/IronStorage/issues/92) | Shared/Android Rust bridge and Gradle rust-bridge | cargo-ndk, generated immutable Kotlin/JNA Android, both ARM ABIs, checksums/16 KB/loading/debug symbols |
| [#93 Keystore adapter](https://git.rfc1437.de/hugo/IronStorage/issues/93) | Delivered: Rust sealed-record orchestration and Android OS adapter | [Keystore policy and recovery](keystore.md); native AES-GCM/CryptoObject and Rust lifecycle tests |
| [#94 CI/static analysis/reproducibility](https://git.rfc1437.de/hugo/IronStorage/issues/94) | Build/CI/test infrastructure | Cargo gates, Gradle build/Lint/ktlint, JVM/Compose/instrumented tests, verification/locks/SBOM/ABI checks |
| [#95 Local-first/HTTPS onboarding](https://git.rfc1437.de/hugo/IronStorage/issues/95) | storage mobile_onboarding plus Compose features | Existing Rust initialization/discovery/clone/credentials; no Kotlin transport |
| [#96 Hierarchical navigation](https://git.rfc1437.de/hugo/IronStorage/issues/96) | storage mobile_passwords plus Compose features | Material 3 Adaptive list/detail, typed rows/stable IDs |
| [#97 Home/Git](https://git.rfc1437.de/hugo/IronStorage/issues/97) | storage mobile_home/git plus Compose features | Rust actions/history/progress/conflicts; Compose Home and activity |
| [#98 Biometric authentication lease](https://git.rfc1437.de/hugo/IronStorage/issues/98) | storage authentication/mobile_authentication plus platform adapter | AndroidX BiometricPrompt/CryptoObject, KeyguardManager; Rust generations/policy |
| [#99 Structured viewer](https://git.rfc1437.de/hugo/IronStorage/issues/99) | storage mobile_entry/mobile_authentication plus Compose features | Typed fields/sections/reveal/copy, Rust OTP and diagnostics |
| [#100 Privacy/lifecycle/plaintext](https://git.rfc1437.de/hugo/IronStorage/issues/100) | storage lease/presentation plus platform/app | Lifecycle, FLAG_SECURE, ClipboardManager, no saved plaintext/logs, race tests |
| [#101 Name search](https://git.rfc1437.de/hugo/IronStorage/issues/101) | storage mobile_passwords plus Compose features | Rust cached/name search, Flow cancellation/latest query wins |
| [#102 Adaptive shell](https://git.rfc1437.de/hugo/IronStorage/issues/102) | storage mobile shell contract plus Android app/features | Navigation 3/Material 3 Adaptive, StateFlow, restoration without secrets |
| [#103 Entry/folder/editor/generation](https://git.rfc1437.de/hugo/IronStorage/issues/103) | storage mobile_entry/write/generate plus Compose features | Rust editor sessions/drafts/atomic saves, structured multiline controls and OTP import |
| [#104 Settings/recovery](https://git.rfc1437.de/hugo/IronStorage/issues/104) | storage config/mobile_authentication/key transfer plus Compose features | Shared setters, token/key recovery, Biometric/appearance/identity controls without Watch |
| [#105 Accessibility/adaptive/localization/performance](https://git.rfc1437.de/hugo/IronStorage/issues/105) | Android features/resources plus storage cancellation | Compose semantics/TalkBack/resources, measured Macrobenchmark/profiles if justified |
| [#106 CameraX GPG QR import/export](https://git.rfc1437.de/hugo/IronStorage/issues/106) | storage QR/key transfer plus platform camera/Compose | CameraX frames, Rust decode/envelope/matrices, permission and bounded payload checks |
| [#107 TOTP list/detail](https://git.rfc1437.de/hugo/IronStorage/issues/107) | storage mobile_totp/otp plus Compose features | Rust codes/timing, large display/copy/refresh, OTP creation/import navigation |
| [#108 Move/copy/delete](https://git.rfc1437.de/hugo/IronStorage/issues/108) | storage mobile_mutation/mutation plus Compose features | [Mutation behavior and evidence](mutations.md); Rust plans/revisions/overwrite/reencryption, destination and confirmation UI |
| [#109 Credential Manager/Autofill](https://git.rfc1437.de/hugo/IronStorage/issues/109) | storage identity/permission/credential contract plus OS services | AndroidX provider and framework AutofillService, explicit selection/lease before secrets |
| [#110 TOTP catalog/discovery/search](https://git.rfc1437.de/hugo/IronStorage/issues/110) | storage mobile_totp plus Compose features | Existing hash/path/is_totp catalog, Rust progress/checkpoints/filter, no Watch |
| [#111 Parity/security/reliability audit](https://git.rfc1437.de/hugo/IronStorage/issues/111) | All above plus independent acceptance review | Completed matrix evidence, Rust/Android release gates and emulator threat tests |
| [#112 Google Play distribution](https://git.rfc1437.de/hugo/IronStorage/issues/112) | Release tooling/listing and production app | Protected signing/Play AAB, audited manifest/licenses, emulator install and update-preservation tests |
#87 is the closed umbrella issue, not an open implementation candidate. Verify
live issues after each closure; newly created bug/critical issues may change the
order. #91 and #90 currently name later packaging/contract dependencies; their
implementations may establish the necessary narrow Rust APIs before consuming
full Android packaging, but they must meet all stated acceptance tests before
closure. Do not close a partly integrated issue just because its unit tests pass.