Skip to content

feat: integrate Sentry into QR account sync receive flow#33316

Open
grvgoel81 wants to merge 5 commits into
mainfrom
feat/qr-account-sync-sentry-integration
Open

feat: integrate Sentry into QR account sync receive flow#33316
grvgoel81 wants to merge 5 commits into
mainfrom
feat/qr-account-sync-sentry-integration

Conversation

@grvgoel81

@grvgoel81 grvgoel81 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Description

Implements sentry integration for QR account sync failures, so sync receive-path errors are queryable in Sentry without leaking secrets (OTP, SRP, addresses, raw QR / deeplink payloads).

This change:

  • Adds app/core/QrSync/qrSyncTelemetry.ts with feature:qr-sync tags, phase breadcrumbs, sensitive-field scrubbing, and reportQrSyncFailure (via Logger.error → Sentry)
  • Reports scanner invalid/expired QR and Add Device submit failures.
  • Adds an OTP grant-wait deadline watchdog + GRANT_WAIT_TIMEOUT, and reports terminate / import / provisioning failures.
  • Emits scrubbed phase breadcrumbs on controller transitions.

Changelog

CHANGELOG entry: null

Related issues

Refs: https://consensyssoftware.atlassian.net/browse/TO-920

Manual testing steps

Feature: QR account sync Sentry integration

 Background:
    Given I am running a production-like build with metrics reporting enabled
    And I can open Sentry Issues filtered by feature:qr-sync

  Scenario: invalid or expired Add Device QR reports scanner failure
    Given I am on the QR scanner for Add Device / QR sync
    When user scans an invalid or expired sync QR code
    Then the app shows the existing invalid/expired sync error UI
    And a Sentry event is captured with feature:qr-sync and surface:scanner
    And the event extras do not contain OTP, SRP, addresses, or raw QR payloads

  Scenario: grant-wait timeout reports grant_wait failure
    Given a QR sync session is waiting for the extension grant / OTP confirmation
    And the grant-wait deadline elapses without completion
    When the OTP grant-wait watchdog fires
    Then the sync session terminates with GRANT_WAIT_TIMEOUT
    And a Sentry event is captured with feature:qr-sync and surface:grant_wait
    And breadcrumbs show phase transitions without secrets

  Scenario: import / provisioning failure reports import failure
    Given a QR sync session reaches password / import after a successful scan
    When user submits a password or completes import and import/provisioning fails
    Then the app shows the existing import failure UX
    And a Sentry event is captured with feature:qr-sync and surface:import
    And scrubbed extras do not contain mnemonic, OTP, or address values

  Scenario: happy-path sync does not spam failure events
    Given a valid QR sync session between mobile and extension
    When user completes Add Device sync successfully
    Then accounts sync without error UI
    And no QR sync failure Sentry events are created for that session

Screenshots/Recordings

Before

N/A - no UI change

After

N/A - no UI change

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
New OTP grant-timeout termination changes session behavior when handshake stalls, and error reporting now runs across vault import and provisioning paths—though secrets are scrubbed before Sentry.

Overview
Adds qrSyncTelemetry so QR account sync receive-path failures are reported to Sentry with feature:qr-sync tags, surface/operation metadata, phase breadcrumbs, and scrubbed extras (no OTP, SRP, addresses, or raw QR/deeplink payloads).

reportQrSyncFailure replaces ad-hoc Logger.error calls across Add Device scan submit, the QR scanner (invalid/expired classification), QrSyncController, import/navigation hooks, provisioning, and onboarding provisionFromMetadata.

QrSyncController now schedules an OTP grant-wait watchdog from the display deadline, fails with new GRANT_WAIT_TIMEOUT, clears the timer on connect/completion/teardown, and emits phase breadcrumbs on key transitions; session termination also reports via telemetry.

Unit tests cover scrubbing, breadcrumbs, reportQrSyncFailure, and the grant-timeout behavior.

Reviewed by Cursor Bugbot for commit 83d5cd9. Configure here.

@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamask-ci metamask-ci Bot added the team-onboarding Onboarding team label Jul 15, 2026
@metamask-ci

metamask-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

PR template — items to address before "Ready for review"

Warnings — informational, address before merging:

  • Pre-merge author checklist has unchecked items (e.g. "I've tested on Android"). Every box must be consciously checked — see docs/readme/ready-for-review.md.

See docs/readme/ready-for-review.md for the full Definition of Ready for Review.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 83d5cd9. Configure here.

Comment thread app/core/QrSync/QrSyncController.ts
@grvgoel81 grvgoel81 marked this pull request as ready for review July 15, 2026 07:48
@grvgoel81 grvgoel81 requested review from a team as code owners July 15, 2026 07:48
@github-actions github-actions Bot added the risk:medium AI analysis: medium risk label Jul 15, 2026
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🧪 Flaky unit test detection

Run history flaky detection

View recent run history

Historical failure rate is a hint, not proof — review each suggestion in context. See the flaky-test-detection skill for the full pattern reference and manual audit workflow.

Failures / runs sampled per window:

File 7d 15d 30d
app/components/UI/OptinMetrics/OptinMetrics.navigation.test.tsx 0/96 0/174 0/365
app/util/onboarding/finalizeOnboardingCompletion.test.ts 0/96 0/174 0/365

AI-detected flaky patterns

app/components/UI/OptinMetrics/OptinMetrics.navigation.test.tsx

  • J1 — Missing act() around async state updates (critical)
    • onComplete is an async callback from navigation params that triggers Redux dispatches (setWalletHomeOnboardingStepsEligibleAction), mockProvisionFromMetadata, mockDiscoverAccounts, and navigation.reset - all state updates. It is called directly with 'await onComplete()' in multiple tests (including this one and SRP import tests) without act() wrapper. This matches J1 critical pattern exactly and can lead to intermittent React update errors in CI. No act imported or used in file. Historical hint not used as file had 0 failures.
    • Suggested fix in app/components/UI/OptinMetrics/OptinMetrics.navigation.test.tsx:
      -      const navCall = mockNavigate.mock.calls.find(
      -        (call) => call[0] === Routes.ONBOARDING.INTEREST_QUESTIONNAIRE,
      -      );
      -      const onComplete = navCall?.[1]?.onComplete;
      -
      -      mockReset.mockClear();
      -      await onComplete();
      -
      -      await waitFor(() => {
      -        expect(mockReset).toHaveBeenCalledWith(
      -          expect.objectContaining({
      -            routes: [{ name: Routes.ONBOARDING.HOME_NAV }],
      -          }),
      -        );
      -      });
      +      const navCall = mockNavigate.mock.calls.find(
      +        (call) => call[0] === Routes.ONBOARDING.INTEREST_QUESTIONNAIRE,
      +      );
      +      const onComplete = navCall?.[1]?.onComplete;
      +
      +      mockReset.mockClear();
      +      await act(async () => {
      +        await onComplete();
      +      });
      +
      +      await waitFor(() => {
      +        expect(mockReset).toHaveBeenCalledWith(
      +          expect.objectContaining({
      +            routes: [{ name: Routes.ONBOARDING.HOME_NAV }],
      +          }),
      +        );
      +      });

app/util/onboarding/finalizeOnboardingCompletion.test.ts

  • J10 — jest.spyOn without restoreAllMocks in afterEach (medium)
    • File uses jest.spyOn(Logger, 'error') in two tests (provisionFromMetadata and discoverAccounts failure cases) with .mockImplementation and manual mockRestore at end of each it(). No afterEach(jest.restoreAllMocks()) present. Spies can leak across tests if a test fails before restore or in randomized order, matching J10. All other mocks use jest.mock at top level. beforeEach only clears but does not restore spies. Historical hint not used (0 failures).
    • Suggested fix in app/util/onboarding/finalizeOnboardingCompletion.test.ts:
      -  beforeEach(() => {
      -    jest.clearAllMocks();
      -    mockProvisionFromMetadata.mockResolvedValue(undefined);
      -  });
      +  beforeEach(() => {
      +    jest.clearAllMocks();
      +    mockProvisionFromMetadata.mockResolvedValue(undefined);
      +  });
      +
      +  afterEach(() => {
      +    jest.restoreAllMocks();
      +  });

This check is informational only and does not block merging.

Comment thread app/components/Views/AddDeviceToWallet/index.tsx Outdated
Comment thread app/components/Views/QRScanner/index.tsx Outdated
Comment thread app/core/QrSync/services/qr-sync-provisioning-service.ts Outdated
Comment thread app/core/QrSync/services/qr-sync-provisioning-service.ts Outdated
Comment thread app/core/QrSync/QrSyncController.ts Outdated
Comment thread app/core/QrSync/QrSyncController.ts Outdated
Comment thread app/core/QrSync/QrSyncController.ts Outdated
Comment thread app/core/QrSync/QrSyncController.ts Outdated
Comment thread app/core/QrSync/QrSyncController.ts Outdated
Comment thread app/core/QrSync/types.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: None (no tests recommended)
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: low
  • AI Confidence: 92%
click to see 🤖 AI reasoning details

E2E Test Selection:
All 12 changed files are telemetry/observability improvements only:

  1. New qrSyncTelemetry.ts: A new Sentry observability helper module that provides structured error reporting (reportQrSyncFailure), phase breadcrumbs (addQrSyncPhaseBreadcrumb), and sensitive data scrubbing utilities. This is purely additive infrastructure.

  2. QrSyncController.ts, completeExistingUserQrSyncImport.ts, useQrSyncImportNavigation.ts, qr-sync-provisioning-service.ts, AddDeviceToWallet/index.tsx, finalizeOnboardingCompletion.ts, QRScanner/index.tsx: All replace Logger.error(err, 'string message') calls with reportQrSyncFailure(err, { structured options }). The underlying error handling behavior (catch blocks, navigation, state resets) is unchanged — only the error reporting format changes.

  3. Test files (qrSyncTelemetry.test.ts, useQrSyncImportNavigation.test.ts, OptinMetrics.navigation.test.tsx, finalizeOnboardingCompletion.test.ts): Unit test updates to match the new structured telemetry format.

No functional user flows are modified. The QR sync import flow, onboarding completion, and QR scanner behavior remain identical. A grep of the smoke test suite confirms there are no E2E smoke tests for QR sync flows. No E2E tags are warranted for pure telemetry instrumentation changes.

Performance Test Selection:
All changes are telemetry instrumentation (replacing Logger.error with structured reportQrSyncFailure calls and adding Sentry breadcrumbs). There are no changes to rendering logic, data fetching, state management, or any performance-sensitive code paths. No performance test tags are warranted.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:medium AI analysis: medium risk size-L team-onboarding Onboarding team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants