Skip to content

fix(remote-config): support restored Node.js capability bits - #7917

Open
mtoffl01 wants to merge 13 commits into
mainfrom
fix/nodejs-sdk-configuration-capabilities
Open

mtoffl01 wants to merge 13 commits into
mainfrom
fix/nodejs-sdk-configuration-capabilities

Conversation

@mtoffl01

@mtoffl01 mtoffl01 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

DataDog/dd-trace-js#10573 restores the legacy per-setting APM_TRACING_* capability bits alongside SDK_CONFIGURATION. Node.js v6.17.0 and v6.18.0 advertise only SDK_CONFIGURATION, while the v6.19.0 release line will advertise both families, but continues to consume only sdk_config.

System-tests previously treated the presence of any legacy bit as proof that a tracer consumed lib_config. This caused the dynamic-configuration parametric suite and debugger in-product enablement tests to send the wrong payload shape.

Changes

  • Treat the presence of SDK_CONFIGURATION as authoritative for Node.js after APM_TRACING registration, including when legacy capability bits are also present.
  • Preserve the existing libdatadog bit-collision safeguard for other tracers.
  • Use SDK_CONFIGURATION to select sdk_config for Node.js 6.17.0 and later. Preserve the historical capability masks: 6.17.0–6.18.x advertise only SDK_CONFIGURATION, while 6.19.0+ also advertise the restored per-setting bits.
  • Require SDK_CONFIGURATION plus the restored legacy bits on the 6.x release line from v6.19.0. Allow 7.0.0 prerelease main builds to advertise those extra bits without requiring them before dd-trace-js#10573 lands.
  • Add regression coverage for the mixed Node.js capability set and the equivalent PHP interpretation.

Validation

Tested locally against the exact system_tests_binaries artifact produced by dd-trace-js#10573, reporting nodejs@7.0.0-pre.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

tests/parametric/capabilities.yml                                       @DataDog/system-tests-reviewers
tests/test_the_test/test_remote_config.py                               @DataDog/system-tests-reviewers
utils/_remote_config.py                                                 @DataDog/system-tests-core

@rachelyangdog rachelyangdog changed the title fix(remote-config): support restored Node.js capability bits [nodejs]: fix(remote-config): support restored Node.js capability bits Oct 1, 2026
@mtoffl01 mtoffl01 changed the title [nodejs]: fix(remote-config): support restored Node.js capability bits [nodejs]: fix(remote-config): support restored capability bits Oct 1, 2026
@mtoffl01
mtoffl01 force-pushed the fix/nodejs-sdk-configuration-capabilities branch from 93a7f07 to 5ac37c0 Compare October 1, 2026 19:08
@mtoffl01 mtoffl01 changed the title [nodejs]: fix(remote-config): support restored capability bits fix(remote-config): support restored Node.js capability bits Oct 1, 2026
@mtoffl01
mtoffl01 marked this pull request as ready for review October 1, 2026 19:13
@mtoffl01
mtoffl01 requested review from a team as code owners October 1, 2026 19:13
@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Pipelines  Tests

✨ Unblock PR with BitsAI

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 14 Pipeline jobs failed

Testing the test | System Tests (ruby, dev) / End-to-end #1 / rails52 1 — ❌ 15 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag.test_ai_guard_event[rails52] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag object at 0x7f214c1ebef0>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag object at 0x7f214c1ebef0>

    def test_ai_guard_event(self):
        """Test AI Guard sets ai_guard.event:true tag in the local root span of the trace."""
>       assert self.r.status_code == 200
E       assert 500 == 200
...
❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone.test_standalone_keeps_ai_guard_trace[rails52] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone object at 0x7f3440d7dfa0>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone object at 0x7f3440d7dfa0>

    def test_standalone_keeps_ai_guard_trace(self):
>       assert self.r.status_code == 200
E       assert 500 == 200
E        +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
...
❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker.test_all_spans_have_apm_disabled_marker[rails52] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker object at 0x7f3440d7d760>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker object at 0x7f3440d7d760>

    def test_all_spans_have_apm_disabled_marker(self) -> None:
>       assert self.r.status_code == 200
E       assert 500 == 200
E        +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
...
↳ and 12 more — View all
Testing the test | System Tests (ruby, dev) / End-to-end #1 / rails61 1 — ❌ 15 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag.test_ai_guard_event[rails61] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag object at 0x7f712fe14890>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag object at 0x7f712fe14890>

    def test_ai_guard_event(self):
        """Test AI Guard sets ai_guard.event:true tag in the local root span of the trace."""
>       assert self.r.status_code == 200
E       assert 500 == 200
...
❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone.test_standalone_keeps_ai_guard_trace[rails61] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone object at 0x7f47f9c71880>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone object at 0x7f47f9c71880>

    def test_standalone_keeps_ai_guard_trace(self):
>       assert self.r.status_code == 200
E       assert 500 == 200
E        +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
...
❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker.test_all_spans_have_apm_disabled_marker[rails61] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker object at 0x7f47f9c713d0>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker object at 0x7f47f9c713d0>

    def test_all_spans_have_apm_disabled_marker(self) -> None:
>       assert self.r.status_code == 200
E       assert 500 == 200
E        +  where 500 = HttpResponse(status_code:500, headers:{'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Conten...'Transfer-Encoding': 'chunked'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
...
↳ and 12 more — View all
Testing the test | System Tests (ruby, dev) / End-to-end #1 / rails72 1 — ❌ 15 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag.test_ai_guard_event[rails72] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...01738', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...01738', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag object at 0x7f4ff5a09040>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardEvent_Tag object at 0x7f4ff5a09040>

    def test_ai_guard_event(self):
        """Test AI Guard sets ai_guard.event:true tag in the local root span of the trace."""
>       assert self.r.status_code == 200
E       assert 500 == 200
...
❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone.test_standalone_keeps_ai_guard_trace[rails72] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...02199', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...02199', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone object at 0x7f62ec18e930>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone object at 0x7f62ec18e930>

    def test_standalone_keeps_ai_guard_trace(self):
>       assert self.r.status_code == 200
E       assert 500 == 200
E        +  where 500 = HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...02199', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
...
❌ tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker.test_all_spans_have_apm_disabled_marker[rails72] from system_tests_suite
assert 500 == 200
 +  where 500 = HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...01324', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
 +    where HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...01324', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}) = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker object at 0x7f62ec18e690>.r

self = <tests.ai_guard.test_ai_guard_sdk.Test_AIGuardStandalone_APMDisabledMarker object at 0x7f62ec18e690>

    def test_all_spans_have_apm_disabled_marker(self) -> None:
>       assert self.r.status_code == 200
E       assert 500 == 200
E        +  where 500 = HttpResponse(status_code:500, headers:{'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0', 'x-content-type-optio...01324', 'Content-Length': '80'}, text:{"error":"unknown keywords: :id, :tool_name, :arguments","type":"ArgumentError"}).status_code
...
↳ and 12 more — View all

View all 14 failed jobs.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 4147038 | Docs | View more details | Give us feedback!

Comment thread utils/_remote_config.py Outdated
@mtoffl01
mtoffl01 requested a review from cbeauchesne October 2, 2026 16:07

This branch has not been deployed

No deployments
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.

4 participants