Skip to content

feat(capabilities): inject container-id/entity-id/external-env headers#166

Merged
bengl merged 1 commit into
mainfrom
bengl/entity-headers
Jul 9, 2026
Merged

feat(capabilities): inject container-id/entity-id/external-env headers#166
bengl merged 1 commit into
mainfrom
bengl/entity-headers

Conversation

@bengl

@bengl bengl commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Native (wasm) trace export never sent Datadog-Container-ID / Datadog-Entity-ID / Datadog-External-Env: libdatadog's entity detection (libdd-common entity_id) is gated #[cfg(unix)] and inert on wasm32, and DD_EXTERNAL_ENV is unreachable from wasm. System-tests expect these headers.

What

Detect the entity headers in the Node HTTP transport (crates/capabilities/src/http_transport.js) — Node can read /proc and process.env — and rewrite the Rust-rendered HTTP/1.1 request head to carry them. This is the wasm analog of the headers native libdatadog adds via Endpoint::set_standard_headers.

  • detectEntityHeaders() mirrors dd-trace-js's exporters/common/docker.js (the proven legacy-exporter path) and libdd-common's compute_entity_id (ci-<container_id> else in-<cgroup_inode>); external-env from DD_EXTERNAL_ENV. Cached (values are process-stable).
  • applyEntityHeaders() rewrites the pre-rendered head: it drops any existing line for a name it sets — so libdatadog's empty datadog-container-id is replaced, not duplicated — appends the detected headers, and preserves the request line + framing (Host, Content-Length) byte-for-byte (latin1 round-trip). Returns the head untouched when nothing is detected or the head is malformed.
  • DD_EXTERNAL_ENV is rejected if it contains CR/LF or non-ASCII, to avoid header injection (native libdatadog rejects invalid bytes via HeaderValue).

Why here (not Rust)

The head is rendered in Rust but wasm cannot read /proc/env; the Node transport is the only layer with both the rendered head and OS access. No upstream-libdatadog or dd-trace-js change is required — consumers pick this up on the next release.

Tests

test/http_transport.js (pre-existing observer + UDS tests preserved): detection (docker id, in-<inode> fallback, external-env, CR/LF rejection, empty case), head rewrite (append + framing preservation, empty-container-id dedup, no-op, malformed passthrough), and a real-transport E2E asserting datadog-external-env lands on the wire through the rewritten head.

  • node --test test/http_transport.js → 16 passing
  • node --test test/pipeline.js (rebuilt wasm) → 49 passing
  • eslint clean

libdatadog's automatic entity detection (libdd-common's entity_id module) is
gated #[cfg(unix)] and therefore inert on the wasm32 target, and DD_EXTERNAL_ENV
is unreachable from wasm, so the native exporter never sent Datadog-Container-ID
/ Datadog-Entity-ID / Datadog-External-Env. Node can read /proc and process.env,
so detect them in the HTTP transport and rewrite the Rust-rendered request head
to carry them — the headers native libdatadog adds via set_standard_headers.

Detection mirrors dd-trace-js's exporters/common/docker.js (the proven legacy
exporter path) and libdd-common's compute_entity_id (ci-<container_id> else
in-<cgroup_inode>). The empty datadog-container-id libdatadog emits on wasm is
replaced rather than duplicated, and external-env is rejected if it carries
CR/LF or non-ASCII to avoid header injection.
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Overall package size

Self size: 30.08 MB
Deduped: 30.08 MB
No deduping: 30.08 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------|

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@bengl bengl marked this pull request as ready for review July 9, 2026 18:19
@bengl bengl requested review from a team as code owners July 9, 2026 18:19
@bengl bengl requested a review from Copilot July 9, 2026 18:36

Copilot AI 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.

Pull request overview

Adds WASM-compatible injection of Datadog entity headers by detecting container/entity/external-env values in the Node HTTP transport layer (which can read /proc and process.env) and rewriting the Rust-rendered HTTP/1.1 request head to include them, with accompanying unit and E2E tests to satisfy system-test expectations.

Changes:

  • Implement detectEntityHeaders() (container-id/entity-id via cgroup parsing; external-env via DD_EXTERNAL_ENV with CR/LF + non-ASCII rejection) plus memoized caching.
  • Implement applyEntityHeaders() to drop/replace any existing lines for injected header names and append detected headers while keeping the rest of the head intact.
  • Add tests covering detection, head rewriting behavior (including dedup of empty container-id), and a real-transport E2E asserting headers appear on the wire.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
crates/capabilities/src/http_transport.js Adds entity header detection + caching and rewrites the Rust-rendered request head to inject/replace these headers during httpRequest.
test/http_transport.js Adds unit tests for detection and head rewriting, plus an end-to-end transport test validating header injection on the wire.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/capabilities/src/http_transport.js

@rochdev rochdev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should be an event that is handled by the binary instead of altering the headers from the outside. It's fine for now to unblock, but this should be addressed as a follow-up, and ideally a TODO should be added.

@bengl bengl merged commit 35702fc into main Jul 9, 2026
48 checks passed
@bengl bengl deleted the bengl/entity-headers branch July 9, 2026 19:38
@bengl bengl mentioned this pull request Jul 9, 2026
bengl added a commit that referenced this pull request Jul 9, 2026
#166)

libdatadog's automatic entity detection (libdd-common's entity_id module) is
gated #[cfg(unix)] and therefore inert on the wasm32 target, and DD_EXTERNAL_ENV
is unreachable from wasm, so the native exporter never sent Datadog-Container-ID
/ Datadog-Entity-ID / Datadog-External-Env. Node can read /proc and process.env,
so detect them in the HTTP transport and rewrite the Rust-rendered request head
to carry them — the headers native libdatadog adds via set_standard_headers.

Detection mirrors dd-trace-js's exporters/common/docker.js (the proven legacy
exporter path) and libdd-common's compute_entity_id (ci-<container_id> else
in-<cgroup_inode>). The empty datadog-container-id libdatadog emits on wasm is
replaced rather than duplicated, and external-env is rejected if it carries
CR/LF or non-ASCII to avoid header injection.
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