RI-8113 Add Sentry error tracking for the Electron app#6073
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A synchronous throw inside the globalShortcut callback is swallowed by Electron's native dispatch and never reaches Sentry's uncaughtException handler, so Cmd/Ctrl+Shift+K reported nothing. Capture the error explicitly instead, matching the shortcut's non-crashing intent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two-tier consent model inside Sentry (anonymous Tier 1 / consented Tier 2), scrubbing security-review checklist, early-crash + consent-caching handling, and mapping to the RI-8113 scope. Intended for Legal/Security review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tier-1 allowlist accepted; IP not tracked; region confirmation pending (EU recommended); retention defaulted to 90 days. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ing) Org is US-region (per DSN host). Region is fixed at org creation, so Legal should confirm US is acceptable for anonymized crash data, or an EU org must be created before launch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sentry is an org-approved vendor; all data stored in US. No EU org needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements the consent model from docs/sentry-production-readiness.md: - Shared, SDK-agnostic scrubbing module (ui/src/services/sentry) used by both the main process and renderer so the layers cannot drift: scrubEvent (redacts extra/contexts/request/breadcrumbs, normalizes stack-frame paths, strips server_name/IP) + minimizeEvent (Tier 1 anonymous allowlist under a shared sentinel id). - Main process: default-deny consent flag cached in electron-store for a synchronous boot read; beforeSend sends full (scrubbed) events with consent and minimized anonymous events without; breadcrumbs gated on consent; native crashReporter upload gated behind consent (start-once); setConsent() updates the tier at runtime. - Renderer: beforeSend self-gates per-event via checkIsAnalyticsGranted. - Consent plumbing: useSentryConsentSync pushes agreements.analytics to the main process over IPC (setSentryConsent) on startup and on toggle. - Unit tests for the scrubbing module. Note: autoSessionTracking/serverName options dropped where the Sentry v10 type no longer accepts them (renderer); server_name is cleared per-event. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The PoC added a predicate function into rollup's `external` array, which only accepts string | RegExp — a TS2769 overload error surfaced after the rebase pulled in newer vite/rollup types. Fold the module list, regex patterns, and the api-dist predicate into a single `external` function (behavior-preserving). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@redis-ui/components v44 (pulled in by the rebase) imports icons via subpaths, e.g. @redislabsdev/redis-ui-icons/multicolor. The moduleNameMapper matched only the bare package name and dropped the subpath, so the mapped module resolved to the package root and LoaderLargeIcon was undefined — styled(undefined) crashed every UI test suite at setup. Anchor each mapping and capture the optional subpath ($1) so deep imports survive the rename. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the title the visual focal point (was small/faded vs the button), mute the supporting copy, and replace the alarming brand-red action with the calm primary blue (recovery, not crash). Colors are theme-aware via the persisted document.body theme class and mirror redis-ui neutral/ primary tokens — inlined because the boundary renders above ThemeProvider, where useTheme()/themed CSS variables are unavailable when a crash is caught. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Separate the generic ErrorBoundary (catch + fallback UI + onError callback) from SentryErrorBoundary (a thin wrapper that injects Sentry reporting). Fixes a real robustness gap: the Sentry capture call previously ran unguarded in componentDidCatch, so if it threw, the error escaped the boundary and the fallback UI never rendered. ErrorBoundary now invokes onError inside try/catch, so a reporting failure can never prevent the fallback from showing. The generic boundary is also reusable/testable without any Sentry dependency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow the component-folder convention: extract ErrorBoundaryProps/State and Palette to .types.ts, the inline CSSProperties to .styles.ts, the palettes + copy to .constants.ts, and getPalette to .utils.ts. The component file is now just the boundary logic + markup. Styles stay plain CSSProperties (not styled-components) because the boundary renders above ThemeProvider; the rationale lives in the constants/styles file headers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover the fallback rendering, custom fallback, onError forwarding, and the robustness guarantee that the fallback still renders when onError throws. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…IDs) Record §9: source maps are required for real debugging value; decision is release=pkg.version (no per-build SHA) + debug IDs for bundle/map matching, SHA as metadata only. Captures current build state, implementation outline, and the build-determinism open question. Also mark ErrorBoundary refinement done. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add @sentry/vite-plugin (renderer) and @sentry/webpack-plugin (main), gated on SENTRY_AUTH_TOKEN so they are a no-op for local/dev builds. When the token is present (CI) they generate hidden source maps, inject debug IDs into bundle+map, upload to Sentry, and delete the maps so they never ship in the app. Release name = pkg.version (matches the runtime release); debug IDs handle bundle/map matching, so no per-build SHA is needed. Wire the env vars into all four build pipelines, and add the missing RI_SENTRY_UI_DSN (the renderer Sentry layer reads it but it was never passed). New CI config required (see readiness doc): SENTRY_AUTH_TOKEN (secret), SENTRY_ORG / SENTRY_PROJECT_UI / SENTRY_PROJECT_ELECTRON (vars), and the RI_SENTRY_UI_DSN secret. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…vars Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Prefix the source-map env vars with RI_ for consistency: RI_SENTRY_AUTH_TOKEN / RI_SENTRY_ORG / RI_SENTRY_PROJECT_UI / RI_SENTRY_PROJECT_ELECTRON (vite + webpack configs and all four pipelines). Note: the auth token is build-time only and must never be read via import.meta.env in client code. 2. Initialize Sentry in the web entry (index.tsx) via a new services/sentryWeb.ts using @sentry/react, mirroring the Electron renderer (consent-gated two-tier reporting, shared scrubbing). All three targets now report: Electron main, Electron renderer, and web/docker. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A PoC commit (link electron sentry project) repointed the UI sentry.dsn at RI_SENTRY_ELECTRON_DSN, so the renderer and web reported to the Electron project and RI_SENTRY_UI_DSN was never read. Point it back at the UI DSN. Also document that this sentry block is runtime-overridable per host via the domainConfig merge in config/index.ts — the channel the cloud deployment will use to point the web build at its own Sentry project (no refactor of the init code needed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture that this PR is forward-compatible with the cloud runtime-config approach (getConfig deep-merges per-host domainConfig; init reads config not env; sync resolution = no re-init), the additive cloud work, and the exact integration point. Records that cloud serves a prebuilt S3 web artifact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidate the split RI_SENTRY_ELECTRON_DSN / RI_SENTRY_UI_DSN into one RI_SENTRY_DSN shared by the Electron main process, renderer, and web — one Sentry project, filtered by platform/environment within it (no second project to maintain). Update the main init, UI config, webpack EnvironmentPlugin, all four pipelines, and the readiness doc. Also drop the redundant source-map comment lines from the workflow env blocks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With one Sentry project, the renderer and main source-map uploads target the same project. Collapse RI_SENTRY_PROJECT_UI / RI_SENTRY_PROJECT_ELECTRON into a single RI_SENTRY_PROJECT (vite + webpack configs, all four pipelines, doc). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The webpack EnvironmentPlugin defaulted RI_SENTRY_ENVIRONMENT to 'production' while the runtime code and UI config default to 'development'. Align it to 'development' and fix the stale doc comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep the readiness/planning doc local-only (added to .git/info/exclude), like docs/pr-plan-RI-7682-decouple-fe-be.md. It should not land in the PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Main process now enables Sentry on 'true' OR '1', matching the renderer/web booleanEnv semantics, so the two layers no longer diverge when RI_SENTRY_ENABLED=1 (main was strict-'true' only). - Add normalizePath regression tests for C:/Users/... and file:///C:/Users/... — the /Users/ branch already normalizes these (prefix-agnostic); the tests lock it in against regex regressions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13eff86766
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…en scrubbing - Source-map upload gates (vite + webpack) now accept RI_SENTRY_ENABLED='1' as well as 'true', matching the runtime/booleanEnv semantics so a build configured with '1' still symbolicates (previously: events on, maps off). - Free-text scrubber now redacts Bearer/Basic auth scheme credentials and OAuth-prefixed token names (access_token, refreshToken, ...), which the previous assignment pattern missed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 65bd50da9d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Default session integrations emit release-health envelopes on load/navigation that are NOT events, so they bypass the beforeSend consent gate and would send usage telemetry for opted-out users. Disable them in all three layers: - web + Electron renderer: BrowserSession - main: MainProcessSession Also align the Electron renderer's `release` to riConfig.app.version (same source as the web init and the Vite upload plugin) for consistency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 514ca30562
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
filesToDeleteAfterUpload only runs after a successful upload, and the upload errorHandler is intentionally non-fatal — so a failed upload (bad token, 5xx, network) left the emitted .js.map files in the output dir to be packaged. Delete them in the errorHandler too (both vite + webpack) so maps never ship regardless of upload outcome. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 02e83f18e0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
minimizeEvent dropped debug_meta and minimizeFrame dropped abs_path, so no-consent (Tier-1) events could not be matched to uploaded source maps and showed minified frames. Keep debug_meta (code_file + debug_id) and abs_path, normalizing any user path defensively. These carry no PII — build paths + debug-id UUIDs — so anonymous stacks become readable without weakening the Tier-1 redaction. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… request url scrubSensitiveData only redacts by key name, so a secret inside a string value (e.g. a token/credential in a breadcrumb's data.url) passed through on the consented path. Add scrubSecretsDeep, applied to extra/contexts/request/ breadcrumb data, so string values are also free-text scrubbed. Also run normalizePath over request.url to strip an OS account name from a Windows file:// page URL (matching how stack-frame paths are handled). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e30d40fdbf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Electron's crashReporter is unsupported under the MAS App Sandbox. Guard process.mas in initCrashReporter so MAS builds skip native minidumps while JS-level Sentry reporting continues to work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses review feedback on the PR: - Trim comments across the Sentry modules to short why-only notes (per the comments rule in #6091); drop how/story comments and stale doc references. - Wrap Sentry.init in try/catch in the web and Electron-renderer initSentry (matching the main process) so a Sentry init failure can't break app startup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 0a3ba64. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0a3ba64346
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

What
Integrates Sentry error tracking for the Electron app (main + renderer) and the web build (RI-8113).
APPLICATION_STARTEDmodel); with consent, full events that are still scrubbed. A shared, SDK-agnostic scrubbing module strips sensitive fields, drops IP /server_name, and normalizes file paths. Consent is plumbed renderer → main over IPC and cached for an early-boot decision.crashReporterminidumps) starts only after consent (start-once; cannot be scrubbed).ErrorBoundarysplit into component / types / styles / constants / utils, with a thinSentryErrorBoundarywrapper that reports to Sentry. The renderer SDK's IPC bridge is set up via@sentry/electron/preloadso renderer-side errors actually reach the main process.dist). Maps arehiddenand deleted after upload, so they never ship. Gated onRI_SENTRY_AUTH_TOKEN+RI_SENTRY_ENABLED→ prod builds only; upload failures are non-fatal.app.layer(electron-main/electron-renderer/web).RI_SENTRY_ENABLEDor a missing DSN makes Sentry a no-op (e.g. the RedisInsight-Cloud repo can disable it).CI configuration required
RI_SENTRY_ENABLED,RI_SENTRY_ORG,RI_SENTRY_PROJECTRI_SENTRY_DSNRI_SENTRY_AUTH_TOKEN(source-map upload; prod builds only — dev builds still report, but ship no maps)Note
@sentry/*is locked to@sentry/react10.39.0 /@sentry/electron7.8.0 in the lockfile; newer 10.50+/7.13 resolutions introduce a duplicate@sentry/coreand a type error. Don't bump without re-runningyarn type-check.Testing
RI_SENTRY_ENABLED=trueandRI_SENTRY_DSNset; trigger a renderer error (error boundary) and a main-process error and confirm both reach Sentry, taggedelectron-renderer/electron-main.feature/RI-8113/sentry-tracking-crashadds crash-trigger helpers for manual verification (kept in sync from this branch).scrubbing.spec.ts(scrubbing + Tier-1 minimization) andErrorBoundary.spec.tsx.Closes RI-8113
Note
Medium Risk
Touches crash reporting, consent-gated telemetry, and CI secrets; misconfiguration could leak richer data without consent or ship source maps if upload cleanup fails (mitigated in code).
Overview
Adds Sentry end-to-end for the desktop app (main + renderer) and the web UI, gated on
RI_SENTRY_ENABLEDandRI_SENTRY_DSN.Runtime: Early
initSentry()in main (app.ts), web (index.tsx), and Electron renderer (indexElectron.tsx); preload imports@sentry/electron/preloadfor renderer IPC. Main process uses consent-awarebeforeSend/beforeBreadcrumb, strips minidump/session integrations that bypass consent, and toggles ElectroncrashReporter(enabled inconfig.json) only when analytics consent is granted via new IPCsetSentryConsent+useSentryConsentSync. Renderer/web mirror the same pattern withcheckIsAnalyticsGranted()and sharedscrubEvent/minimizeEventhelpers.UX: Generic
ErrorBoundaryplusSentryErrorBoundarywrap web and Electron roots; config gains asentryblock from env.Build/CI: Docker, Linux, macOS, and Windows pipelines pass
RI_SENTRY_*vars/secrets. Vite and webpack Sentry plugins upload hidden source maps when enabled + auth token, then delete maps (failed uploads also rimraf so maps never ship). UI build gets extra heap viacross-env NODE_OPTIONS.Reviewed by Cursor Bugbot for commit 0a3ba64. Bugbot is set up for automated code reviews on this repo. Configure here.