Skip to content

🐛 honor strictest allowUntrustedEvents policy in XHR observable#4604

Open
thomas-lebeau wants to merge 1 commit into
v7from
thomas.lebeau/fix-xhr-untrusted-events-singleton
Open

🐛 honor strictest allowUntrustedEvents policy in XHR observable#4604
thomas-lebeau wants to merge 1 commit into
v7from
thomas.lebeau/fix-xhr-untrusted-events-singleton

Conversation

@thomas-lebeau
Copy link
Copy Markdown
Collaborator

Motivation

Addresses a P2 review comment on #4425.

initXhrObservable is a singleton initialized by its first caller. In v7, bufferedData.ts calls it during early SDK setup with { allowUntrustedEvents: true } — well before the customer configuration is available. The subsequent initXhrObservable(configuration) call from rum-core/requestCollection.ts silently reused the existing singleton, discarding the customer's stricter allowUntrustedEvents: false (the default).

As a result, application code that dispatches synthetic loadend events on an XMLHttpRequest could be reported as completed XHRs (fake resources / network errors) even for customers who never enabled untrusted events.

Changes

  • packages/core/src/browser/xhrObservable.ts: track every caller's allowUntrustedEvents policy in a module-level array. The trust filter in the loadend listener now evaluates the strictest policy (every caller must allow) at event time. This mirrors the per-subscriber pattern already used by initFetchObservable's responseBodyActionGetters.
  • packages/core/src/browser/xhrObservable.spec.ts: two new tests covering the conflicting-policy scenario — one verifies that an untrusted loadend is filtered when the customer disallows it (the bug), and one verifies that it passes through when every caller allows it.

Scope nuance: the trust filter only gates the loadend fallback listener. The primary completion path via onreadystatechange instrumentation is unaffected (it's function-call interception, not a DOM event). Fetch is unaffected — initFetchObservable doesn't take a trust parameter.

Test instructions

  • yarn test:unit --spec packages/core/src/browser/xhrObservable.spec.ts — the two new tests under with conflicting allowUntrustedEvents policies across callers pass. Reverting xhrObservable.ts to main (singleton-only) makes the "does not emit completion …" test fail with a spurious completion event.
  • yarn test:unit — full suite stays green (939 core + 1390 rum-core tests).
  • yarn typecheck / yarn lint clean.

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

@cit-pr-commenter-54b7da
Copy link
Copy Markdown

cit-pr-commenter-54b7da Bot commented May 11, 2026

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 169.26 KiB 169.32 KiB +70 B +0.04%
Rum Profiler 5.97 KiB 5.97 KiB 0 B 0.00%
Rum Recorder 21.23 KiB 21.23 KiB 0 B 0.00%
Logs 54.56 KiB 54.66 KiB +102 B +0.18%
Rum Slim 127.59 KiB 127.66 KiB +69 B +0.05%
Worker 22.99 KiB 22.99 KiB 0 B 0.00%
🚀 CPU Performance
Action Name Base CPU Time (ms) Local CPU Time (ms) 𝚫%
RUM - add global context 0.0018 0.0022 +22.22%
RUM - add action 0.0112 0.0167 +49.11%
RUM - add error 0.0102 0.0161 +57.84%
RUM - add timing 0.0005 0.0006 +20.00%
RUM - start view 0.0101 0.0131 +29.70%
RUM - start/stop session replay recording 0.0007 0.0009 +28.57%
Logs - log message 0.0172 0.0275 +59.88%
🧠 Memory Performance
Action Name Base Memory Consumption Local Memory Consumption 𝚫
RUM - add global context 38.90 KiB 42.67 KiB +3.78 KiB
RUM - add action 62.40 KiB 68.20 KiB +5.80 KiB
RUM - add timing 37.14 KiB 35.87 KiB -1.27 KiB
RUM - add error 67.68 KiB 68.38 KiB +715 B
RUM - start/stop session replay recording 41.66 KiB 39.98 KiB -1.68 KiB
RUM - start view 484.99 KiB 484.27 KiB -742 B
Logs - log message 54.21 KiB 54.45 KiB +250 B

🔗 RealWorld

@datadog-prod-us1-3
Copy link
Copy Markdown

datadog-prod-us1-3 Bot commented May 11, 2026

Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

🎯 Code Coverage (details)
Patch Coverage: 83.33%
Overall Coverage: 77.47% (-0.00%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: ad75fb2 | Docs | Datadog PR Page | Give us feedback!

@thomas-lebeau thomas-lebeau force-pushed the thomas.lebeau/fix-xhr-untrusted-events-singleton branch from a70315f to 3fdfac1 Compare May 12, 2026 06:25
The XHR observable is a singleton initialized by the first caller. In v7,
bufferedData calls `initXhrObservable({ allowUntrustedEvents: true })` early
during SDK setup, before the customer config is parsed. The later
`initXhrObservable(configuration)` call from rum-core's requestCollection
silently reused that singleton — discarding the customer's stricter
`allowUntrustedEvents: false`. As a result, application code dispatching
synthetic `loadend` events could be reported as completed XHRs (fake
resources/network errors) even when the customer disabled untrusted events.

Track every caller's policy and evaluate the strictest (every must allow)
at event time. Mirrors the per-subscriber pattern used by initFetchObservable.
@thomas-lebeau thomas-lebeau force-pushed the thomas.lebeau/fix-xhr-untrusted-events-singleton branch from 3fdfac1 to ad75fb2 Compare May 12, 2026 06:29
@thomas-lebeau thomas-lebeau marked this pull request as ready for review May 12, 2026 06:33
@thomas-lebeau thomas-lebeau requested a review from a team as a code owner May 12, 2026 06:33
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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: ad75fb274f

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +43 to +45
if (configuration.allowUntrustedEvents !== undefined) {
allowUntrustedEvents = configuration.allowUntrustedEvents
}
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 Preserve opt-out when a later caller opts in

When any later caller passes { allowUntrustedEvents: true }, this assignment overwrites a prior customer opt-out, so XHRs sent after that point capture true in the loadend listener and synthetic loadend events are accepted. This can happen, for example, if RUM has already initialized with the default false and another SDK/public API starts buffering data later (startBufferingData() calls initXhrObservable({ allowUntrustedEvents: true })); the stricter policy is then lost until another false call happens, contrary to the singleton needing to honor all subscribers' policies.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

it's fine, it's not expected to have the SDK initialize more that once

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