Skip to content

feat(otlp): added CORS support - #2336

Draft
lucastemb wants to merge 1 commit into
mainfrom
lt/otlp-cors-config
Draft

feat(otlp): added CORS support#2336
lucastemb wants to merge 1 commit into
mainfrom
lt/otlp-cors-config

Conversation

@lucastemb

Copy link
Copy Markdown
Contributor

Summary

Added support for the otlp_config.http.cors sub-config.

Change Type

  • Bug fix
  • New feature
  • Non-functional (chore, refactoring, docs)
  • Performance

How did you test this PR?

Unit tests

References

@dd-octo-sts dd-octo-sts Bot added area/components Sources, transforms, and destinations. area/docs Reference documentation. source/otlp OTLP source. relay/otlp labels Aug 13, 2026
@pr-commenter

pr-commenter Bot commented Aug 13, 2026

Copy link
Copy Markdown

Regression Detector (Agent Data Plane)

Run ID: 77864861-79b6-4736-8632-fd699aaa868d
Baseline: 0f47357a · Comparison: bc6fdcd2 · diff

Optimization Goals: ✅ No significant changes detected

Fine details of change detection per experiment (5)

Experiments configured erratic: true are tagged (ignored) and skipped when determining which experiments regressed or improved. Experiments which are detected as erratic at runtime are tagged (erratic) to flag that the run's sample dispersion was high, but their regression / improvement signal still counts.

experiment goal Δ mean % links
quality_gates_rss_dsd_medium memory ⚪ +0.72 metrics profiles logs
quality_gates_rss_idle memory ⚪ +0.70 metrics profiles logs
quality_gates_rss_dsd_heavy memory ⚪ +0.64 metrics profiles logs
quality_gates_rss_dsd_low memory ⚪ +0.63 metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory ⚪ +0.25 metrics profiles logs
Bounds Checks: ✅ Passed (5)
experiment check replicates observed links
quality_gates_rss_dsd_heavy memory_usage 10/10 ✅ 227 MiB ≤ 250 MiB metrics profiles logs
quality_gates_rss_dsd_low memory_usage 10/10 ✅ 51.5 MiB ≤ 60 MiB metrics profiles logs
quality_gates_rss_dsd_medium memory_usage 10/10 ✅ 91.5 MiB ≤ 100 MiB metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory_usage 10/10 ✅ 390 MiB ≤ 420 MiB metrics profiles logs
quality_gates_rss_idle memory_usage 10/10 ✅ 31.9 MiB ≤ 40 MiB metrics profiles logs
Explanation

A change is flagged as a regression when |Δ mean %| > 5.00% in the regressing direction for its optimization goal AND SMP marks the experiment as a regression (is_regression: true). Improvements use the matching criteria for the improving direction. Experiments configured erratic: true (tagged (ignored)) are skipped outright; experiments detected as erratic at runtime (tagged (erratic)) still count, since that flag describes sample dispersion rather than directional certainty. The Δ mean % cell is colored accordingly: 🟢 = improvement, 🔴 = regression, ⚪ = neutral. Reduction in CPU or memory is an improvement; reduction in ingress throughput is a regression. Experiments tagged (no analysis) show ⚠️ n/a: SMP ran them but produced no analysis, usually because a replicate failed and exhausted its retries. Check the SMP report for that experiment's replicate failures.

Base automatically changed from lt/2283 to main August 14, 2026 15:34
@lucastemb
lucastemb force-pushed the lt/otlp-cors-config branch from d6c5f02 to bc6fdcd Compare August 14, 2026 20:55
@pr-commenter

pr-commenter Bot commented Aug 14, 2026

Copy link
Copy Markdown

Binary Size Analysis (Agent Data Plane)

Baseline: 0f47357 · Comparison: bc6fdcd · diff
Analysis Configuration: stripped binaries · Pass/Fail Threshold: +5%
Sizes: 41.27 MiB (baseline) vs 41.46 MiB (comparison)
Size Change: +195.16 KiB (+0.46%)

✅ Binary size difference within threshold

Changes by Module
Module File Size Symbols
tracing +140.85 KiB 98
saluki_common::resource_tracking::groups -139.10 KiB 39
core +84.60 KiB 9855
hyper +24.77 KiB 262
serde_core -24.76 KiB 780
serde_with +23.49 KiB 47
anon.e5f4c9df0a419875f27443f75b25e8d8.939.llvm.8887706276972916938 +18.48 KiB 1
tower_http +18.46 KiB 11
anon.a0ca6a6a6723caf97f9e22a220a3e9ae.917.llvm.12682091795628431370 -18.14 KiB 1
anon.6c8cc82583d787f2710e1f8f86e78987.13.llvm.13314861055718887123 -17.17 KiB 1
anon.f69797dabbd49a2170f83101acbb7c03.13.llvm.10454670247825227591 +17.17 KiB 1
hyper_util -16.19 KiB 47
figment +15.19 KiB 181
axum +13.56 KiB 345
saluki_components::common::datadog -12.27 KiB 511
anon.54098a5604e71afbcee4c958c0ab0ff9.975.llvm.4980247667417168617 +12.11 KiB 1
anon.eaa35ebdc5998855717b6f667ad22404.791.llvm.3148331925466594304 -11.93 KiB 1
alloc +11.77 KiB 1524
otlp_protos::otlp_include::opentelemetry -11.29 KiB 195
rmp +10.80 KiB 39
Detailed Symbol Changes
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  +0.9%  +140Ki  +0.8%  +101Ki    [37167 Others]
  [NEW] +59.5Ki  [NEW] +59.4Ki    saluki_components::common::datadog::io::run_endpoint_io_loop::_{{closure}}::h19d5805f97cd6f73
  [NEW] +42.3Ki  [NEW] +42.2Ki    agent_data_plane::cli::run::handle_run_command::_{{closure}}::h6efc9ed4a7774226
  [NEW] +40.5Ki  [NEW] +40.4Ki    agent_data_plane::cli::run::create_topology::_{{closure}}::hebabaa42ad1914d4
  [NEW] +39.3Ki  [NEW] +39.1Ki    _<saluki_components::forwarders::otlp::OtlpForwarder as saluki_core::components::forwarders::Forwarder>::run::_{{closure}}::h6bc96c84d0eea042
  [NEW] +36.5Ki  [NEW] +36.3Ki    _<saluki_components::transforms::aggregate::Aggregate as saluki_core::components::transforms::Transform>::run::_{{closure}}::h7c4a7362740e1fec
  [NEW] +33.6Ki  [NEW] +33.4Ki    _<saluki_components::transforms::apm_stats::ApmStats as saluki_core::components::transforms::Transform>::run::_{{closure}}::h0a265e3bfa1a50af
  [NEW] +32.3Ki  [NEW] +32.2Ki    saluki_components::sources::otlp::metrics::translator::OtlpMetricsTranslator::translate_metrics::h9447635813ba995a
  [NEW] +30.1Ki  [NEW] +30.0Ki    agent_data_plane::cli::dogstatsd::run_dogstatsd_command::_{{closure}}::h6c9451111db7e46e
  [NEW] +28.5Ki  [NEW] +28.4Ki    agent_data_plane::dogstatsd_contexts::artifact::for_each_record::h7e316c27bdcb8e32
  [NEW] +26.9Ki  [NEW] +26.6Ki    _<saluki_components::sources::dogstatsd::_::<impl serde_core::de::Deserialize for saluki_components::sources::dogstatsd::DogStatsDConfiguration>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map::h00d4e7c229f1308c
  [NEW] +26.7Ki  [NEW] +26.5Ki    core::ptr::drop_in_place<agent_data_plane::cli::run::handle_run_command::{{closure}}>::h6b538167ee42782c
  [DEL] -26.7Ki  [DEL] -26.5Ki    core::ptr::drop_in_place<agent_data_plane::cli::run::handle_run_command::{{closure}}>::hac8ba744a6354ad7
  [DEL] -28.5Ki  [DEL] -28.3Ki    agent_data_plane::dogstatsd_contexts::artifact::for_each_record::h39b2832027986acc
  [DEL] -30.6Ki  [DEL] -30.4Ki    agent_data_plane::cli::dogstatsd::run_dogstatsd_command::_{{closure}}::h8e6a26bba5766166
  [DEL] -35.5Ki  [DEL] -35.2Ki    _<saluki_components::sources::dogstatsd::_::<impl serde_core::de::Deserialize for saluki_components::sources::dogstatsd::DogStatsDConfiguration>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map::h6a606a7931ae90c3
  [DEL] -38.5Ki  [DEL] -38.3Ki    _<saluki_components::transforms::aggregate::Aggregate as saluki_core::components::transforms::Transform>::run::_{{closure}}::h5212ad494e6e6d30
  [DEL] -39.5Ki  [DEL] -39.3Ki    _<saluki_components::forwarders::otlp::OtlpForwarder as saluki_core::components::forwarders::Forwarder>::run::_{{closure}}::hcd2e7e0448ed9644
  [DEL] -40.3Ki  [DEL] -40.2Ki    agent_data_plane::cli::run::create_topology::_{{closure}}::h23953cd93c271a64
  [DEL] -42.2Ki  [DEL] -42.1Ki    agent_data_plane::cli::run::handle_run_command::_{{closure}}::h8c5bc31d01253285
  [DEL] -60.1Ki  [DEL] -59.9Ki    saluki_components::common::datadog::io::run_endpoint_io_loop::_{{closure}}::hd9fc277b29cf0b9d
  +0.5%  +195Ki  +0.4%  +155Ki    TOTAL

@lucastemb
lucastemb marked this pull request as ready for review August 14, 2026 21:09
@lucastemb
lucastemb requested a review from a team as a code owner August 14, 2026 21: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: bc6fdcd225

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

/// characters (for example, `http://*.domain.com` matches `http://foo.domain.com`). Only the
/// first `*` is treated as a wildcard; additional `*` characters become literal suffix.
fn build_cors_layer(cors: &Cors) -> CorsLayer {
let mut layer = CorsLayer::new();

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 Allow POST in CORS preflight responses

When a browser exporter sends OTLP using application/json or application/x-protobuf, it preflights the POST request. CorsLayer::new() starts with no allowed methods, and this builder never calls allow_methods, so the preflight response omits permission for POST and the browser blocks the upload despite the configured origin; add POST to the layer's allowed methods.

Useful? React with 👍 / 👎.

Comment on lines +230 to +233
let has_wildcard = cors.allowed_origins.iter().any(|o| o.contains('*'));

if has_wildcard {
layer = layer.allow_origin(Any);

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 Match partial origin wildcards instead of allowing every origin

For a partial-wildcard configuration such as http://*.example.com, this contains('*') check selects Any, so an unrelated origin such as https://evil.example receives CORS permission and can submit telemetry. Only a bare * should enable allow-all; partial wildcards need the documented prefix/suffix matching that the test-only helper currently implements.

Useful? React with 👍 / 👎.

Comment on lines +262 to +266
/// Origins allowed to make cross-origin requests. Allows for wildcard character when describing
/// domains (for example: "http://*.domains.com")
///
/// Defaults to an empty list (disabling CORS).
pub allowed_origins: Vec<String>,

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 Document operator guidance for every CORS field

The new public CORS settings describe their mechanics and mostly their defaults, but none explains which operators or workloads should change them; allowed_origins also fails to document the security-relevant bare-* boundary. Add actionable operator guidance and complete edge-case documentation for all four fields as required for configuration fields.

AGENTS.md reference: AGENTS.md:L149-L154

Useful? React with 👍 / 👎.

@datadog-datadog-prod-us1-2 datadog-datadog-prod-us1-2 Bot left a comment

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.

Datadog Autotest: FAIL

A configured partial wildcard such as http://*.example.com currently activates allow_origin(Any), allowing browser OTLP submissions from unrelated origins. The new matcher tests do not protect this path because the matcher is test-only and never used by the CORS layer.

Open Bits AI session

🤖 Datadog Autotest · Commit bc6fdcd · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

let mut layer = CorsLayer::new();

// Origins. `rs/cors` treats any `*` in the list as allow-all.
let has_wildcard = cors.allowed_origins.iter().any(|o| o.contains('*'));

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.

P1 Preserve partial-wildcard origin restrictions

Operators attempting to restrict browser OTLP ingestion to a domain family instead expose the receiver to requests from every web origin.

Assertion details
  • Input: Configure otlp_config.receiver.protocols.http.cors.allowed_origins with a documented partial wildcard such as http://*.example.com.
  • Expected: Only a bare * should permit every origin. Partial wildcards must replace zero or more characters while retaining their configured prefix and suffix, as required by the checked-in CORS schema.
  • Actual: Every configured origin containing * selects allow_origin(Any). Consequently, http://*.example.com also permits an unrelated origin such as http://attacker.example. The adjacent wildcard_match helper is compiled only for tests and is never called by the CORS layer. A complete fix must reserve Any for a bare *, compile the matcher for production, wire partial patterns into an origin predicate, and make the existing tests exercise the resulting layer; those non-contiguous changes are not suitable for one inline suggestion.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@lucastemb
lucastemb marked this pull request as draft August 14, 2026 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/components Sources, transforms, and destinations. area/docs Reference documentation. relay/otlp source/otlp OTLP source.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant