-
Notifications
You must be signed in to change notification settings - Fork 98
[AB-738] Implement FE/BE crash reports & metrix #1212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
0a56d36
cd45c2d
c001690
d113cbd
9624b0d
4912adf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| VITE_SENTRY_DSN=https://6c13c3260114c5b1ceb3b6ae58d0cdb3@o1026471.ingest.us.sentry.io/4510398008393728 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify .env file is not committed to version control. The Sentry DSN is exposed in this .env file. While the DSN is a public key, environment files should typically not be committed to version control as they can contain sensitive configuration. Ensure this file is properly listed in .gitignore, or consider using environment variables at runtime instead. 🏁 Script executed: #!/bin/bash
# Check if .env is in .gitignore
grep -r "^\.env$" .gitignore
# Check if this .env file is tracked by git
git ls-files src/ui/.envLength of output: 11 Let me verify the .gitignore status to ensure we have complete information: Length of output: 42 Length of output: 407 Length of output: 425 Remove src/ui/.env from version control and add it to .gitignore. The .env file containing the Sentry DSN is currently tracked by git and is not listed in .gitignore. This violates security best practices and exposes environment configuration in version control history. Add 🤖 Prompt for AI AgentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Sentry DSN (Data Source Name) is hardcoded and committed to version control. This credential should be treated as a secret. Anyone with repository access can view this DSN, and it remains in git history even if removed in future commits. While Sentry DSNs are designed for client-side use (write-only), exposing them allows malicious actors to send false error reports to your project, potentially causing rate limit issues and polluting your error tracking data. Committing environment-specific configuration files violates the principle of separating configuration from code. This DSN appears to be for production, which means developers might accidentally send development errors to production Sentry. Remediation: Add Configure actual values through your deployment platform's environment variables (Vercel, Netlify, AWS, etc.). Remove
🔺 Vulnerability (Error) |
||
| VITE_SENTRY_ENABLED=true | ||
| VITE_SENTRY_ENVIRONMENT=production | ||
| VITE_SENTRY_TRACES_SAMPLE_RATE=1.0 | ||
| VITE_SENTRY_REPLAY_SAMPLE_RATE=0.1 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,3 +71,5 @@ export function useBlueprintNodeTools( | |
| hasToolsButNoFunctionTools, | ||
| }; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import { trackError } from "@/observability/frontendMetrics"; | ||
|
|
||
| let isInitialized = false; | ||
| let errorHandlerRef: ((event: ErrorEvent) => void) | null = null; | ||
| let rejectionHandlerRef: ((event: PromiseRejectionEvent) => void) | null = null; | ||
|
|
||
| function extractError(error: unknown): Error { | ||
| if (error instanceof Error) { | ||
| return error; | ||
| } | ||
| if (typeof error === "string") { | ||
| return new Error(error); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Error messages might include stack traces, large JSON payloads, or extensive debugging information. Without length limits, this creates a DoS vector where triggered errors with arbitrarily large messages could exhaust resources. Remediation: Implement maximum length validation: const MAX_ERROR_LENGTH = 1500;
function extractError(error: unknown): Error {
if (error instanceof Error) {
if (error.message.length > MAX_ERROR_LENGTH) {
error.message = error.message.substring(0, MAX_ERROR_LENGTH) + '... (truncated)';
}
return error;
}
let msg = typeof error === "string" ? error : String(error || "Unknown error");
if (msg.length > MAX_ERROR_LENGTH) {
msg = msg.substring(0, MAX_ERROR_LENGTH) + '... (truncated)';
}
return new Error(msg);
}
🔸 Vulnerability (Warning) |
||
| } | ||
| return new Error(String(error || "Unknown error")); | ||
| } | ||
|
|
||
| function handleError(event: ErrorEvent): void { | ||
| try { | ||
| const error = extractError(event.error || event.message); | ||
| trackError(error, error.name || "window_error"); | ||
| } catch (trackingError) { | ||
| console.error("Failed to track error:", trackingError); | ||
| } | ||
| } | ||
|
|
||
| function handleUnhandledRejection(event: PromiseRejectionEvent): void { | ||
| try { | ||
| const error = extractError(event.reason); | ||
| trackError(error, "unhandled_promise_rejection"); | ||
| } catch (trackingError) { | ||
| console.error("Failed to track promise rejection:", trackingError); | ||
| } | ||
| } | ||
|
|
||
| export function setupGlobalErrorHandling(): void { | ||
| if (typeof window === "undefined") { | ||
| return; | ||
| } | ||
|
|
||
| if (isInitialized) { | ||
| console.warn("Global error handling already initialized"); | ||
| return; | ||
| } | ||
|
|
||
| errorHandlerRef = handleError; | ||
| rejectionHandlerRef = handleUnhandledRejection; | ||
|
|
||
| window.addEventListener("error", errorHandlerRef); | ||
| window.addEventListener("unhandledrejection", rejectionHandlerRef); | ||
|
|
||
| isInitialized = true; | ||
| } | ||
|
|
||
| export function teardownGlobalErrorHandling(): void { | ||
| if (typeof window === "undefined" || !isInitialized) { | ||
| return; | ||
| } | ||
|
|
||
| if (errorHandlerRef) { | ||
| window.removeEventListener("error", errorHandlerRef); | ||
| errorHandlerRef = null; | ||
| } | ||
|
|
||
| if (rejectionHandlerRef) { | ||
| window.removeEventListener("unhandledrejection", rejectionHandlerRef); | ||
| rejectionHandlerRef = null; | ||
| } | ||
|
|
||
| isInitialized = false; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,40 @@ | ||
| /* eslint-disable no-console */ | ||
|
|
||
| import { observabilityRegistry } from "@/observability"; | ||
|
|
||
| export type ILogger = Pick<typeof console, "log" | "warn" | "info" | "error">; | ||
|
|
||
| /** | ||
| * A simple abstraction to use logger in the application. For the moment, it's just a proxy to `console`, but it can be plugged to any library later. | ||
| */ | ||
| export function useLogger(): ILogger { | ||
| const provider = observabilityRegistry.getInitializedProvider(); | ||
|
|
||
| return { | ||
| log: console.log, | ||
| warn: console.warn, | ||
| info: console.info, | ||
| error: console.error, | ||
| warn: (...args: any[]) => { | ||
| console.warn(...args); | ||
| if (provider && args.length > 0) { | ||
| const message = | ||
| typeof args[0] === "string" ? args[0] : String(args[0]); | ||
| provider.captureMessage(message, "warning", { | ||
| source: "logger", | ||
| component: "useLogger", | ||
| args: args.slice(1), | ||
| }); | ||
| } | ||
| }, | ||
| error: (...args: any[]) => { | ||
| console.error(...args); | ||
| if (provider && args.length > 0) { | ||
| const error = | ||
| args[0] instanceof Error | ||
| ? args[0] | ||
| : new Error(String(args[0])); | ||
| provider.captureException(error, { | ||
| source: "logger", | ||
| component: "useLogger", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error method passes all additional arguments to the observability provider as context without sanitization. Developers often include user objects, request payloads, or application state when logging errors. If any of this context contains passwords, API keys, tokens, PII, or other sensitive data, it will be sent to Sentry and accessible to all team members. This violates data protection regulations and creates a security liability. Once sensitive data enters Sentry, it may be retained for extended periods with less stringent access controls than production databases. Remediation: Sanitize arguments before sending to observability: const SENSITIVE = /password|secret|token|key|auth|api[-_]?key/i;
function sanitizeArgs(args: any[]): any[] {
return args.slice(0, 5).map(arg => {
if (typeof arg === 'string') {
return arg.substring(0, 500);
}
if (arg && typeof arg === 'object') {
const clean: any = {};
for (const [k, v] of Object.entries(arg).slice(0, 20)) {
clean[k] = SENSITIVE.test(k) ? '[REDACTED]' : v;
}
return clean;
}
return arg;
});
}Apply the same sanitization to the warn method at line 21.
🔸 Vulnerability (Warning) |
||
| args: args.slice(1), | ||
| }); | ||
| } | ||
| }, | ||
| }; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to use
config.js. You can take a look at this PR which does that: https://github.com/WriterInternal/fs.agent-flow/pull/89 .IMO, it needs to be a new hook like