Some checks failed
Payment domain and storage / isolated-payment-tests (push) Has been cancelled
Phase 3 (secure repository) is now complete. 3.3 retention and erasure — new retention.rs: - Data minimisation and financial record keeping pull opposite ways, so the policy states both: evidence expires 90 days after settlement, settled records are held for a five-year floor, never-dispatched intents expire in 30 days, and anything awaiting reconciliation is never swept. Deleting an unresolved payment would destroy the only record of money that may have left the account. - erase_payment_on_request honours a user deletion request without destroying the accounting record: it normally erases the parsed copy of the user's inbox and retains the financial record, erases fully only past the floor, and refuses outright while in flight. Refusals carry a reason. 3.4 backup, restore and corruption reporting: - integrity_check and foreign_key_check surface damage as StorageError ::Corrupt rather than letting a damaged ledger be trusted. - backup_to uses SQLite's online backup API instead of copying the file, so a concurrent writer cannot produce a torn copy, and refuses to back up a database that fails its integrity check. - restore_from validates the candidate in a separate connection before touching the live database, so a failed restore cannot destroy a working ledger. Tested with both a missing and a corrupt backup. Storage tests 20 -> 36. Phase 4 (blocking I/O) — 4.1 to 4.3 implemented: - 4.1 expenses/mod.rs called reload(), a full parse of the store from disk, as the first statement of draw_walk; scrolling re-read the whole ledger every frame. Now loaded once, with invalidate()/reload_if_stale() on the event path. - 4.2 the SMS scan was a wall-clock check inside draw_walk, so the branch ran every frame and the scan landed mid-paint. Now a cx.start_interval timer on the event path, with the interval named rather than inline. - 4.3 update_summary walked the filtered list and rewrote labels every frame. Now invalidated only in refresh_filtered and applied in handle_event, fully out of the draw path rather than guarded inside it. - 4.4 already satisfied by PaymentStorageWorker since tranche 1. Supporting domain work: view_state.rs adds PeriodSummary and TransactionsViewState so the summary arithmetic is testable outside a widget. The tests immediately pin two things the inlined code got wrong: totals now report overflow instead of wrapping, and a net outflow returns None rather than a clamped zero. Money gains Default (zero). Domain tests 66 -> 75. Validated on rustc 1.97.1: domain and storage each pass test --locked, fmt, clippy -D warnings and cargo-deny; storage also --features sqlcipher; domain benches run; 7 M-Pesa store tests pass; 49 manifests parse. NOT VERIFIED: the nigig-pay widget edits for 4.1-4.3 are not compiled here. That crate needs the git-hosted Makepad fork. cargo check -p nigig-pay on a full developer checkout is required before Phase 4 can be called complete.
27 lines
1.2 KiB
TOML
27 lines
1.2 KiB
TOML
[package]
|
|
name = "nigig-pay-storage"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
# Matches the licence already declared by the other first-party crates in
|
|
# this workspace (nigig-system-prefs, robius-ussd, theming).
|
|
license = "MIT"
|
|
description = "SQLite repository for nigig-pay payment intents. No UI or platform dependency."
|
|
|
|
[features]
|
|
default = []
|
|
# Encryption at rest (review item 3.1). Enabling this swaps the bundled
|
|
# SQLite for a bundled SQLCipher and requires a DatabaseKey to open a
|
|
# repository. It is opt-in because the host application must first supply a
|
|
# real key hierarchy (Android Keystore / platform secure enclave); shipping it
|
|
# on by default would invite a hardcoded or device-derived key.
|
|
sqlcipher = ["rusqlite/bundled-sqlcipher"]
|
|
|
|
[dependencies]
|
|
# Version-pinned as well as path-based: a bare path dependency is a wildcard
|
|
# requirement, which cargo-deny rejects for a payment crate.
|
|
nigig-pay-domain = { path = "../nigig-pay-domain", version = "0.1.0" }
|
|
# `backup` provides SQLite's online backup API, used for consistent
|
|
# backup/restore (review item 3.4) instead of copying the file underneath a
|
|
# live writer.
|
|
rusqlite = { version = "0.32", features = ["bundled", "backup"] }
|
|
serde_json = "1"
|