Files
IronStorage/docs/desktop-audit.md

122 lines
10 KiB
Markdown

# Desktop parity, platform, and security audit
The Iced application is a presentation adapter over `crates/storage`. The
tables below are the milestone 01/02 coverage record. `action.rs` is the single
desktop action and enablement registry used by menus, shortcuts, direct
controls, context controls, Help, and the command palette. A desktop unit test
requires every registered action ID to remain present in this document.
## Coverage matrix
| Area and compatible operation | Registered desktop action and menu | Direct control, dialog, or view | Command palette |
| --- | --- | --- | --- |
| Configuration and lock: open configured store | `open-folder` (File) | Compact toolbar control and native folder picker; storage validates and persists configuration | Yes |
| Configuration and lock: edit shared settings | `settings` (IronStorage) | Labelled Settings form for vault, default key, and inactivity timeout | Yes |
| Configuration and lock: refresh typed tree | `refresh` (View) | Sidebar Refresh control | Yes |
| Configuration and lock: lock/unlock | `lock` (Tools) | Toolbar Lock control; opening protected content starts storage authentication | Lock only; unlock is the protected action being resumed |
| Base pass: `init` root or nested recipient policy | `initialize-store`, `new-folder` (File) | Recipient/default-key form and explicit replacement confirmation | Yes |
| Base pass: default/list/`ls`/`list` | `refresh` (View) | Expandable storage-provided tree with object icons and descendant entry counts | Yes for refresh; browsing is direct navigation |
| Base pass: `show` and reload | `open-entry`, `reload-entry` (Entry) | Tree activation, typed identity header, structured viewer, Reload control | Yes |
| Base pass: `insert`/`add` | `new-entry` (File) | New Entry form creates a lossless draft, then the structured editor saves it | Yes |
| Base pass: `edit` and save | `edit-entry`, `save` (Entry/File) | Compact Edit and Save controls; shared Save/Discard/Cancel guard | Yes |
| Base pass: `generate` and replace | `generate-password` (Entry) | Field Generate control and explicit replacement confirmation | Yes |
| Base pass: authenticated values and clipboard | `copy-field`, `copy-edited-field` (Entry) | Every field is visible while unlocked; compact Copy controls retain the configured cleanup countdown | Yes |
| Base pass: `find` | `find` (Edit) | Name-search form and typed result activation | Yes |
| Base pass: `grep` | `search-contents` (Edit) | Authenticated decrypted-search form and typed result activation | Yes |
| Base pass: `mv`/`rename`, `cp`/`copy`, `rm`/`remove` | `move-entry`, `copy-entry`, `delete-entry` (Entry) | Sidebar context controls and validated mutation forms; delete is confirmed | Yes |
| KeePass migration: additive KDBX import and quick add | `import-kdbx` (Tools) | Native file/key picker, protected password input, explicit confirmation, and storage-owned tree refresh | Yes |
| Pass OTP: code/show and timed copy | `generate-otp`, `copy-otp` (Entry) | OTP panel shows typed metadata, code, validity, and HOTP confirmation | Yes |
| Pass OTP: insert/add/append and validate | `import-otp` (Entry) | URI/QR import form; storage validates, replaces, and commits | Yes |
| Pass OTP: URI terminal/clipboard/QR | `show-otp-uri`, `copy-otp-uri`, `show-otp-qr` (Entry) | Explicit secret view, timed copy, and storage-provided QR matrix | Yes |
| Pass OTP: remove | `remove-otp` (Entry) | Explicit permanent-removal confirmation | Yes |
| Embedded Git: status, history, remote divergence | `git-status` (Tools) | Git dashboard renders the storage snapshot and recent history | Yes |
| Embedded Git: fetch/pull | `git-pull` (Tools) | Pull progress/cancel control; fetch is the receive phase of the typed pull | Yes |
| Embedded Git: push | `git-push` (Tools) | Push progress/cancel control | Yes |
| Embedded Git: sync and conflicts | `git-sync` (Tools) | Sync progress plus per-path local/remote conflict choices | Yes |
| Desktop command discovery and pane navigation | `command-palette`, `toggle-pane-focus` (View) | Toolbar search, Tab focus transfer, arrows/Home/End/Enter navigation | The palette opens itself by shortcut/control and is intentionally not a result |
| Desktop text editing | `undo`, `redo`, `cut`, `paste` (Edit) | Platform text controls own these standard operations; the shared registry explains why app-level dispatch is disabled | Listed with its current availability |
| Window/application lifecycle | `about`, `close-window`, `quit`, `minimize` (IronStorage/File/Window) | Standard native roles on macOS and equivalent in-window actions elsewhere | Yes except native-only minimize behavior where the OS owns the role |
| Help and current shortcuts | `help` (Help) | Labelled, scrollable Help view generated from the action registry | Yes |
The CLI/TUI expose a few terminal-shaped selectors rather than separate domain
capabilities. Generic `show --qrcode`, OTP version output, arbitrary embedded
Git plumbing, and shell completion are therefore not duplicate desktop
actions. The desktop viewer already renders an ordinary field, OTP version
compatibility belongs to storage/CLI metadata, Git initialization and commits
occur within typed storage mutations, remote configuration is shared Settings,
and desktop command discovery is the palette. Git history and conflict
resolution are controls inside `git-status` rather than separate commands.
These are deliberate presentation differences, not storage-feature gaps.
## Interaction and accessibility evidence
- Keyboard-only operation uses Tab between panes, arrows/Home/End/Enter within
trees, fields, menus, and palette results, Escape to dismiss, and registered
accelerators. The same controls are mouse/touch activatable; sidebar context
actions also accept a secondary click.
- Both panes are independently scrollable, the divider is resizable, action
rows wrap, long names and storage-grouped multiline values are retained, and
the supported narrow window floor is 480 by 360 logical pixels. Iced/winit applies native
display scaling before layout.
- Compact toolbar controls use one 16-by-16 vector icon system with descriptive
delayed tooltips and registered shortcuts. Focused/selected rows use the
theme's primary contrast pair; field labels remain visible as a non-colour cue.
- The app implements no animation or motion-driven state transition. The one-
second subscription updates lease, OTP, Git, and clipboard presentation state
without moving focus or renewing authentication, so reduced-motion mode has
no additional transition to disable.
- Iced 0.14 does not expose a stable application API for supplying a native
screen-reader accessibility tree. Controls therefore have complete visible
labels and deterministic keyboard focus, but native screen-reader role/name
integration is an explicit framework limitation rather than a silent stub.
## Platform menu and workflow smoke contract
`conventional_shortcuts_resolve_on_every_supported_platform` executes the
Command-versus-Control mapping for macOS, Linux, and Windows on every test host.
The macOS-only native adapter test verifies its native accelerators. Linux and
Windows use the same action registry through the in-window menu, so its labels,
enablement, palette dispatch, and workflow state tests are platform-neutral.
Native equivalent runners use stable Rust and run from the repository root:
```sh
cargo test --package ironstorage-desktop --all-targets
cargo check --package ironstorage-desktop --all-targets
cargo run --package ironstorage-desktop
```
For the final smoke step on each native host:
| Platform | Menu/accelerator smoke | Primary workflow smoke |
| --- | --- | --- |
| macOS | System App/File/Edit/View/Entry/Tools/Window/Help menus; Command-O/S/F/K/L, Tab, F1 | Open a test vault, unlock/view/edit/save, search, Git refresh, OTP code/copy, lock, close |
| Linux | In-window menus; Ctrl-O/S/F/K/L, Tab, F1 | Same sequence under X11 or Wayland with the desktop portal available |
| Windows | In-window menus; Ctrl-O/S/F/K/L, Tab, F1 | Same sequence with the native folder picker and Windows secure store available |
The automated state tests use temporary real encrypted stores and cover the
same primary workflows without retaining a GUI password or starting a helper.
Native picker, clipboard, secure-store, and actual screen-reader integration
remain native-host smoke checks because CI cannot emulate those OS services.
## Security and architecture audit
| Risk | Enforced behavior and executable evidence |
| --- | --- |
| Plaintext lifetime and persistence | Entry/OTP values use storage `SecretBytes` or zeroizing edit buffers. Lock, expiry, vault switch, and stale completion paths drop the editor and sensitive presentation state. The source audit rejects desktop filesystem writes. |
| Authenticated values, errors, and diagnostics | Storage supplies sensitivity and redacted typed errors. Viewer/editor tests require every field to remain visible until lock or lease expiry; malformed and non-UTF-8 fields remain lossless. Desktop messages are not `Debug`, and the source audit rejects print/debug/log-style output. |
| Clipboard | `NativeClipboardManager` owns timeout and replacement-safe cleanup. Desktop state shows a live remaining-seconds value, cancels cleanup on lock, and ignores stale completions. |
| Authentication expiry | Storage authentication leases own the clock and policy. Passive ticks, rendering, pointer movement, and window events do not renew activity; deterministic tests cover expiry during protected state. |
| Dirty documents and conflicts | Every entry/vault/window/Git worktree replacement routes through one Save/Discard/Cancel decision. Failed saves and conflicts keep the complete draft. |
| Background and window lifecycle | Generation counters reject stale asynchronous results. Lock cancels Git/clipboard work and clears OTP, QR, URI, entry, and editor state. Close and quit use the same dirty guard. |
| Repository and domain ownership | The executable source audit rejects repository/Git construction, process launch, OTP/QR parsing, filesystem writes, unsafe blocks, and non-HTTPS literals in production desktop modules. The folder picker may read only a user-selected QR image; all password-store I/O remains in `crates/storage`. |
Run the complete repository gate after the desktop-specific checks:
```sh
cargo fmt --all -- --check
RUSTFLAGS="-D warnings" cargo check --workspace --all-targets
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
```