Skip to content

feat: add generic exception telemetry - #5134

Open
pierrealexandre2 wants to merge 1 commit into
webex:nextfrom
pierrealexandre2:piealexa/genericErrorTelemetry
Open

feat: add generic exception telemetry#5134
pierrealexandre2 wants to merge 1 commit into
webex:nextfrom
pierrealexandre2:piealexa/genericErrorTelemetry

Conversation

@pierrealexandre2

Copy link
Copy Markdown

COMPLETES #SPARK-831221

This pull request addresses

Add the capacity to monitor exceptions

by making the following changes

< DESCRIBE YOUR CHANGES >

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

Gather exceptions before sdk ready.
Pump and send exceptions once sdk ready
Send exceptions if sdk ready

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Please Specify Codex
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

Make sure to have followed the contributing guidelines before submitting.

@pierrealexandre2
pierrealexandre2 requested review from a team as code owners July 29, 2026 16:49

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1a0bd4a52

ℹ️ 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".

return undefined;
}

const collector = installGlobalUnhandledExceptionTelemetry({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Skip telemetry when localStorage is unavailable

In browsers where localStorage is disabled or unwritable (for example privacy-restricted contexts, third-party storage blocking, or enterprise policies), PersistentEventQueue throws during its storage probe, and this call is reached by default from NewMetrics construction because the new config enables telemetry by default. That makes Webex.init() fail instead of just skipping optional exception telemetry, unlike the event-target guard above; please catch this installer failure or add a storage-availability guard before installing.

Useful? React with 👍 / 👎.

return;
}

event.metadata = metadata;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Snapshot metadata before queuing it

When an app's getMetadata() returns a mutable object, assigning that object directly means the in-memory queue keeps the same reference until the delayed pump submits it. Because events wait at least the dedupe window before submission, any app-state mutation in that interval changes the metadata reported for the already-captured exception, so telemetry can describe the wrong route/meeting state; store a serialized/deep-cloned snapshot after the size check instead.

Useful? React with 👍 / 👎.

@aws-amplify-us-east-2

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-5134.d3m3l2kee0btzx.amplifyapp.com

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch 2 times, most recently from 08cd78e to b68bd41 Compare July 30, 2026 13:04

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b68bd41513

ℹ️ 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".

const telemetryConfig = webex.config?.metrics?.unhandledExceptionTelemetry;

if (telemetryConfig?.enabled === false) {
uninstallGlobalUnhandledExceptionTelemetry();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Purge queued events when telemetry is disabled

When an application uses the early collector and an exception is captured before Webex.init(), setting metrics.unhandledExceptionTelemetry.enabled: false reaches this branch, but uninstallGlobalUnhandledExceptionTelemetry() only stops listeners/deletes the global symbol and does not remove the webex-unhandled-exception:v1... localStorage entries. Those opt-out events remain on disk and will be drained if telemetry is enabled later in the same origin, so disabling telemetry should also clear the collector's persisted queue.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch 2 times, most recently from abeb352 to 56649f6 Compare August 3, 2026 13:12

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 56649f6c8d

ℹ️ 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".

return !TELEMETRY_SERVICES.has(getService(options));
};

export const createNetworkFailureMetric = (

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wire the network metric into request failures

As added, this helper is not wired to the SDK event that actually reports request failures: I searched the source for createNetworkFailureMetric/NETWORK_REQUEST_FAILURE_METRIC and found only this module and its unit test, while RequestEventInterceptor emits request:failure from packages/@webex/webex-core/src/interceptors/request-event.js at lines 49 and 86. In any real SDK request failure outside the test's manual webex.emit, nothing listens, so JS_SDK_NETWORK_REQUEST_FAILURE is never submitted; please register a request:failure handler in the metrics plugin and call submitClientMetrics with this metric.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from 56649f6 to 15b2290 Compare August 3, 2026 14:33

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 15b229059e

ℹ️ 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".

Comment on lines +557 to +560
existingCollector.updateApplicationContext({
appVersion: options.appVersion,
getMetadata: options.getMetadata,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply SDK limits when adopting the early collector

When an app installs the early collector before SDK load and supplies telemetry limits only in Webex.init, this adoption branch drops every limit option (maxSerializedMetadataBytes, maxEventsPerMinute, maxEvents, maxAgeMs) and only updates appVersion/getMetadata. The existing collector keeps its constructor defaults, so future captured exceptions can include metadata or retain queued events beyond the app's configured bounds; pass these options into the existing collector or require them to be set in the bootstrap.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from 15b2290 to b196322 Compare August 6, 2026 15:58

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b196322211

ℹ️ 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".

try {
const error = {
...details,
message: truncate(details.message, MAX_ERROR_MESSAGE_LENGTH),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Strip URL secrets from messages

When an exception message itself contains a URL with query parameters or fragments, this only truncates details.message before sending it in eventPayload.error.message; for example, a rejected request wrapper can throw GET https://host/path?token=... failed, and that token will be reported even though the stack/resource URL paths are sanitized. Please run messages through the URL-detail sanitizer before truncating/submitting them.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from b196322 to a0fc6db Compare August 7, 2026 08:50

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0fc6dbded

ℹ️ 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".


this.capture({
kind: 'unhandledrejection',
message: typeof reason?.message === 'string' ? reason.message : stringifyReason(reason),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid serializing arbitrary rejection objects

When an unhandled rejection uses a plain object instead of an Error or string, this path JSON-serializes the whole object into eventPayload.error.message; request libraries and app code commonly reject with objects containing URLs, headers, bodies, or IDs, so enabled telemetry can send credentials or PII without any allowlist/redaction. Please avoid stringifying arbitrary rejection reasons, or redact/allowlist object fields before submission.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from a0fc6db to c6c2972 Compare August 7, 2026 09:09

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c6c2972e2b

ℹ️ 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".

Comment on lines +116 to +117
eventTarget.addEventListener('error', (event) => this.captureError(event), true);
eventTarget.addEventListener('unhandledrejection', (event) => this.captureRejection(event));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid installing duplicate global telemetry listeners

When a page creates another SDK instance with telemetry enabled, such as a re-login flow, Webex.init() returns a fresh instance (packages/webex/src/webex.js:79-88) and this constructor adds another permanent window listener without a singleton guard or removeEventListener path. Every later browser error/rejection is then captured and submitted once per previously initialized reporter, so the optional telemetry duplicates events and can keep submitting through stale SDK instances.

Useful? React with 👍 / 👎.

}

function removeUrlDetailsFromText(value: string | undefined): string | undefined {
return value?.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s)]+/gi, (url) => removeUrlDetails(url) ?? url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Sanitize relative URLs before submission

When enabled telemetry captures an exception message or stack containing a relative request URL such as GET /api?token=secret failed, this sanitizer leaves the query/fragment intact because it only matches scheme:// URLs. Fresh evidence beyond the earlier absolute-URL concern is that the current redaction regex still bypasses same-origin relative URLs, so those secrets are copied into eventPayload.error.message or stack before submission.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from c6c2972 to 24b8dd5 Compare August 11, 2026 14:10

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24b8dd50b3

ℹ️ 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".

Comment on lines +358 to +359
if (webex.config?.metrics?.unhandledExceptionTelemetry?.enabled !== true) {
return undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop stale telemetry when disabled

When a page creates a new SDK instance with metrics.unhandledExceptionTelemetry.enabled omitted or set to false after an earlier enabled instance, this early return leaves activeTelemetry installed on window, so subsequent errors are still captured and submitted through the stale SDK even though the current configuration opted out. Please stop and clear any existing reporter before returning for disabled or unsupported telemetry.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from 24b8dd5 to c932ee5 Compare August 12, 2026 06:55

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c932ee5da9

ℹ️ 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".

this.flushTimer = undefined;
}

this.pendingEvents.forEach((event) => this.submit(event));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Drop pending events when telemetry is disabled

When a second Webex.init() uses the default/disabled metrics.unhandledExceptionTelemetry after an earlier enabled instance has captured an error but before the 1s dedupe timer fires, startUnhandledExceptionTelemetry() calls stop() and this line submits the stale reporter’s pending event through the old SDK before returning disabled. Fresh evidence beyond the earlier stale-listener concern is that the listener is now stopped, but stop() still flushes pendingEvents; the opt-out path should clear them instead of submitting.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from c932ee5 to 8eb0b65 Compare August 12, 2026 09:12

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8eb0b65886

ℹ️ 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".

return value
?.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s)]+/gi, (url) => removeUrlDetails(url) ?? url)
.replace(
/(^|[\s("'=[{])((?:\/|\.\.?\/)[^\s)"'\]}]+)/g,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Sanitize bare relative URLs before submitting

When an error message or stack contains a same-origin relative URL without a leading slash or dot, such as GET api/messages?token=secret failed or at load (scripts/app.js?token=secret:10:20), this regex does not match it because it only handles scheme URLs and paths beginning with /, ./, or ../. Those query strings/fragments therefore remain in eventPayload.error.message or stack despite the new sanitizer, so enabled exception telemetry can still leak URL secrets; please cover bare relative path references before truncating/submitting.

Useful? React with 👍 / 👎.

constructor(webex: WebexForUnhandledExceptionTelemetry, eventTarget: BrowserEventTarget) {
this.webex = webex;
this.eventTarget = eventTarget;
eventTarget.addEventListener('error', this.errorListener, true);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

eventTarget.addEventListener('error', this.errorListener, {capture: true});

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from 8eb0b65 to f6f31b5 Compare August 13, 2026 15:47

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f6f31b527d

ℹ️ 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".

}

private captureError(event: any): void {
const resourceUrl = removeUrlDetails(event?.target?.src ?? event?.target?.href);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound resource URLs before submitting

When a resource load failure comes from an element whose src/href is a data: URL or another very long URL path, this keeps the full value; unlike message and stack, resourceUrl is never length-capped or scheme-filtered before it is copied into eventPayload.error.resourceUrl and submitted. An invalid <img src="data:..."> can therefore enqueue arbitrary inline content or oversized payloads into client metrics, so reject non-network schemes or cap the resource URL before capture.

Useful? React with 👍 / 👎.

(_, prefix, url) => `${prefix}${removeUrlDetails(url) ?? url}`
)
.replace(
/(^|[\s("'=[{])((?:[a-z0-9._~%-]+\/)+(?:[a-z0-9._~%-]+)?[?#][^\s)"'\]}]+)/gi,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Sanitize single-segment relative URLs

When an error message or stack contains a same-origin relative URL with no slash, such as GET api?token=secret failed or at load (app.js?token=secret:1:1), this bare-relative matcher does not run because it requires at least one / before [?#]. Those query strings/fragments remain in eventPayload.error.message or stack before submission, so please cover single-segment relative references as well.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from f6f31b5 to 7a3d9cf Compare August 14, 2026 08:57

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7a3d9cf081

ℹ️ 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".

}

function removeUrlDetails(value: unknown): string | undefined {
return typeof value === 'string' && value.length > 0 ? value.split(/[?#]/, 1)[0] : undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Redact URL credentials before telemetry

When an exception message, stack, filename, or resource load URL contains URL userinfo such as https://user:token@host/path, the sanitizers eventually rely on removeUrlDetails(), but this only splits on query strings and fragments. Fresh evidence beyond the prior query/fragment comments is that credentials before the host are outside [?#], so user:token@ is still copied into eventPayload.error.* and submitted; please parse/redact URL userinfo before truncating or storing these fields.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from 7a3d9cf to ba7c533 Compare August 17, 2026 08:52
@gitguardian

gitguardian Bot commented Aug 17, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 5 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - Basic Auth String ee209bf packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ee209bf packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ee209bf packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ee209bf packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ee209bf packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba7c53350c

ℹ️ 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".

};

this.addMetadata(event);
this.pendingEvents.set(fingerprint, event);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cap the number of pending exception events

When an enabled application produces many distinct errors within one second, every fingerprint is inserted into this map, so the deduplication logic provides no bound on memory or submissions. The subsequent flush submits every entry, and the client-metrics batcher sends at most 50 metrics per request, turning an application error cascade into a potentially large burst of telemetry requests; enforce a pending-event or per-minute limit before queuing new fingerprints.

Useful? React with 👍 / 👎.


this.capture({
column: typeof event?.colno === 'number' ? event.colno : undefined,
filename: removeUrlDetails(event?.filename),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound and scheme-filter error filenames

When an uncaught error originates from a data: script or an unusually long source URL, ErrorEvent.filename can contain the entire inline script or an arbitrarily long path. Unlike resource URLs, this field is only stripped at ? or #, so inline source, credentials, or oversized content before those delimiters is copied into eventPayload.error.filename; apply the same scheme filtering and length cap used for resource URLs.

Useful? React with 👍 / 👎.

}

private captureError(event: any): void {
const rawResourceUrl = event?.target?.src ?? event?.target?.href;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prefer currentSrc for responsive resource failures

When an IMG loads a candidate selected from srcset, target.currentSrc identifies the resource that failed while target.src is only the fallback URL and may be empty. This lookup therefore reports the wrong resource URL, or falls through and records an Unknown uncaught error when no fallback src exists; inspect currentSrc before src so responsive-image failures are classified accurately.

Useful? React with 👍 / 👎.

@pierrealexandre2

Copy link
Copy Markdown
Author

⚠️ GitGuardian has uncovered 4 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard. Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.
🔎 Detected hardcoded secrets in your pull request

GitGuardian id GitGuardian status Secret Commit Filename
- - Basic Auth String ba7c533 packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ba7c533 packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ba7c533 packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
- - Basic Auth String ba7c533 packages/@webex/internal-plugin-metrics/test/unit/spec/unhandled-exception-telemetry.ts View secret
🛠 Guidelines to remediate hardcoded secrets

🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Only in unit tests...

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from ba7c533 to 46d79c4 Compare August 17, 2026 09:19

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46d79c44bf

ℹ️ 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".

Comment on lines +258 to +261
error.message,
error.stack,
error.filename,
error.resourceUrl,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include source coordinates in exception fingerprints

When two errors have the same name/message/filename and no stack but originate at different lines or columns within the one-second window, this fingerprint treats them as the same failure even though line and column were captured. The second exception is therefore discarded into the first event's occurrenceCount, and telemetry reports only the first source location; include the available source coordinates in the fingerprint so distinct stackless browser errors remain separate.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from 46d79c4 to c21261c Compare August 17, 2026 09:34

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c21261cadb

ℹ️ 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".

this.capture({
kind: 'unhandledrejection',
message: typeof reason?.message === 'string' ? reason.message : stringifyReason(reason),
name: typeof reason?.name === 'string' ? reason.name : 'UnhandledRejection',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Sanitize and bound custom exception names

When a rejection reason provides a string name, such as {name: 'GET https://host/path?token=secret', message: 'failed'}, this value bypasses the message/stack URL sanitizer and all length limits. It is then submitted in both eventPayload.error.name and the error_name metric field, potentially exposing URL credentials or producing an oversized metric; sanitize and truncate exception names before capture.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from c21261c to b736eef Compare August 17, 2026 10:00

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b736eefb78

ℹ️ 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".

// Examples: https://host/api?token=x -> https://host/api, ../app.js#fragment -> ../app.js,
// api/messages?token=x -> api/messages, and GET app.js?token=x -> GET app.js.
return value
?.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s)]+/gi, (url) => removeUrlDetails(url) ?? url)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Redact non-hierarchical URLs from exception text

When an error message or stack contains a non-hierarchical URL such as data:text/plain,inline-secret or blob:https://example.test/identifier, this matcher ignores it because it requires ://, while the relative-URL matchers do not cover schemes. The complete value is consequently copied into eventPayload.error.message or stack and submitted (up to the truncation limit), so apply the same non-network-scheme filtering or redaction used for resource URLs.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from b736eef to c578c12 Compare August 17, 2026 12:08

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c578c1236c

ℹ️ 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".

// https://host/api, api/messages?token=x -> api/messages, and GET app.js?token=x -> GET app.js.
return value
?.replace(
/(^|[\s("'[{,;])(([a-z][a-z0-9+.-]*):[^\s)"'\]}]+)/gi,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Sanitize URLs after assignment delimiters

When an exception formats a URL as an assigned value, such as url=https://host/path?token=secret or payload=data:text/plain,secret, this matcher does not run because its allowed prefix characters omit =; the later relative-URL matcher cannot match these scheme URLs either. The complete query, credentials, or non-network URL is therefore copied into the submitted message/stack, so include assignment and similar value delimiters in the absolute-URL sanitizer.

Useful? React with 👍 / 👎.

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from c578c12 to a69ac9a Compare August 17, 2026 14:29

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a69ac9afea

ℹ️ 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".


this.capture({
kind: 'unhandledrejection',
message: typeof reason?.message === 'string' ? reason.message : stringifyReason(reason),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Contain failures while reading rejection reasons

When a promise is rejected with a Proxy or other object whose message, name, or stack getter throws, these property reads execute in the global unhandledrejection listener before entering the guarded capture() method. The reporter therefore throws its own uncaught exception while handling the original rejection, potentially generating a secondary error event and affecting the host application; wrap rejection-detail extraction in the same containment boundary as capture/submission.

Useful? React with 👍 / 👎.

@Coread Coread left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please see comments

Comment thread .gitignore Outdated
docs/samples/webex.min.js.map
docs/samples/meetings.min.js
docs/samples/meetings.min.js.map
docs/samples/contact-center.min.js

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: Is this part of the current commit? If not it is best added in a separate PR

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This file kept popping out in the diff, every time I run the build. I can remove it

overrides: this.delayedClientEventsOverrides,
});
// @ts-ignore
startUnhandledExceptionTelemetry(this.webex);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

issue: need a test that checks that startUnhandledExceptionTelemetry is called when ready


## Unhandled exception telemetry

Browser exception telemetry starts after the Webex SDK emits `ready`. It does not install a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thought: The SDK is designed to support both browser and node-js. It is probably worth mentioning explicitly that this unhandled exception telemetry is currently only supported in a browser environment

};
};

function truncate(value: string | undefined, maxLength: number): string | undefined {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion: All these utilities are better tested separately with separate unit tests. You can get easier/better coverage that way


try {
Promise.resolve(
submitClientMetrics.call(this.webex.internal?.metrics, UNHANDLED_EXCEPTION_METRIC_NAME, {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

issue: This is unable to submit metrics prior to auth because it does not pass in a preloginId. If a preloginId is supplied, submitClientMetrics calls the preloginMetrics batcher rather than the logged in version. Right now, errors thrown before sign in will be silently failing to send

},
eventPayload: event,
})
).catch(() => undefined);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion: I don't think that catching and doing nothing about errors when failing to send it necessarily the best idea. Perhaps a log message at least? We do want to know if/when this system starts failing

const MAX_RESOURCE_URL_LENGTH = 2_048;
const MAX_STACK_LENGTH = 8_192;

type BrowserEventTarget = {

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.

Why do you need this type? dom.d.ts has a built in EventTarget type, please use that instead.

If you must use this type, please fix it. addEventListener and removeEventListener has identical parameter list, but here the 3. param type is different.

// Examples: data:text/plain,secret -> [redacted-url], https://host/api?token=x ->
// https://host/api, api/messages?token=x -> api/messages, and GET app.js?token=x -> GET app.js.
return value
?.replace(

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.

question: could you please add 1-2 lines of comment for each replace to se which one is handling which case.

private readonly pendingEvents = new Map<string, UnhandledExceptionEvent>();
private readonly eventTarget: BrowserEventTarget;
private readonly errorListener = (event: any) => this.captureError(event);
private readonly rejectionListener = (event: any) => this.captureRejection(event);

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.

the event has a proper type: PromiseRejectionEvent

class UnhandledExceptionTelemetry {
private readonly pendingEvents = new Map<string, UnhandledExceptionEvent>();
private readonly eventTarget: BrowserEventTarget;
private readonly errorListener = (event: any) => this.captureError(event);

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.

The event has a proper type: ErrorEvent

this.webex = webex;
this.eventTarget = eventTarget;
eventTarget.addEventListener('error', this.errorListener, true);
eventTarget.addEventListener('unhandledrejection', this.rejectionListener);

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.

for better consistency you should use the capture phase for unhandledrejection as well. Do not forgot to update the removeEventListener as well

*/
class UnhandledExceptionTelemetry {
private readonly pendingEvents = new Map<string, UnhandledExceptionEvent>();
private readonly eventTarget: BrowserEventTarget;

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.

error and unhandledrejection emitted only from the global object, so you can do this instead:

Suggested change
private readonly eventTarget: BrowserEventTarget;
private readonly eventTarget: Window | Worker;

this.pendingEvents.clear();
}

private captureError(event: any): void {

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.

Suggested change
private captureError(event: any): void {
private captureError(event: ErrorEvent): void {

column: typeof event?.colno === 'number' ? event.colno : undefined,
filename: removeUrlDetails(event?.filename),
kind: 'error',
line: typeof event?.lineno === 'number' ? event.lineno : undefined,

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.

is typeof necessary here? when lineno is not number then it must be `undefined. so this should do it:

Suggested change
line: typeof event?.lineno === 'number' ? event.lineno : undefined,
line: event?.lineno,

same for stack

const now = new Date().getTime();
let nextFlushInMs: number | undefined;

this.flushTimer = undefined;

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.

issue: please clear the timeout before drop the timer

@pierrealexandre2
pierrealexandre2 force-pushed the piealexa/genericErrorTelemetry branch from a69ac9a to ee209bf Compare August 18, 2026 14:44

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee209bf0e7

ℹ️ 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".

Comment on lines +208 to +210
name: truncate(removeUrlDetailsFromText(details.name), MAX_ERROR_NAME_LENGTH) ?? 'Error',
message: truncate(removeUrlDetailsFromText(details.message), MAX_ERROR_MESSAGE_LENGTH),
stack: truncate(removeUrlDetailsFromText(details.stack), MAX_STACK_LENGTH),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound exception text before running URL sanitizers

When an uncaught error supplies a very large name, message, or stack, these expressions run four global regex replacements over the complete strings and allocate replacement copies before applying the advertised 256/4096/8192-character limits. A large server response embedded in an Error message can therefore stall the global error handler or cause substantial transient memory usage even though almost all of the input is discarded; bound the amount of text processed by the sanitizer as well as the submitted output.

Useful? React with 👍 / 👎.

},
eventPayload: event,
},
this.webex.canAuthorize === true ? undefined : this.preLoginId

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid overwriting the shared pre-login identifier

When an anonymous exception flushes while another submitClientMetrics(..., appPreLoginId) call is waiting in the metrics batcher, passing this reporter-specific UUID changes the identifier for the shared clientMetricsPreloginBatcher. prelogin-metrics-batcher.ts stores only one mutable preLoginId and applies it to the entire batched request, so metrics queued under the application's identifier can be sent under this unrelated UUID (or telemetry can be sent under a later caller's ID); use the application's stable pre-login identity or isolate batches by identifier.

Useful? React with 👍 / 👎.

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.

3 participants