Skip to content

Bug reporting and diagnostic sending#832

Open
praveenperera wants to merge 30 commits into
masterfrom
bug-reporting
Open

Bug reporting and diagnostic sending#832
praveenperera wants to merge 30 commits into
masterfrom
bug-reporting

Conversation

@praveenperera

@praveenperera praveenperera commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added Send Diagnostics flows on Android and iOS, including report previews, descriptions, sharing, submission, retry, and log clearing.
    • Added diagnostics redaction to protect sensitive wallet, key, address, transaction, and recovery-phrase data.
    • Added Submitted Diagnostics history with report IDs, timestamps, descriptions, copy actions, and clearing.
    • Added persistent diagnostic logging with rotating storage and safe size limits.
  • Bug Fixes

    • Improved diagnostics timeout, error handling, cancellation, and stale-result protection.
    • Prevented diagnostics history from appearing in decoy mode.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e7e14830-6c79-4a96-a3de-479e08ec1d52

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug-reporting

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds diagnostic reporting and persistent diagnostic history. The main changes are:

  • Android and iOS screens for building, previewing, sharing, submitting, and reviewing diagnostics.
  • Rust diagnostic report generation, upload, redaction, and submitted-report storage.
  • Persistent Rust log capture with rotation, clearing, and bootstrap-time attachment.
  • Database and bootstrap diagnostics updates for the new report history table.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
rust/src/diagnostics/redact.rs Adds diagnostics redaction for sensitive wallet data, including embedded and hex-adjacent transaction IDs.
rust/src/bootstrap.rs Attaches persistent diagnostics logging before the fallible bootstrap work.
rust/crates/cove-common/src/logging/capture.rs Adds persistent Rust log capture with ring buffering, disk replay, flushing, clearing, and rotation.
rust/src/database/diagnostics_reports.rs Adds submitted diagnostics report history storage with bounded retention.

Reviews (4): Last reviewed commit: "Correct coin control trace label" | Re-trigger Greptile

Comment thread rust/src/bootstrap.rs Outdated
Comment thread rust/src/diagnostics/redact.rs
Add persistent Rust log capture and a diagnostics report API that assembles, redacts, gzips, and uploads reviewed reports. Keep release debug logging intentional while demoting noisy hot-path logs to trace.
Add Settings -> About entry points and short-lived iOS and Android review sheets for diagnostics. The flow lets users preview, share locally, clear stored logs, submit explicitly, and copy the returned report ID.
Regenerate the Swift and Kotlin Cove Core bindings for the new diagnostics report API.
Add description-based preview rendering and redaction for upload data, while updating Android and iOS diagnostics UI to hide/send-submit behavior in decoy mode and block dismissal while submitting. Harden response handling to limit and truncate diagnostic upload server responses.
Update log capture snapshots to read from rolling log files when file-backed logging is attached, instead of only using in-memory ring buffer text. Adds tests to cover restart persistence and archive ordering (oldest archive through current log) in snapshot output.
Split diagnostics sheet state, content, and platform helpers
into dedicated files while preserving behavior.
Drop the helper subtitle under Send Diagnostics in the About screen
to match the Android row presentation.
Attach persistent Rust log capture before storage bootstrap work so failed launches keep diagnostic logs across restarts.

Also redact transaction IDs embedded in larger log tokens to keep previews and uploads aligned with the privacy notice.
Capture Swift log messages to rotated app-owned files so iOS diagnostics include app logs even though system logs are sandboxed.

Keep Rust file logging off the tracing hot path with a writer thread while flushing before snapshots and clears.
Show user-oriented diagnostics upload errors, retry transient collector failures, and preserve multiline Swift log messages so diagnostics redaction sees their original shape.
Store recent diagnostics report IDs after successful uploads so the apps can recover them after the success alert is dismissed. Cap the history and expose read and clear operations through UniFFI.
Add settings entry points and platform-native history screens so users can revisit, copy, or clear recently submitted diagnostics report IDs.
Return a structured diagnostics submission so clients can surface a saved report ID warning when local history persistence fails. Validate collector success responses, keep decode failures distinct from request encoding, and avoid retaining plaintext redaction secrets in debug output.
Treat history load errors as an explicit failed state in Android and iOS instead of successful empty history. Keep the About entry visible when history is unavailable and add retry paths plus focused Android helper coverage.
Track Rust and Swift diagnostics log write errors so snapshots include a visible breadcrumb instead of silently dropping entries. Fall back to in-memory Rust logs when disk capture is incomplete and clear attached log files during local data reset.
Make SwiftLogStore.clear return errors when file operations fail and
update callers and tests to propagate and validate failure cases.
Ensure reattaching diagnostics capture releases the current writer
before opening a new one so shutdown callbacks can safely replace
current log files.
Add git branch and build profile to diagnostics metadata.
Use the captured values in preview generation and upload payload
assertions to keep both surfaces consistent.
Use a no-redirect reqwest client and retry only
connection failures during upload, because post and status errors may
already have reached the collector.
Expand seed-phrase redaction to detect formatted and numbered
mnemonic lists, while preserving valid BIP-39 constraints and preserving
boundary formatting in output.
When users choose to clear stored diagnostics logs, the Android flow now also attempts to clear platform logcat output (`logcat -c`) before collecting new logs. The clear step is best-effort, runs on the IO dispatcher, and enforces the existing timeout with process cleanup to avoid hanging.
- Narrow broad `Exception` catches to specific types (`DiagnosticsException`, `IOException`, `ActivityNotFoundException`, etc.) in `SendDiagnosticsSheet` and `SubmittedDiagnosticsScreen`
- Extract inline composables (`SubmittedDiagnosticsLoading`, `SubmittedDiagnosticsLoadError`, `SubmittedDiagnosticsErrorDialog`) to reduce nesting
- Change `loadSubmittedDiagnosticsRecords` to accept a `Result`-returning lambda instead of a throwing one
- Extract `new_test_wallet_actor` helper in Rust actor tests to reduce boilerplate
- Add missing `global_state_test_lock` guards to two actor tests
- Use `Mnemonic::parse_in_normalized` with explicit language in bip39 tests
Comment thread rust/src/diagnostics/redact.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (4)
ios/Cove/Flows/SettingsFlow/AboutScreen.swift (1)

49-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: fold summary/visibility logic onto the shared load-state type.

shouldShowSubmittedDiagnostics duplicates the exact switch in SubmittedDiagnosticsLoadState.canClear, and submittedDiagnosticsSummary re-implements the count/label logic that also exists on the Android side. Consider exposing these as computed properties on SubmittedDiagnosticsLoadState to keep the platforms in sync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/Cove/Flows/SettingsFlow/AboutScreen.swift` around lines 49 - 70, Move the
submitted diagnostics visibility and summary logic from AboutScreen’s
shouldShowSubmittedDiagnostics and submittedDiagnosticsSummary into computed
properties on the shared SubmittedDiagnosticsLoadState type, including
canClear-aligned visibility and count-based labeling; update AboutScreen to
consume those properties and preserve existing behavior.
rust/src/diagnostics/upload.rs (1)

10-10: 🔒 Security & Privacy | 🔵 Trivial

Confirm the shipped APP_TOKEN is a non-secret client identifier with collector-side abuse protection.

APP_TOKEN is compiled into the mobile binary and sent as bearer_auth, so it is extractable by anyone and cannot be treated as a per-user secret. That's acceptable for a shared app token, but the diagnostics collector should not rely on it for authentication/authorization and should enforce rate limiting / size limits / abuse protection independently. Please confirm this matches the collector's threat model, and prefer build-time injection over a source-committed constant if rotation is expected.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/src/diagnostics/upload.rs` at line 10, The hardcoded APP_TOKEN in upload
diagnostics must be treated only as a publicly extractable client identifier,
not a secret or authorization credential. Verify the collector independently
enforces authentication/authorization boundaries, rate limiting, payload-size
limits, and abuse protection; if token rotation is expected, replace the source
constant with build-time configuration while preserving a safe fallback or
validation.
rust/crates/cove-common/src/logging/capture.rs (1)

151-156: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Separate the guard from event formatting.

Add a blank line after the multi-line let ... else guard before formatting the event. As per coding guidelines, “Add blank lines between logical steps … after multi-line if/match/guard blocks before the next independent statement.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/crates/cove-common/src/logging/capture.rs` around lines 151 - 156, Add a
blank line after the multi-line ReentrancyGuard `let ... else` block in the
event-capture function, before the `format_event(event)` statement, keeping the
guard and event formatting as separate logical steps.

Source: Coding guidelines

android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SubmittedDiagnosticsScreen.kt (1)

79-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Key LaunchedEffect to an actual dependency instead of Unit.

Per the path instructions for this codebase, LaunchedEffect should be keyed to actual dependencies, not Unit. Keying to ioDispatcher satisfies the rule without changing behavior — the effect will still run once on initial composition and re-run only if the dispatcher changes (which it won't in practice).

♻️ Suggested change
-    LaunchedEffect(Unit) {
+    LaunchedEffect(ioDispatcher) {
         loadState = loadSubmittedDiagnosticsRecords(ioDispatcher)
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SubmittedDiagnosticsScreen.kt`
around lines 79 - 81, Change the LaunchedEffect in SubmittedDiagnosticsScreen
from Unit to the actual ioDispatcher dependency, so it runs on initial
composition and only re-runs if the dispatcher changes. Keep the existing
loadSubmittedDiagnosticsRecords call and state assignment unchanged.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SendDiagnosticsSheet.kt`:
- Around line 346-361: Clear the stale action error at the start of
SettingsFlow's share() method, before calling shareDiagnosticsFile, by resetting
actionError to its neutral state; preserve the existing exception handling so
new share failures still populate the error.
- Around line 86-88: Change the LaunchedEffect in SendDiagnosticsSheet to use
context as its key instead of Unit, while keeping the existing
state.rebuildReport(context, clearStoredLogs = false) call unchanged.

In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SubmittedDiagnosticsScreen.kt`:
- Around line 113-125: Wrap each Database() instance in
SubmittedDiagnosticsScreen, including the instance used in the coroutine’s
diagnosticsReports().clear() call, with use { } so it is closed automatically;
update both call sites consistently while preserving the existing exception
handling and behavior.

In `@ios/Cove/SwiftLogStore.swift`:
- Around line 118-121: Update the file creation logic in SwiftLogStore to apply
the .protectionKey file protection attribute when creating the diagnostics log
via fileManager.createFile, ensuring the unredacted log uses the required
explicit protection class.

In `@rust/crates/cove-common/src/logging/capture.rs`:
- Around line 91-100: Bound the writer queue used by LogWriterHandle and the
writer loop: replace the unbounded mpsc::channel with a bounded channel, make
Write submissions non-blocking, and drop or degrade writes when the queue is
full while retaining Flush and ClearAndWrite control commands. Update the
relevant send/receive handling around the writer task and preserve existing
ring-buffer and control-command behavior.

In `@rust/src/manager/send_flow_manager/psbt_builder.rs`:
- Line 77: Update the trace label in build_psbt_for_coin_control from
build_psbt_for_utxo_list to build_psbt_for_coin_control so diagnostics identify
the correct code path.

---

Nitpick comments:
In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SubmittedDiagnosticsScreen.kt`:
- Around line 79-81: Change the LaunchedEffect in SubmittedDiagnosticsScreen
from Unit to the actual ioDispatcher dependency, so it runs on initial
composition and only re-runs if the dispatcher changes. Keep the existing
loadSubmittedDiagnosticsRecords call and state assignment unchanged.

In `@ios/Cove/Flows/SettingsFlow/AboutScreen.swift`:
- Around line 49-70: Move the submitted diagnostics visibility and summary logic
from AboutScreen’s shouldShowSubmittedDiagnostics and
submittedDiagnosticsSummary into computed properties on the shared
SubmittedDiagnosticsLoadState type, including canClear-aligned visibility and
count-based labeling; update AboutScreen to consume those properties and
preserve existing behavior.

In `@rust/crates/cove-common/src/logging/capture.rs`:
- Around line 151-156: Add a blank line after the multi-line ReentrancyGuard
`let ... else` block in the event-capture function, before the
`format_event(event)` statement, keeping the guard and event formatting as
separate logical steps.

In `@rust/src/diagnostics/upload.rs`:
- Line 10: The hardcoded APP_TOKEN in upload diagnostics must be treated only as
a publicly extractable client identifier, not a secret or authorization
credential. Verify the collector independently enforces
authentication/authorization boundaries, rate limiting, payload-size limits, and
abuse protection; if token rotation is expected, replace the source constant
with build-time configuration while preserving a safe fallback or validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c16dead7-d2b5-4029-b6ba-e308d4e91371

📥 Commits

Reviewing files that changed from the base of the PR and between ebaae5c and 14ef915.

⛔ Files ignored due to path filters (3)
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt is excluded by !android/app/src/main/java/org/bitcoinppl/cove_core/**
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**, !ios/CoveCore/Sources/CoveCore/generated/**
  • rust/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (42)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/AboutSettingsScreen.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/LogcatProcessCollector.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/MainSettingsScreen.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SendDiagnosticsContent.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SendDiagnosticsPlatform.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SendDiagnosticsSheet.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/SubmittedDiagnosticsScreen.kt
  • android/app/src/test/java/org/bitcoinppl/cove/flows/SettingsFlow/LogcatProcessCollectorTest.kt
  • android/app/src/test/java/org/bitcoinppl/cove/flows/SettingsFlow/SendDiagnosticsSheetHelpersTest.kt
  • ios/Cove.xcodeproj/project.pbxproj
  • ios/Cove/Flows/SettingsFlow/AboutScreen.swift
  • ios/Cove/Flows/SettingsFlow/BackupExportView.swift
  • ios/Cove/Flows/SettingsFlow/SendDiagnosticsSheet.swift
  • ios/Cove/Flows/SettingsFlow/SubmittedDiagnosticsSheet.swift
  • ios/Cove/SwiftLogStore.swift
  • ios/CoveTests/SwiftLogStoreTests.swift
  • ios/Logger.swift
  • rust/Cargo.toml
  • rust/crates/cove-bip39/src/lib.rs
  • rust/crates/cove-common/Cargo.toml
  • rust/crates/cove-common/src/logging.rs
  • rust/crates/cove-common/src/logging/capture.rs
  • rust/crates/cove-http/src/lib.rs
  • rust/crates/cove-tokio/src/debounced_task.rs
  • rust/src/app.rs
  • rust/src/bootstrap.rs
  • rust/src/bootstrap/diagnostics.rs
  • rust/src/database.rs
  • rust/src/database/diagnostics_reports.rs
  • rust/src/database/error.rs
  • rust/src/diagnostics.rs
  • rust/src/diagnostics/redact.rs
  • rust/src/diagnostics/upload.rs
  • rust/src/discovery_scanner.rs
  • rust/src/lib.rs
  • rust/src/manager/deferred_sender.rs
  • rust/src/manager/send_flow_manager.rs
  • rust/src/manager/send_flow_manager/amount_input.rs
  • rust/src/manager/send_flow_manager/fee_selection.rs
  • rust/src/manager/send_flow_manager/psbt_builder.rs
  • rust/src/manager/wallet_manager/actor.rs
  • rust/src/transaction_watcher.rs
💤 Files with no reviewable changes (1)
  • rust/src/app.rs

Comment thread ios/Cove/SwiftLogStore.swift
Comment thread rust/crates/cove-common/src/logging/capture.rs Outdated
Comment thread rust/src/manager/send_flow_manager/psbt_builder.rs Outdated
Treat contiguous hex sequences of txid length or longer as a single transaction ID when the exact 64-character boundaries are unclear. This avoids leaking trailing hex data from larger runs, and adds a regression test for the prefixed txid case.
Bound Rust writer memory and surface dropped disk entries through the
ring-buffer fallback. Apply explicit data protection to Swift logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant