Define native Android architecture and parity contract (#88)
Dependency security audit / rustsec (push) Failing after 26s
Dependency security audit / rustsec (push) Failing after 26s
This commit is contained in:
1 parent
71a4f289cf
commit
30d9119302
4 files changed
+316
No files matched your search
@@ -0,0 +1,211 @@
|
||||
# Android architecture decision
|
||||
|
||||
Accepted implementation contract for [#88](https://git.rfc1437.de/hugo/IronStorage/issues/88)
|
||||
in milestone 23, **06 - Implement an Android version of the software**.
|
||||
Reviewed against the checkout's iPhone app, AutoFill extension, and shared Rust
|
||||
mobile APIs on 2026-10-08. The milestone goal is full native Android feature
|
||||
parity. This decision records ownership and release requirements; it does not
|
||||
claim that the Android implementation or device audit already exists.
|
||||
|
||||
## Language and presentation
|
||||
|
||||
Use Kotlin, Gradle Kotlin DSL, one activity, Jetpack Compose, Material 3 and
|
||||
Material 3 Adaptive. Use Navigation 3: its [stable release is 1.2.0](https://developer.android.com/jetpack/androidx/releases/navigation3).
|
||||
Screen ViewModels expose immutable StateFlow state and accept typed events.
|
||||
Compose observes with collectAsStateWithLifecycle. Hilt supplies dependencies;
|
||||
KSP runs its processors. Blocking UniFFI calls run on a bounded background
|
||||
coroutine dispatcher. Cancellation cancels the Rust operation as well as the
|
||||
coroutine; a late result must not restore a revoked lease or stale screen.
|
||||
|
||||
Rust owns repository layout, config, keys, OpenPGP, Git, conflicts, documents,
|
||||
generation, OTP, QR payloads, identities, external access permissions and
|
||||
secure-secret orchestration. Kotlin collects input, renders Rust state, and
|
||||
adapts OS mechanics. No app component launches a subprocess. No Kotlin feature
|
||||
reads repository files, parses entries/URIs or error labels, generates passwords
|
||||
or codes, or independently decides credential matches or authentication policy.
|
||||
|
||||
Use typed semantic icons/actions, stable IDs, generation/revision tokens,
|
||||
view-ready records and typed errors. #91 removes SF Symbol and Watch assumptions
|
||||
from shared phone contracts. Keep Swift compatibility through mechanical
|
||||
adapters. #92 generates Kotlin and Swift from one shared UniFFI surface rather
|
||||
than copying crates/apple conversions. A thin Android bridge may adapt platform
|
||||
callbacks; it must contain no password-store decisions or handwritten unsafe
|
||||
Rust. Generated/dependency FFI stays isolated from project-authored safe Rust.
|
||||
|
||||
## Modules and allowed dependencies
|
||||
|
||||
| Module | Responsibility | Allowed project dependencies |
|
||||
| --- | --- | --- |
|
||||
| android/app | Activity, composition root, navigation, manifest and service registration | features, core, platform |
|
||||
| android/features | Related Compose workflows, screen ViewModels, accessibility | core only |
|
||||
| android/core | Android-facing facade, immutable presentation contracts, coroutine scheduling, bridge mapping | rust-bridge |
|
||||
| android/platform | Keystore, BiometricPrompt, clipboard, camera, paths and OS request translation | core contracts |
|
||||
| android/rust-bridge | Generated UniFFI Kotlin and ABI native packaging | shared Rust bridge via build tasks |
|
||||
| Shared Rust bridge | Mechanical records, lifetime/callback/error conversion | crates/storage |
|
||||
| crates/storage | All domain behavior and trust-boundary validation | audited Rust dependencies |
|
||||
|
||||
Start with these five Gradle modules; split feature groups only when useful.
|
||||
Platform implementations are injected at app composition. Feature code cannot
|
||||
import generated UniFFI/JNA types or depend directly on platform/bridge modules.
|
||||
OS services delegate to core; exported service input is untrusted. Only Rust
|
||||
holds repository capabilities. Gradle dependency checks, source-boundary checks,
|
||||
and release manifest inspection are gates in #89/#94/#111, not substitutes for
|
||||
review. Generated bindings and native/build outputs are not checked in.
|
||||
|
||||
## Support and build policy
|
||||
|
||||
Production package, namespace and application ID: **de.rfc1437.ironstorage**.
|
||||
Updates retain this ID and signing lineage. Tests use derived IDs; a development
|
||||
variant may not masquerade as the production signed installation.
|
||||
|
||||
Minimum SDK: **26** (Android 8, including Autofill). Compile/target SDK: **37**
|
||||
(Android 17) at this decision, following the [SDK instructions](https://developer.android.com/about/versions/17/setup-sdk).
|
||||
Recheck stable SDK and [Play requirements](https://support.google.com/googleplay/android-developer/answer/11926878)
|
||||
at implementation and release. Never select preview APIs to satisfy a release
|
||||
policy. The installed android-37.0 SDK reports an empty codename and
|
||||
PreviewSdkInt=0 (revision 2); verify the same package metadata in CI before
|
||||
pinning the build, rather than relying on preview wording in older instructions.
|
||||
|
||||
Release ABIs: **arm64-v8a**, **armeabi-v7a**, **x86_64**, corresponding to
|
||||
**aarch64-linux-android**, **armv7-linux-androideabi**,
|
||||
**x86_64-linux-android**. An ABI may be removed only with a dependency audit and
|
||||
an amendment to this decision; emulator success alone proves no arm64 hardware
|
||||
coverage. All shipped native dependencies, including JNA, must pass ELF LOAD
|
||||
alignment, APK ZIP alignment and actual 16 KB runtime checks. Do not depend on
|
||||
compatibility mode. [Android's page-size guidance](https://developer.android.com/guide/practices/page-sizes)
|
||||
requires auditing dependencies as well as the app library.
|
||||
|
||||
At #89 pin a mutually supported stable AGP/Gradle/Kotlin/KSP/Hilt set, JDK,
|
||||
SDK build tools and NDK, plus wrapper checksum. The current [AGP 9.4 contract](https://developer.android.com/build/releases/agp-9-4-0-release-notes)
|
||||
requires Gradle 9.6.0 and JDK 17 and supports API 37. This is a candidate build
|
||||
baseline, subject to actual artifact availability and plugin compatibility.
|
||||
No dynamic versions, snapshots or automatic toolchain substitutions. #92 pins
|
||||
cargo-ndk, Rust targets/toolchain and the workspace UniFFI version and builds all
|
||||
ABIs from the locked Cargo graph. Retain separate native symbols and R8 mappings.
|
||||
|
||||
Support phones, tablets, foldables, resizing/multi-window, desktop windowing,
|
||||
portrait/landscape, system/light/dark themes, hardware keyboard, large fonts,
|
||||
TalkBack and process recreation. Preserve non-secret navigation/filter state;
|
||||
never serialize decrypted fields, passphrases, tokens, QR key payloads or a lease
|
||||
into SavedStateHandle, bundles, preferences, crash reports or test artifacts.
|
||||
Rotation/process death must not replay a mutation. In-flight mutations resolve
|
||||
through Rust revision/transaction state before a retry.
|
||||
|
||||
Apple Watch, watchOS and Watch Connectivity are excluded. Android Auto, TV,
|
||||
Wear OS and XR-specific experiences are outside the product; Wear is not a
|
||||
substitute for Watch. Do not show disabled Watch controls on Android.
|
||||
|
||||
## Approved dependencies and review policy
|
||||
|
||||
These are approved purposes, not permission to add every library immediately.
|
||||
#89 pins only scaffold dependencies; later owners add their required artifacts.
|
||||
Exact versions live in one version catalog, Cargo.lock and reviewed toolchain
|
||||
pins. Keep Gradle dependency verification metadata and locks where supported;
|
||||
review checksums independently before accepting a new artifact. For each addition
|
||||
and upgrade, record exact coordinates/version, upstream release/maintenance
|
||||
check, SPDX license and bundled notices, transitives, security advisories and
|
||||
compatibility results. Approval of a library family does not approve every
|
||||
transitive version. #94 builds the resolved SBOM/license gate; #112 bundles
|
||||
attributions and available source obligations.
|
||||
|
||||
| Library/API | Single purpose | License review and maintenance source |
|
||||
| --- | --- | --- |
|
||||
| Kotlin and Compose compiler plugin | Kotlin compilation | Apache-2.0, [JetBrains license](https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt); check matching stable compiler/plugin releases |
|
||||
| Gradle, AGP and Android Lint | Reproducible packaging and Android static checks | Apache-2.0 tool distribution notices; [AGP compatibility/release notes](https://developer.android.com/build/releases/about-agp) |
|
||||
| Compose BOM, Material 3, Adaptive, Activity Compose | Native controls/layout and activity hosting | Apache-2.0, [AndroidX license](https://github.com/androidx/androidx/blob/androidx-main/LICENSE.txt); check each resolved artifact's stable AndroidX release |
|
||||
| Navigation 3 | Typed adaptive navigation/back stack | AndroidX Apache-2.0; stable release source above |
|
||||
| Lifecycle ViewModel/Runtime Compose | Lifecycle-aware screen state collection | AndroidX Apache-2.0; stable AndroidX release notes |
|
||||
| kotlinx.coroutines and coroutines-test | Bounded async calls, Flow and deterministic scheduling tests | Apache-2.0, [upstream](https://github.com/Kotlin/kotlinx.coroutines); check Kotlin compatibility and tagged release |
|
||||
| Hilt/Dagger | Dependency injection | Apache-2.0, [upstream license](https://github.com/google/dagger/blob/master/LICENSE.txt); verify KSP/AGP support |
|
||||
| KSP | Hilt code generation | Apache-2.0, [upstream license](https://github.com/google/ksp/blob/main/LICENSE); verify compiler/AGP support |
|
||||
| UniFFI | Shared typed Swift/Kotlin bridge generation | MPL-2.0, [Mozilla license](https://github.com/mozilla/uniffi-rs/blob/main/LICENSE); pin workspace tool/library together |
|
||||
| JNA Android AAR | UniFFI native loading/calls | Choose Apache-2.0 under [JNA dual license](https://github.com/java-native-access/jna/blob/master/LICENSE); verify Android ABI/16 KB binaries per version |
|
||||
| cargo-ndk and NDK | ABI cross compilation/packaging | MIT OR Apache-2.0 for [cargo-ndk](https://github.com/bbqsrc/cargo-ndk); retain NDK component notices and review stable toolchain |
|
||||
| AndroidX Biometric | OS authentication prompt | AndroidX Apache-2.0; choose stable API supporting CryptoObject and required auth policy |
|
||||
| CameraX Preview/ImageAnalysis | Camera capture and frame delivery | AndroidX Apache-2.0; check stable artifacts and device support; Rust decodes/parses frames |
|
||||
| AndroidX Credentials provider | Android 14+ password-provider integration | AndroidX Apache-2.0; verify provider support and stable artifact API |
|
||||
| AndroidX Test and Compose UI Test | Instrumented/system and Compose behavior checks | AndroidX Apache-2.0; align with Compose BOM and test runner |
|
||||
| JUnit | JVM unit tests | EPL-1.0 for [JUnit 4](https://github.com/junit-team/junit4); test-only, pin maintained 4.13.x patch |
|
||||
| ktlint | Kotlin formatting/static style | MIT, [upstream](https://github.com/pinterest/ktlint); pin CLI/rules together and review Kotlin compatibility |
|
||||
| Macrobenchmark/Baseline Profiles | Measure startup and optimize measured bottlenecks | AndroidX Apache-2.0; add only with reproducible measurements in #105 |
|
||||
| WorkManager | Explicitly approved durable noninteractive work | AndroidX Apache-2.0; add only when an operation survives process loss safely |
|
||||
| Android framework | Keystore, KeyguardManager, AutofillService, clipboard, FLAG_SECURE, private paths, backup rules, connectivity and permissions | OS APIs; no extra bundled crypto/storage implementation; behavior audited on supported APIs/OEMs |
|
||||
|
||||
DataStore is allowed only for presentation-only preferences if necessary.
|
||||
Shared preferences use Rust configuration. Room, Retrofit/OkHttp, JGit,
|
||||
Bouncy Castle/OpenPGP, Kotlin OTP/password/parser libraries, ML Kit payload
|
||||
interpretation and a competing QR format are prohibited. Reuse existing Rust
|
||||
crypto/Git/QR code. Do not schedule interactive unlock, secret display or repository
|
||||
mutations as background WorkManager tasks.
|
||||
|
||||
## Threat model and state lifetime
|
||||
|
||||
Protect the pass repository/key material, passphrases, HTTPS application tokens,
|
||||
OTP secrets/codes, decrypted fields, credential selections and identity grants.
|
||||
Untrusted inputs include remote endpoints/data, repository entries and policies,
|
||||
QR/images, OS provider callers, restored files, and concurrent/stale UI requests.
|
||||
Rust validates transports before any repository mutation or connection and uses
|
||||
repository remotes as authoritative. Android starts HTTPS-only with SSH disabled;
|
||||
SSH endpoints still parse to typed unsupported errors. Adding SSH requires an
|
||||
explicit audited support decision while preserving storage-owned transport policy.
|
||||
|
||||
The sandbox and Keystore protect against ordinary cross-app access and accidental
|
||||
backup, not a fully compromised/rooted device. Debuggable builds, logs, screenshots,
|
||||
recents thumbnails, clipboard history, accessibility, keyboard suggestions and
|
||||
crash telemetry are disclosure paths. #100 uses FLAG_SECURE, redaction, background
|
||||
relock, bounded clipboard ownership/expiry and memory cleanup; never claim complete
|
||||
Kotlin/JVM memory erasure. Clear platform references and revoke Rust generations.
|
||||
|
||||
Keystore holds non-exportable AES-GCM wrapping keys. Only sealed envelopes reach
|
||||
private storage. Rust decides secret type, identity, enrollment/invalidation,
|
||||
authentication policy, lease and recovery. Kotlin translates OS error facts.
|
||||
BiometricPrompt authorizes the required CryptoObject; device credential fallback
|
||||
must match the Rust policy/API level and must not silently weaken it. Changed
|
||||
biometrics, lock-screen removal, restored-without-key data, cancellation and a
|
||||
stale callback fail closed and require explicit recovery. Provider candidates
|
||||
are non-secret until authorized user/system selection plus a valid lease.
|
||||
|
||||
## Paths, backup, update and recovery
|
||||
|
||||
#90 receives canonical filesDir, noBackupFilesDir and cacheDir from Android once;
|
||||
Rust creates scoped capabilities and owns all contents. Never infer HOME or use
|
||||
public/shared storage. Place repository, keys, config, TOTP discovery catalog,
|
||||
Keystore envelopes and transactional durable scratch under noBackupFilesDir.
|
||||
Disposable camera/image buffers may use cacheDir only when cleanup is safe;
|
||||
never use the cache for the only copy of a repository or credential.
|
||||
|
||||
Set allowBackup=false and explicit legacy backup and Android 12+ data-extraction
|
||||
rules excluding all sensitive roots from cloud backup and device transfer. Test
|
||||
OEM transfer behavior; no claim that one manifest flag defeats every OEM tool.
|
||||
No automatic key/repository transfer. The TOTP catalog contains only canonical
|
||||
path, ciphertext SHA-256 and is_totp; treat even that metadata as private.
|
||||
|
||||
An APK/Play update installs over the same ID/signing lineage and retains valid
|
||||
private state and Keystore aliases. Migrations are Rust-owned, versioned and
|
||||
atomic; migration failure retains prior recoverable data. Process death revokes
|
||||
in-memory authentication, preserves valid completed cache checkpoints and leaves
|
||||
atomic transactions recoverable. Low storage/read-only/corruption produce typed
|
||||
errors without deleting unrelated data. Uninstall/reset deletes app data and can
|
||||
make keys unrecoverable; reinstall/restore is not an update. Recovery needs the
|
||||
user's externally retained encrypted key material/passphrase and, when configured,
|
||||
a remote clone. Do not seed app data or commit credentials to prove recovery.
|
||||
|
||||
## Verification and acceptance
|
||||
|
||||
The [parity matrix](parity.md) assigns every current non-Watch mobile capability
|
||||
and every Android issue to a Rust owner and Android API. Its pending rows are
|
||||
implementation obligations, not accepted gaps. #111 must replace pending status
|
||||
with evidence and have no unexplained gap before #112 distribution.
|
||||
|
||||
Every issue runs the AGENTS.md Rust gates before commit. Android changes also
|
||||
run build/lint/unit/instrumented checks appropriate to the issue and computer-use
|
||||
validation on the existing emulator. Update by installation over the existing
|
||||
app, never uninstall/reset. If unlocking needs an unavailable user, label the
|
||||
issue untested and document exactly what could not be checked. Emulator evidence
|
||||
cannot satisfy physical biometric/camera/Keystore/autofill or Play acceptance.
|
||||
Apple changes require XcodeGen and affected simulator builds and UI checks;
|
||||
never re-enroll an already enrolled iPhone simulator in ordinary validation.
|
||||
|
||||
#94 owns reproducible CI and test boundaries, #105 accessibility/performance,
|
||||
#111 the complete architecture/security/parity audit, and #112 physical production
|
||||
install/update/Play release evidence. No release approval is implied by this ADR.
|
||||
@@ -0,0 +1,92 @@
|
||||
# Android parity and issue ownership
|
||||
|
||||
Contract for [#88](https://git.rfc1437.de/hugo/IronStorage/issues/88), reviewed
|
||||
2026-10-08 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:** all Android implementation rows below are pending. No Android app
|
||||
exists at this decision. The table is a complete assignment of work, not a
|
||||
claim of completed parity. #111 must attach screen/component/test evidence to
|
||||
each row. Every 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 | Single Activity, Compose Material 3 Adaptive, Navigation 3, ViewModel/StateFlow | #89/#91/#102; shell fixtures, startup, back/navigation and recreation |
|
||||
| Local-first setup, generated/imported key, passphrase confirmation, staged QR import (SetupChoiceViewController, LocalSetupViewController) | mobile_onboarding::MobileOnboardingOperation, crypto; mobile_key_transfer import | Compose forms and core facade; OS input/camera adapters | #95/#106; real local init, key export/import, canceled/failed setup rollback |
|
||||
| Optional HTTPS clone, server/account/token, repository/branch discovery; attach remote to local store (OnboardingViewController) | mobile_onboarding::{MobileOnboardingRequest, MobileOnboardingOperation}; git/config/secret_store | Forms, typed incremental progress and cancel | #95; TLS/auth/branch/cancel/offline errors; repository remote authority |
|
||||
| Home history, ahead/behind, local/remote change status, commit activity (ShellViewController, MobileCommitActivityViewController) | mobile_home::MobileHomePage/Operation and git | Compose Home/list/detail | #97; summaries and stale/error state, Git identity, author/history |
|
||||
| Commit, Fetch, Pull, Push and pull-then-push Sync | mobile_home::MobileHomeOperation; git sync/merge/conflicts/signing | Typed actions, progress/cancel, conflict presentation | #97; pull failure prevents push, conflict/data-loss cases and signing |
|
||||
| Directory hierarchy, breadcrumbs, folder and entry rows (PasswordDirectoryViewController) | mobile_passwords::MobilePasswordPage/Row/RowKind; repository/read | Adaptive list/detail with stable IDs | #96; deep tree, empty/error, keyboard and size changes |
|
||||
| Password-store name search (PasswordSearchViewController) | mobile_passwords::MobilePasswordPage::search | Search ViewModel, Flow latest-query-wins | #101; large-store responsiveness and canceled/stale results |
|
||||
| Unlock entry, explicit user activity, timeout, manual/background lock; shared entry/TOTP/editor lease (LockedPasswordViewController, AppContext) | mobile_authentication::MobileAuthentication; authentication generation/leases | AndroidX BiometricPrompt/CryptoObject, KeyguardManager, lifecycle | #93/#98/#100; wrong passphrase, cancel, expiry, generation race, changed enrollment and process death |
|
||||
| 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} | Compose viewer, sensitive controls and accessibility semantics | #99/#100; no pre-unlock values, relock clears all views, copy expiry/ownership |
|
||||
| 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 | Compose editor/forms, stable field IDs | #103; actual encrypted saves, conflict tokens, interrupted saves and dirty navigation |
|
||||
| Password length/generation and replacement | generate; mobile_entry::MobileEntryDraft::generate_password | Generator controls call Rust | #103; Rust validation and unbiased generated value; no Kotlin generator |
|
||||
| OTP URI input, camera/image import, review before Save (OtpImportViewController; TOTP Add action) | mobile_entry::MobileEntryDraft::add_otp_image; document/otp/presentation | CameraX frames or Android photo picker bytes; Rust decode and field construction | #103/#106/#107; URI/image/scan parity, invalid/oversized input, cancel; no payload parsing in Kotlin |
|
||||
| Move/copy/delete entries and folders, destination browse, overwrite and dirty-editor handling (PasswordMutationCoordinator) | mobile_mutation::MobileMutationService/Plan/Request; mutation | Compose dialogs/destination picker | #108; revisions, destination conflicts, recipient reencryption and rollback |
|
||||
| TOTP discovery catalog, incremental progress, warm cache, refresh, cancel/resume, cached search (TotpListViewController) | mobile_totp discovery/catalog/operation; mobile_authentication cached/search APIs | Compose list/progress/search; private no-backup catalog | #90/#110; cold/warm/change/add/remove/corrupt/wrong-store/concurrent-change tests |
|
||||
| TOTP rows, large detail code, countdown/expiry, copying (TotpDetailViewController, TotpCodeView) | mobile_totp::MobileTotpPage/Detail; otp; mobile_authentication::{totp_detail,copy_totp_code} | Compose code/detail; OS clock facts, Rust timing | #107/#100; RFC vectors, boundary countdown, stale callback/relock and clipboard |
|
||||
| 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 | Compose Settings/facade | #104/#95; no token display; protected replacement/removal and offline operation |
|
||||
| Key identity/fingerprint, GPG recovery import and public/private QR export (KeyImportScannerViewController, KeyExportListViewController, KeyQrExportViewController) | mobile_key_transfer::{MobileKeyTransferService,MobileKeyTransferImport}; crypto/presentation | CameraX Preview/ImageAnalysis; animated Rust-provided matrices | #106/#104; multi-frame order/duplicates/interruption, bounded frames, private export authorization and camera denial |
|
||||
| Inactivity timeout, biometric enable/disable, Lock Now, appearance and Git commit name/email | mobile_authentication preference setters, git_identity; config | Compose Settings, BiometricPrompt, system/light/dark theme | #98/#104; persistent settings, validation, Keystore enrollment/recovery and lease revocation |
|
||||
| iPhone AutoFill credential selection (CredentialProviderViewController) and shared identity/access domain | desktop/read/document/secret_store today; storage-owned provider contract to add | AndroidX CredentialProviderService (API 34+) and framework AutofillService (API 26+) | #109; typed caller/site identity, non-secret candidates, explicit selection/auth, forged/stale requests, permissions and cross-process lifetime |
|
||||
| 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 | Android framework adapters, FLAG_SECURE, backup rules, ClipboardManager | #90/#93/#98/#100; backup inspection, sandbox paths, pressure/update, screen/clipboard/lifecycle tests |
|
||||
| Accessible labels/actions, large text, keyboard, responsive layout and localization | Typed Rust state/actions; UI accessibility is Kotlin | Compose semantics, TalkBack, adaptive layout, resources | #105; measured keyboard/TalkBack/large-font/multi-window/RTL/rotation coverage |
|
||||
| Watch pairing/install state in Settings; TOTP Watch selection, snapshots, receipts, transfer and watchOS detail | mobile_watch; Watch fields currently in mobile_totp/mobile_authentication and Apple bridge | Excluded from Android records and UI by #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/#91 must
|
||||
also supply bounded image/frame facts for Rust decoding as required by the
|
||||
Android contract; that additional adapter is pending, not an existing API.
|
||||
The external-credential matching/grant API required by #109 must be implemented
|
||||
in storage, rather than copying frontend selection assumptions from AutoFill.
|
||||
|
||||
## 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, three ABIs, checksums/16 KB/loading/debug symbols |
|
||||
| [#93 Keystore adapter](https://git.rfc1437.de/hugo/IronStorage/issues/93) | crates/storage secure-secret orchestration and platform adapter | Framework Keystore AES-GCM; callback facts, sealed records, invalidation/recovery 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 | Rust plans/tokens/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 physical-device 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, physical clean 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.
|
||||
Reference in new issue
Block a user