Add debug reports with context to feedback flow#1798
Conversation
|
Paragon Review Skipped Hi @richiemcilroy! Your Polarity credit balance is insufficient to complete this review. Please visit https://app.paragon.run to finish your review. |
| {debugReport && ( | ||
| <Section className="my-4 p-4 bg-gray-50 rounded-lg"> | ||
| <Text className="text-xs leading-5 text-gray-700 whitespace-pre-wrap"> | ||
| {debugReport} | ||
| </Text> | ||
| </Section> | ||
| )} |
There was a problem hiding this comment.
Unbounded JSON blob in email body
debugReport is the full tab-indented clientContext JSON, which includes up to 20 recordings, 20 screenshots, all device formats, all stores, and diagnostics. This can easily reach 50–100 KB. Many transactional email providers (e.g. Resend) impose payload size limits, and silently hitting that ceiling would cause the sendEmail call to throw, returning a 500 to the client with no useful error message. At minimum the field should be truncated before passing to this component.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/database/emails/feedback.tsx
Line: 74-80
Comment:
**Unbounded JSON blob in email body**
`debugReport` is the full tab-indented `clientContext` JSON, which includes up to 20 recordings, 20 screenshots, all device formats, all stores, and diagnostics. This can easily reach 50–100 KB. Many transactional email providers (e.g. Resend) impose payload size limits, and silently hitting that ceiling would cause the `sendEmail` call to throw, returning a 500 to the client with no useful error message. At minimum the field should be truncated before passing to this component.
How can I resolve this? If you propose a fix, please make it concise.| platform: navigator.platform, | ||
| online: navigator.onLine, |
There was a problem hiding this comment.
navigator.platform is deprecated in modern browsers and may return an empty string in some Chromium-based webviews. Consider using navigator.userAgentData?.platform as the preferred source with navigator.platform as a fallback.
| platform: navigator.platform, | |
| online: navigator.onLine, | |
| platform: (navigator as unknown as { userAgentData?: { platform?: string } }).userAgentData?.platform ?? navigator.platform, | |
| online: navigator.onLine, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/(window-chrome)/settings/feedback.tsx
Line: 90-91
Comment:
`navigator.platform` is deprecated in modern browsers and may return an empty string in some Chromium-based webviews. Consider using `navigator.userAgentData?.platform` as the preferred source with `navigator.platform` as a fallback.
```suggestion
platform: (navigator as unknown as { userAgentData?: { platform?: string } }).userAgentData?.platform ?? navigator.platform,
online: navigator.onLine,
```
How can I resolve this? If you propose a fix, please make it concise.| feedback, | ||
| clientContext, | ||
| } = c.req.valid("form"); | ||
| const user = c.get("user"); |
There was a problem hiding this comment.
If reportId (or clientContext) is present, it probably means “debug report” and should require auth. Otherwise this endpoint can be hit anonymously to post “debug report” messages + attachments to the webhook.
| const user = c.get("user"); | |
| if (reportId && !user) { | |
| return c.json( | |
| { error: "Authentication required for debug reports" }, | |
| { status: 401 }, | |
| ); | |
| } |
| const fileBase = `cap-desktop-${os || "unknown"}-${version || "unknown"}-${reportId || Date.now()}`; | ||
| const fileName = `${fileBase}.log`; |
There was a problem hiding this comment.
os / version / reportId are ultimately client-provided, so it’s worth sanitizing before using them in filenames (avoid weird characters or accidental header-ish values).
| const fileBase = `cap-desktop-${os || "unknown"}-${version || "unknown"}-${reportId || Date.now()}`; | |
| const fileName = `${fileBase}.log`; | |
| const safeFilePart = (value: string) => | |
| value.replaceAll(/[^a-zA-Z0-9_.-]/g, "_"); | |
| const fileBase = `cap-desktop-${safeFilePart(os || "unknown")}-${safeFilePart(version || "unknown")}-${safeFilePart(reportId || String(Date.now()))}`; | |
| const fileName = `${fileBase}.log`; |
| os, | ||
| version, | ||
| }); | ||
| const clientContext = JSON.stringify(context, null, "\t"); |
There was a problem hiding this comment.
clientContext gets sent to the API twice (Tauri upload_debug_report + /feedback). Pretty-printing with tabs can significantly inflate the payload; I’d keep it compact for transport (and if you want readability, derive a separate pretty string for display/email with a size cap).
| const clientContext = JSON.stringify(context, null, "\t"); | |
| const clientContext = JSON.stringify(context); |
| {debugReport && ( | ||
| <Section className="my-4 p-4 bg-gray-50 rounded-lg"> | ||
| <Text className="text-xs leading-5 text-gray-700 whitespace-pre-wrap"> | ||
| {debugReport} |
There was a problem hiding this comment.
Potential footgun: debugReport can be very large (it’s a full JSON dump right now). Capping what gets embedded in the email helps avoid oversized emails / deliverability issues.
| {debugReport} | |
| {debugReport.length > 20000 | |
| ? `${debugReport.slice(0, 20000)}…` | |
| : debugReport} |
adds an optional debug report path alongside normal feedback: the desktop app can generate a stable report ID, collect structured client context (runtime, route, stores, diagnostics, sanitized settings), upload logs via an authenticated multipart request when submitting a report, and notify the team through the existing Discord webhook and feedback email pipeline.
Greptile Summary
This PR adds an optional debug report path to the existing feedback flow: the desktop app collects structured client context (runtime, stores, diagnostics, sanitized settings), uploads logs via an authenticated multipart request, and notifies the team via Discord and email.
lib.rs,logging.rs): a newupload_debug_reportTauri command refactors the existing log-upload path intoupload_log_file_with_context, switching toauthed_api_requestand appending report fields only when a debug report is present — logic is correct and clean.root.ts): the/logsendpoint now accepts and uploads the context and diagnostics as separate Discord file attachments, with individual section truncation and a final 1900-char cap; the expanded Zod schemas use.passthrough()to stay forward-compatible.feedback.tsx) and email template: the two-step submission flow creates a duplicate-Discord-notification risk on retry, and the full JSON context blob is passed to the email component without a size limit, which can silently fail email delivery for large payloads.Confidence Score: 3/5
Two issues in the submission flow need attention before merging: oversized email payloads can silently fail, and retries generate duplicate Discord alerts.
The Rust and server changes are solid, but the client-side action sends the full tab-indented JSON context (potentially 50–100 KB) directly into the email template with no truncation, which can cause silent delivery failures at the email provider. Separately, the two-step submit design means a transient failure on step 2 leaves the Discord side-effect already fired — retries produce duplicate webhook notifications for the same issue.
apps/desktop/src/routes/(window-chrome)/settings/feedback.tsx(two-step retry logic) andpackages/database/emails/feedback.tsx(unboundeddebugReportfield).Important Files Changed
debugReportJSON blob inline; no size limit means oversized payloads could silently fail email delivery.upload_log_fileintoupload_log_file_with_context, adding optional debug report fields and switching toauthed_api_requestwhen a report is present; logic is correct and clean.upload_debug_reportTauri command and registers it; straightforward delegation tologging.rs./logsendpoint to accept and upload report context/diagnostics as Discord file attachments; expands the diagnostics schema with.passthrough()and adds Discord message formatting helpers with appropriate truncation.reportId,kind, anddebugReportfields to thesubmitFeedbackcontract; non-breaking change.Comments Outside Diff (1)
apps/desktop/src/routes/(window-chrome)/settings/feedback.tsx, line 382-420 (link)sendDebugReportActioncallsinvoke("upload_debug_report")first (which triggers the Discord webhook via/api/desktop/logs) and then callsapiClient.desktop.submitFeedback. If the second call fails (network hiccup, 500, etc.), the user sees the error toast and may click "Send Debug Report" again. Each retry re-fires the Discord webhook with a freshly-generatedreportIdand uploads a new log file to storage, so the support team receives duplicate Discord alerts that look like separate reports for the same issue.Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "feat(desktop): submit debug reports from..." | Re-trigger Greptile