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
@@ -100,3 +100,11 @@ The checked-in compatibility suite completes the earlier OpenPGP backend gate:
|
|||||||
`pgp` imports protected armored and binary exports, decrypts every GnuPG-audited
|
`pgp` imports protected armored and binary exports, decrypts every GnuPG-audited
|
||||||
fixture, emits independently decryptable single- and multi-recipient messages,
|
fixture, emits independently decryptable single- and multi-recipient messages,
|
||||||
and verifies the detached recipient signatures.
|
and verifies the detached recipient signatures.
|
||||||
|
|
||||||
|
## Android dependency policy
|
||||||
|
|
||||||
|
The approved Android library/API purposes, license review, maintenance checks,
|
||||||
|
version pinning and update gates are recorded in
|
||||||
|
[`docs/android/architecture.md`](docs/android/architecture.md#approved-dependencies-and-review-policy).
|
||||||
|
The Gradle catalog and resolved dependency/license records must identify actual
|
||||||
|
shipped versions before release; this approval matrix does not replace that audit.
|
||||||
@@ -75,6 +75,11 @@ Rollback-safe remove, move, and copy transactions, destination rules, and
|
|||||||
selective subtree reencryption are documented in
|
selective subtree reencryption are documented in
|
||||||
[`docs/tree-mutations.md`](docs/tree-mutations.md).
|
[`docs/tree-mutations.md`](docs/tree-mutations.md).
|
||||||
|
|
||||||
|
The native Android architecture, support policy and complete mobile parity/issue
|
||||||
|
map are recorded in [`docs/android/architecture.md`](docs/android/architecture.md)
|
||||||
|
and [`docs/android/parity.md`](docs/android/parity.md). Android implementation
|
||||||
|
belongs to milestone 06; the decision record does not claim a shipped client.
|
||||||
|
|
||||||
## Project layout
|
## Project layout
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
@@ -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