Repository navigation
feat: observe owner-bound migration status - #33
ben-kaufman wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Verdict: ✅ Approve
Full review: diff 7 files.
Findings: none.
QA for 435bb2a:
Rust test suite at the head ✅ cargo test ran 58 tests: 58 passed, 0 failed, 0 ignored.
Includes the new migration status decode tests and the session tests for domain binding, credential renewal, revocation, deadlines and global client replacement.
Formatting, Clippy and release build ✅ cargo fmt --check is clean, Clippy adds no warning in changed code, and the release build succeeds.
Clippy reports only the two existing
module_inception warnings in src/tests.rs and src/ffi_tests.rs, which this PR does not touch.
Check: no new UniFFI export ✅ Checked by reading the diff: it adds only Rust pub use re-exports in src/lib.rs and no uniffi::export or UniFFI derive.
The Swift and Kotlin bindings stay unchanged.
No device run: this PR adds no UniFFI export and no app-visible behaviour, so nothing reaches Bitkit iOS or Android yet. The migration status read runs only against the library's own test fixtures; no deployed VSS server was tested.
Reviewed by claude-opus-5-5-medium
talosmachina
left a comment
There was a problem hiding this comment.
No findings. Adds a strict, owner-bound read of the candidate getStoreMigrationState contract through the original app or LDK credential provider, with explicit legacy vs committed policy and fail-closed wire validation. Reviewed 435bb2a, full tier, as the delta on top of #32 (feat/backup-read-session, the stack root).
What I checked, and 7 candidates I ruled out
Read in full: src/migration_status.rs, src/receipt.rs, src/backup_session.rs; the diff of src/lib.rs, README.md and both test files.
Build: skipped here. talos-pr-run could not confirm the author's permission on this repo and fails closed, so this is a static review plus CI's own run. CI Tests ran 58 passed, 0 failed at this head, including the five migration_status::tests cases; Clippy and manifests green; Android and iOS Bindgen still pending when I read them.
Ruled out
- 200 with an empty body read as legacy: it decodes to a default
Statewhose emptystore_idfails thestate.store_id != store_idcheck, so it isInvalidData, notLegacy. - Negative or large
epochnarrowed by prost:validate_wirereads the raw varint and rejects anything above 1 beforeState::decode, so a 10-byte negativeint64never reaches thematch. - Duplicate fields merged by prost: the
seenbitmask rejects a repeated non-repeated tag at both levels (top level up to 9, nested up to 2 in its own call), andobjectsis capped at 32 occurrences. - Archive and component disagreeing on existence: an archive with
ciphertext_sha256: Nonesharing a key with an object comparesNone != Some(..)and fails; equal key with a different digest fails too; archive equal toinitial_headis rejected outright. - Revocation race in
read_migration_state: same shape as the existingread: subscribe beforeensure_active, a biasedselect!onchanged(), and a secondensure_activebefore the result is wrapped. The sender lives inself.revoked, sochanged()cannot error out from under the borrow. - Deadline not covering credential acquisition:
get_headersruns insiderequest, whichpostwraps intokio::time::timeout(TIMEOUT, ..), so the ten seconds include it. getObjectbehaviour changed by thepostrefactor: same URL ({base}/getObject), same headers, same limit check andbounded_body; only the decode moved to the caller.
Not checkable from this repo: the server side of getStoreMigrationState. The wire messages are pinned to an unpublished proto, so the request shape and field tags are reviewed for internal consistency only.
Merge confidence: 4/5, no findings, but the PR's code was not built here and the two Bindgen jobs were still pending.
dzdidi
left a comment
There was a problem hiding this comment.
Reviewed exact head 435bb2a48459a556f3504981c4dc471c21166d02 against base 17c8373419b892ec0eda9070551c8f22f25b5e54. No blocking or non-blocking findings after full source/context review. Exact-head Tests, Clippy, manifest, SwiftPM, iOS Bindgen, and Android Bindgen checks succeeded. Residual risk: unpublished server contract and no deployed-server acceptance evidence.
Description
Read candidate VSS migration policy through the original wallet's retained app or LDK credential provider. A valid legacy tuple is distinct from committed migration metadata. Missing routes, authorization failures, unknown policies, malformed or conflicting fields and oversized replies remain errors; they cannot authorize legacy fallback.
Each observation belongs to the original session and credential domain. Credential renewal can report a changed physical principal without changing an older observation. Revocation rejects pending and later results, and abandoning a read schedules no replay. The status storage POST shares the strict receipt transport: no automatic retries or redirects, a 64 KiB response cap and a ten-second deadline including credential acquisition.
Stacked on #32. This is in-crate Rust source preparation for terminal complete-WALLET recovery in synonymdev/bitkit-ios#1121 and synonymdev/bitkit-android#1686. It describes the preserved, unpublished VSS status contract. No server code, homeserver dependency, new UniFFI export, released API, app activation, migration or deployment is included.
Validation
0.5.27-dev.4. Existing Swift/Kotlin interfaces are byte-identical to the validated parent. Both iOS17 links and the Kotlin consumer compile pass. Android lint XML: 0 errors, 3 verified unchanged dependency warnings, 0 introduced findings.435bb2a4. The complete audit covered 8,246 log lines and 14 annotations; hosted Rust passed 58 tests with zero failures/ignored cases. Both uploaded artifacts completed in single transfers and passed SHA-256, nested CRC, interface and native-symbol checks. Hosted iOS has 865 correctly targeted arm64 objects per slice; Android has all four API21/r28c ABIs, 16 KiB alignment and matching debug/release build IDs. All preserve the 93 existing FFI exports. Five conditional Rustup-bootstrap skips and two Android NO-SOURCE tasks are not test passes. Existing workflow/toolchain notices and the two base Clippy findings are retained; there were no CI retries or introduced diagnostics.QA Notes
These are controlled library fixtures, not authenticated app or deployed-server acceptance. The credential provider retains its own challenge/callback redirect and response-size policies. A parsed status does not prove deployment, all-tuples coherence, fresh authorization or old reader/writer exclusion. Any later mutation requires an enforcing server to atomically check fresh authorization against the original observed principal/store. Terminal complete-WALLET availability remains open.