From 703b2a318067fcc5b280658ce03b8095c31cf9f2 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Tue, 29 Sep 2026 11:36:08 +0200 Subject: [PATCH 01/13] feat(nodejs): add /security/thread_context_sharing weblog endpoint --- manifests/nodejs.yml | 2 +- utils/build/docker/nodejs/express/app.js | 17 +++++++++++++++ .../docker/nodejs/express4-typescript/app.ts | 18 ++++++++++++++++ utils/build/docker/nodejs/fastify/app.js | 18 ++++++++++++++++ utils/build/docker/nodejs/nextjs.Dockerfile | 1 + .../security/thread_context_sharing/route.js | 21 +++++++++++++++++++ 6 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 utils/build/docker/nodejs/nextjs/src/app/security/thread_context_sharing/route.js diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 101d6548197..4824f5a5982 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1675,7 +1675,7 @@ manifest: tests/auto_inject/test_auto_inject_install.py::TestContainerAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestHostAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestSimpleInstallerAutoInjectManualAppsec: *ref_5_43_0 - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (missing /security/thread_context_sharing endpoint on weblog) + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (thread context sharing not enabled for appsec yet) tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant diff --git a/utils/build/docker/nodejs/express/app.js b/utils/build/docker/nodejs/express/app.js index b5c4e25f98a..4485de611db 100644 --- a/utils/build/docker/nodejs/express/app.js +++ b/utils/build/docker/nodejs/express/app.js @@ -300,6 +300,23 @@ app.get('/make_distant_call', (req, res) => { request.end() }) +app.get('/security/thread_context_sharing', (req, res) => { + const path = req.query.path + if (typeof path !== 'string' || path === '') { + return res.status(400).send('missing path query parameter') + } + + // Synchronous on purpose: async fs opens the file on a libuv worker thread, which does not carry + // the request's thread context that the security agent reads. + fs.writeFileSync(path, 'thread context sharing') + + const context = tracer.scope().active().context() + res.json({ + trace_id: BigInt(`0x${context.toTraceId(true)}`).toString(), + span_id: context.toSpanId() + }) +}) + app.get('/user_login_success_event', (req, res) => { const userId = req.query.event_user_id || 'system_tests_user' diff --git a/utils/build/docker/nodejs/express4-typescript/app.ts b/utils/build/docker/nodejs/express4-typescript/app.ts index 903f32c1ffa..9b7d2f4fd58 100644 --- a/utils/build/docker/nodejs/express4-typescript/app.ts +++ b/utils/build/docker/nodejs/express4-typescript/app.ts @@ -221,6 +221,24 @@ app.get("/make_distant_call", (req: Request, res: Response) => { request.end() }) +app.get("/security/thread_context_sharing", (req: Request, res: Response) => { + const path = req.query.path; + if (typeof path !== "string" || path === "") { + res.status(400).send("missing path query parameter"); + return; + } + + // Synchronous on purpose: async fs opens the file on a libuv worker thread, which does not carry + // the request's thread context that the security agent reads. + require("fs").writeFileSync(path, "thread context sharing"); + + const context = tracer.scope().active().context(); + res.json({ + trace_id: BigInt(`0x${context.toTraceId(true)}`).toString(), + span_id: context.toSpanId() + }); +}); + app.get("/user_login_success_event", (req: Request, res: Response) => { const userId = req.query.event_user_id || "system_tests_user"; diff --git a/utils/build/docker/nodejs/fastify/app.js b/utils/build/docker/nodejs/fastify/app.js index 80b10445db4..932f739de25 100644 --- a/utils/build/docker/nodejs/fastify/app.js +++ b/utils/build/docker/nodejs/fastify/app.js @@ -273,6 +273,24 @@ fastify.get('/make_distant_call', async (request, reply) => { }) }) +fastify.get('/security/thread_context_sharing', async (request, reply) => { + const path = request.query.path + if (typeof path !== 'string' || path === '') { + reply.status(400) + return 'missing path query parameter' + } + + // Synchronous on purpose: async fs opens the file on a libuv worker thread, which does not carry + // the request's thread context that the security agent reads. + require('fs').writeFileSync(path, 'thread context sharing') + + const context = tracer.scope().active().context() + return { + trace_id: BigInt(`0x${context.toTraceId(true)}`).toString(), + span_id: context.toSpanId() + } +}) + fastify.get('/user_login_success_event', async (request, reply) => { const userId = request.query.event_user_id || 'system_tests_user' diff --git a/utils/build/docker/nodejs/nextjs.Dockerfile b/utils/build/docker/nodejs/nextjs.Dockerfile index 7034ba89196..fed62ec4477 100644 --- a/utils/build/docker/nodejs/nextjs.Dockerfile +++ b/utils/build/docker/nodejs/nextjs.Dockerfile @@ -5,6 +5,7 @@ EXPOSE 7777 # Refresh the application route and dependencies baked into the base image. COPY utils/build/docker/nodejs/nextjs/package.json utils/build/docker/nodejs/nextjs/bun.lock ./ COPY utils/build/docker/nodejs/nextjs/src/app/ffe ./src/app/ffe +COPY utils/build/docker/nodejs/nextjs/src/app/security ./src/app/security RUN rm -rf node_modules \ && bun install --frozen-lockfile --network-concurrency 8 --linker=hoisted diff --git a/utils/build/docker/nodejs/nextjs/src/app/security/thread_context_sharing/route.js b/utils/build/docker/nodejs/nextjs/src/app/security/thread_context_sharing/route.js new file mode 100644 index 00000000000..727be6865c4 --- /dev/null +++ b/utils/build/docker/nodejs/nextjs/src/app/security/thread_context_sharing/route.js @@ -0,0 +1,21 @@ +import { NextResponse } from 'next/server' +import { writeFileSync } from 'fs' + +export const dynamic = 'force-dynamic' + +export async function GET (request) { + const path = request.nextUrl.searchParams.get('path') + if (!path) { + return new NextResponse('missing path query parameter', { status: 400 }) + } + + // Synchronous on purpose: async fs opens the file on a libuv worker thread, which does not carry + // the request's thread context that the security agent reads. + writeFileSync(path, 'thread context sharing') + + const context = global._ddtrace.scope().active().context() + return NextResponse.json({ + trace_id: BigInt(`0x${context.toTraceId(true)}`).toString(), + span_id: context.toSpanId() + }) +} From bf58ac78d29cf98f7aef52f459453095099b98bf Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Tue, 29 Sep 2026 12:08:38 +0200 Subject: [PATCH 02/13] test(nodejs): temporarily enable Test_ThreadContextSharing on express5 --- manifests/nodejs.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 4824f5a5982..9befe5eef67 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1675,7 +1675,10 @@ manifest: tests/auto_inject/test_auto_inject_install.py::TestContainerAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestHostAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestSimpleInstallerAutoInjectManualAppsec: *ref_5_43_0 - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (thread context sharing not enabled for appsec yet) + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: + - weblog_declaration: + "*": missing_feature (thread context sharing not enabled for appsec yet) + express5: *ref_4_1_0 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant From 2119a484a06889a41efa1700d2b9b0f3b8885bad Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Tue, 29 Sep 2026 15:34:28 +0200 Subject: [PATCH 03/13] Revert "test(nodejs): temporarily enable Test_ThreadContextSharing on express5" This reverts commit b090af0664e783114c3f78d72cf67251623dd878. --- manifests/nodejs.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 9befe5eef67..4824f5a5982 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1675,10 +1675,7 @@ manifest: tests/auto_inject/test_auto_inject_install.py::TestContainerAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestHostAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestSimpleInstallerAutoInjectManualAppsec: *ref_5_43_0 - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: - - weblog_declaration: - "*": missing_feature (thread context sharing not enabled for appsec yet) - express5: *ref_4_1_0 + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (thread context sharing not enabled for appsec yet) tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant From ddccbd209cb73767fd619ea430e09d12463274a7 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Tue, 29 Sep 2026 18:04:06 +0200 Subject: [PATCH 04/13] chore(nodejs): refresh base image lock --- mirror_images.lock.yaml | 20 ++++++++++++++++++++ mirror_images.yaml | 5 +++++ utils/build/docker/base-images.lock.json | 10 +++++----- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/mirror_images.lock.yaml b/mirror_images.lock.yaml index 795739ade8c..e9b434bba14 100644 --- a/mirror_images.lock.yaml +++ b/mirror_images.lock.yaml @@ -166,10 +166,18 @@ images: digest: sha256:b71678692a476b6acc3eb235edbb98bbb9c6b943e17c246ecb24937276807bc3 target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:django-py3.13.base-d8262a2c816c tag: django-py3.13.base-d8262a2c816c + datadog/system-tests:express4-typescript.base-5a66898a3a49: + digest: sha256:9e5fd36cdd73416a07c690fc3d11ca6feef6988cb1b882de4ef1de4d594eee24 + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:express4-typescript.base-5a66898a3a49 + tag: express4-typescript.base-5a66898a3a49 datadog/system-tests:express4-typescript.base-eb800c09d602: digest: sha256:4c1359af1571b63dfcb95471fb9fa6a368329368ab5b51d755f35a347161e388 target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:express4-typescript.base-eb800c09d602 tag: express4-typescript.base-eb800c09d602 + datadog/system-tests:express4.base-93dbfc9a5699: + digest: sha256:96a80f92a127af451ac5a1f2324ba2d22a3def21f8c70bd3e250ae6729169115 + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:express4.base-93dbfc9a5699 + tag: express4.base-93dbfc9a5699 datadog/system-tests:express4.base-cb2b80abf6d1: digest: sha256:06f818aebeadbcaf9614e5f9b75f388b98afe0903b458be96ee1aa7c47aae9b3 target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:express4.base-cb2b80abf6d1 @@ -178,6 +186,10 @@ images: digest: sha256:89561e1d8fa4a4effbb68f840847454c11249f3d0b4e4f4fb1e7f954dc7a095f target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:express5.base-3ef9e2c68c47 tag: express5.base-3ef9e2c68c47 + datadog/system-tests:express5.base-6df40f6a8621: + digest: sha256:8221ab40116f5421ff278df706c3d20a8c1146a4687222f1ef76dc401b96bd83 + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:express5.base-6df40f6a8621 + tag: express5.base-6df40f6a8621 datadog/system-tests:fastapi.base-1795d4d88178: digest: sha256:bf65195d25f6e0d663c0f414590471fba7f18b1a0e3d284dda0cbd1896bea9a0 target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastapi.base-1795d4d88178 @@ -186,6 +198,10 @@ images: digest: sha256:f72a31702ffaabc1ba5e43042963e9cea965d1be6256d9d8a58e7e2381090d40 target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastapi.base-2917769b3665 tag: fastapi.base-2917769b3665 + datadog/system-tests:fastify.base-9613346d64d0: + digest: sha256:a4fa8c8c475c3d854a935bc753c1b13f774459f5d79b2712486d637e8659356f + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastify.base-9613346d64d0 + tag: fastify.base-9613346d64d0 datadog/system-tests:fastify.base-bce27c61b3f5: digest: sha256:984e566d8eb604d53c1532a55559549f4c443ac73caf41664bb73241e529357c target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastify.base-bce27c61b3f5 @@ -210,6 +226,10 @@ images: digest: sha256:2b09f33c61b2b19f4a239e4d8f10164ece66d925b72337720998ce43d7090d2f target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:lambda-proxy-v1 tag: lambda-proxy-v1 + datadog/system-tests:nextjs.base-312a008bf0e8: + digest: sha256:e7c6ccd084c27819ea41b0ca2c2a03b6b372c18f2c8ac4cac2891fe9d1e54661 + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:nextjs.base-312a008bf0e8 + tag: nextjs.base-312a008bf0e8 datadog/system-tests:nextjs.base-95582a903467: digest: sha256:128b7524cde00a739246166feef66b0d512388005dc125b0f11034555a8b6a70 target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:nextjs.base-95582a903467 diff --git a/mirror_images.yaml b/mirror_images.yaml index 2993dd8ac7b..122dd48b028 100644 --- a/mirror_images.yaml +++ b/mirror_images.yaml @@ -49,17 +49,22 @@ - "datadog/system-tests:apache-mod-8.2.base-d1aeacb6306a" - "datadog/system-tests:django-poc.base-78e2159815b1" - "datadog/system-tests:django-py3.13.base-d8262a2c816c" +- "datadog/system-tests:express4-typescript.base-5a66898a3a49" - "datadog/system-tests:express4-typescript.base-eb800c09d602" +- "datadog/system-tests:express4.base-93dbfc9a5699" - "datadog/system-tests:express4.base-cb2b80abf6d1" - "datadog/system-tests:express5.base-3ef9e2c68c47" +- "datadog/system-tests:express5.base-6df40f6a8621" - "datadog/system-tests:fastapi.base-1795d4d88178" - "datadog/system-tests:fastapi.base-2917769b3665" +- "datadog/system-tests:fastify.base-9613346d64d0" - "datadog/system-tests:fastify.base-bce27c61b3f5" - "datadog/system-tests:flask-poc.base-fa81f4f89ea4" - "datadog/system-tests:golang_buddy-v2" - "datadog/system-tests:java-lambda-runtime.base-e849230b09df" - "datadog/system-tests:java_buddy-v1" - "datadog/system-tests:lambda-proxy-v1" +- "datadog/system-tests:nextjs.base-312a008bf0e8" - "datadog/system-tests:nextjs.base-95582a903467" - "datadog/system-tests:nodejs_buddy-v1" - "datadog/system-tests:openai-py.base-b4fd56aee3f2" diff --git a/utils/build/docker/base-images.lock.json b/utils/build/docker/base-images.lock.json index b52719fd05f..01ab52ef2d5 100644 --- a/utils/build/docker/base-images.lock.json +++ b/utils/build/docker/base-images.lock.json @@ -2,11 +2,11 @@ "version": 1, "images": { "system_tests_base_java_lambda_java_lambda_runtime": "datadog/system-tests:java-lambda-runtime.base-e849230b09df", - "system_tests_base_nodejs_express4": "datadog/system-tests:express4.base-cb2b80abf6d1", - "system_tests_base_nodejs_express4_typescript": "datadog/system-tests:express4-typescript.base-eb800c09d602", - "system_tests_base_nodejs_express5": "datadog/system-tests:express5.base-3ef9e2c68c47", - "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-bce27c61b3f5", - "system_tests_base_nodejs_nextjs": "datadog/system-tests:nextjs.base-95582a903467", + "system_tests_base_nodejs_express4": "datadog/system-tests:express4.base-93dbfc9a5699", + "system_tests_base_nodejs_express4_typescript": "datadog/system-tests:express4-typescript.base-5a66898a3a49", + "system_tests_base_nodejs_express5": "datadog/system-tests:express5.base-6df40f6a8621", + "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-9613346d64d0", + "system_tests_base_nodejs_nextjs": "datadog/system-tests:nextjs.base-312a008bf0e8", "system_tests_base_php_apache_mod_7_0": "datadog/system-tests:apache-mod-7.0.base-8c8102938177", "system_tests_base_php_apache_mod_7_0_zts": "datadog/system-tests:apache-mod-7.0-zts.base-01cc5715b403", "system_tests_base_php_apache_mod_7_1": "datadog/system-tests:apache-mod-7.1.base-96cd329b60b0", From eded623296d3511551fef9515c0525bc1b7446de Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Wed, 30 Sep 2026 12:26:34 +0200 Subject: [PATCH 05/13] test(nodejs): temporarily run Test_ThreadContextSharing end to end on fastify --- manifests/nodejs.yml | 5 ++++- utils/build/docker/nodejs/fastify.Dockerfile | 3 +++ utils/build/docker/nodejs/weblog_metadata.yml | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 4824f5a5982..89edbb37937 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1675,7 +1675,10 @@ manifest: tests/auto_inject/test_auto_inject_install.py::TestContainerAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestHostAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestSimpleInstallerAutoInjectManualAppsec: *ref_5_43_0 - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (thread context sharing not enabled for appsec yet) + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: + - weblog_declaration: + "*": missing_feature (thread context sharing not enabled for appsec yet) + fastify: *ref_4_1_0 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant diff --git a/utils/build/docker/nodejs/fastify.Dockerfile b/utils/build/docker/nodejs/fastify.Dockerfile index 2fd5c72c07b..36badc98df3 100644 --- a/utils/build/docker/nodejs/fastify.Dockerfile +++ b/utils/build/docker/nodejs/fastify.Dockerfile @@ -26,3 +26,6 @@ CMD ./app.sh COPY utils/build/docker/nodejs/install_ddtrace.sh binaries* /binaries/ RUN /binaries/install_ddtrace.sh && rm -rf /root/.bun ENV DD_TRACE_HEADER_TAGS=user-agent +# TEMPORARY (do not merge): run the thread context writer end to end on this weblog. +ENV NODE_OPTIONS=--experimental-async-context-frame +ENV DD_TRACE_OTEL_CTX_ENABLED=true diff --git a/utils/build/docker/nodejs/weblog_metadata.yml b/utils/build/docker/nodejs/weblog_metadata.yml index faf1a7f5746..8548bed45cc 100644 --- a/utils/build/docker/nodejs/weblog_metadata.yml +++ b/utils/build/docker/nodejs/weblog_metadata.yml @@ -51,6 +51,7 @@ fastify: - APPSEC_STANDALONE_RASP - IAST_DEDUPLICATION - IAST_STANDALONE + - THREAD_CONTEXT_SHARING nextjs: build_mode: local supported_scenarios: *framework_scenarios From 5c45a5fea480d784de82929dc5982860cb82c5e6 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 08:36:42 +0200 Subject: [PATCH 06/13] Revert "test(nodejs): temporarily run Test_ThreadContextSharing end to end on fastify" This reverts commit dfce906337dce05461b90fd6f8b1fd123d533ccf. --- manifests/nodejs.yml | 5 +---- utils/build/docker/nodejs/fastify.Dockerfile | 3 --- utils/build/docker/nodejs/weblog_metadata.yml | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 89edbb37937..4824f5a5982 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1675,10 +1675,7 @@ manifest: tests/auto_inject/test_auto_inject_install.py::TestContainerAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestHostAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestSimpleInstallerAutoInjectManualAppsec: *ref_5_43_0 - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: - - weblog_declaration: - "*": missing_feature (thread context sharing not enabled for appsec yet) - fastify: *ref_4_1_0 + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (thread context sharing not enabled for appsec yet) tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant diff --git a/utils/build/docker/nodejs/fastify.Dockerfile b/utils/build/docker/nodejs/fastify.Dockerfile index 36badc98df3..2fd5c72c07b 100644 --- a/utils/build/docker/nodejs/fastify.Dockerfile +++ b/utils/build/docker/nodejs/fastify.Dockerfile @@ -26,6 +26,3 @@ CMD ./app.sh COPY utils/build/docker/nodejs/install_ddtrace.sh binaries* /binaries/ RUN /binaries/install_ddtrace.sh && rm -rf /root/.bun ENV DD_TRACE_HEADER_TAGS=user-agent -# TEMPORARY (do not merge): run the thread context writer end to end on this weblog. -ENV NODE_OPTIONS=--experimental-async-context-frame -ENV DD_TRACE_OTEL_CTX_ENABLED=true diff --git a/utils/build/docker/nodejs/weblog_metadata.yml b/utils/build/docker/nodejs/weblog_metadata.yml index 8548bed45cc..faf1a7f5746 100644 --- a/utils/build/docker/nodejs/weblog_metadata.yml +++ b/utils/build/docker/nodejs/weblog_metadata.yml @@ -51,7 +51,6 @@ fastify: - APPSEC_STANDALONE_RASP - IAST_DEDUPLICATION - IAST_STANDALONE - - THREAD_CONTEXT_SHARING nextjs: build_mode: local supported_scenarios: *framework_scenarios From 635e7096809ff86a2ce5a9fb1659ccf71275ba6f Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 09:07:37 +0200 Subject: [PATCH 07/13] feat(nodejs): run fastify on Node.js 24 and host THREAD_CONTEXT_SHARING there --- manifests/nodejs.yml | 5 +++- .../docker/nodejs/fastify.base.Dockerfile | 2 +- utils/build/docker/nodejs/weblog_metadata.yml | 29 +++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 4824f5a5982..85023ffe7bf 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1675,7 +1675,10 @@ manifest: tests/auto_inject/test_auto_inject_install.py::TestContainerAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestHostAutoInjectInstallScriptAppsec: *ref_5_43_0 tests/auto_inject/test_auto_inject_install.py::TestSimpleInstallerAutoInjectManualAppsec: *ref_5_43_0 - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: missing_feature (thread context sharing not enabled for appsec yet) + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: + - weblog_declaration: + "*": irrelevant (requires AsyncContextFrame, Node.js 22.9+; covered on fastify) + fastify: missing_feature (thread context sharing not enabled for appsec yet) tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant diff --git a/utils/build/docker/nodejs/fastify.base.Dockerfile b/utils/build/docker/nodejs/fastify.base.Dockerfile index 81375981500..263f2a4c7dd 100644 --- a/utils/build/docker/nodejs/fastify.base.Dockerfile +++ b/utils/build/docker/nodejs/fastify.base.Dockerfile @@ -1,4 +1,4 @@ -FROM node:22-alpine +FROM node:24-alpine COPY --from=oven/bun:1.4.0-alpine /usr/local/bin/bun /usr/local/bin/bun diff --git a/utils/build/docker/nodejs/weblog_metadata.yml b/utils/build/docker/nodejs/weblog_metadata.yml index faf1a7f5746..9d6600af557 100644 --- a/utils/build/docker/nodejs/weblog_metadata.yml +++ b/utils/build/docker/nodejs/weblog_metadata.yml @@ -26,7 +26,7 @@ express5: categories: [dd_trace] fastify: build_mode: local - supported_scenarios: &framework_scenarios + supported_scenarios: - DEFAULT - APPSEC_API_SECURITY - APPSEC_API_SECURITY_NO_RESPONSE_BODY @@ -51,9 +51,34 @@ fastify: - APPSEC_STANDALONE_RASP - IAST_DEDUPLICATION - IAST_STANDALONE + - THREAD_CONTEXT_SHARING nextjs: build_mode: local - supported_scenarios: *framework_scenarios + supported_scenarios: + - DEFAULT + - APPSEC_API_SECURITY + - APPSEC_API_SECURITY_NO_RESPONSE_BODY + - APPSEC_API_SECURITY_RC + - APPSEC_API_SECURITY_WITH_SAMPLING + - APPSEC_APM_STANDALONE + - APPSEC_ATO_SDK + - APPSEC_AUTO_EVENTS_EXTENDED + - APPSEC_AUTO_EVENTS_RC + - APPSEC_BLOCKING + - APPSEC_BLOCKING_FULL_DENYLIST + - APPSEC_LOW_WAF_TIMEOUT + - APPSEC_RASP + - APPSEC_RASP_NON_BLOCKING + - APPSEC_RASP_WITHOUT_DOWNSTREAM_BODY_ANALYSIS_USING_MAX + - APPSEC_RASP_WITHOUT_DOWNSTREAM_BODY_ANALYSIS_USING_SAMPLE_RATE + - APPSEC_RATE_LIMITER + - APPSEC_RUNTIME_ACTIVATION + - APPSEC_STANDALONE + - APPSEC_STANDALONE_API_SECURITY + - APPSEC_STANDALONE_APM_STANDALONE + - APPSEC_STANDALONE_RASP + - IAST_DEDUPLICATION + - IAST_STANDALONE uds-express4: build_mode: local supported_scenarios: From 510f565fa72462b66bd6c9d26f3eb63b295c20d0 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 09:15:29 +0200 Subject: [PATCH 08/13] chore(nodejs): refresh base image lock for fastify on Node.js 24 --- mirror_images.yaml | 2 ++ utils/build/docker/base-images.lock.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mirror_images.yaml b/mirror_images.yaml index 122dd48b028..c38887a7740 100644 --- a/mirror_images.yaml +++ b/mirror_images.yaml @@ -59,6 +59,7 @@ - "datadog/system-tests:fastapi.base-2917769b3665" - "datadog/system-tests:fastify.base-9613346d64d0" - "datadog/system-tests:fastify.base-bce27c61b3f5" +- "datadog/system-tests:fastify.base-edcf078de5d9" - "datadog/system-tests:flask-poc.base-fa81f4f89ea4" - "datadog/system-tests:golang_buddy-v2" - "datadog/system-tests:java-lambda-runtime.base-e849230b09df" @@ -126,6 +127,7 @@ - "node:18-alpine" - "node:20-alpine" - "node:22-alpine" +- "node:24-alpine" - "otel/opentelemetry-collector-contrib:0.137.0" - "postgres:alpine" - "public.ecr.aws/lambda/java:17" diff --git a/utils/build/docker/base-images.lock.json b/utils/build/docker/base-images.lock.json index 01ab52ef2d5..b9be8a5d3e7 100644 --- a/utils/build/docker/base-images.lock.json +++ b/utils/build/docker/base-images.lock.json @@ -5,7 +5,7 @@ "system_tests_base_nodejs_express4": "datadog/system-tests:express4.base-93dbfc9a5699", "system_tests_base_nodejs_express4_typescript": "datadog/system-tests:express4-typescript.base-5a66898a3a49", "system_tests_base_nodejs_express5": "datadog/system-tests:express5.base-6df40f6a8621", - "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-9613346d64d0", + "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-edcf078de5d9", "system_tests_base_nodejs_nextjs": "datadog/system-tests:nextjs.base-312a008bf0e8", "system_tests_base_php_apache_mod_7_0": "datadog/system-tests:apache-mod-7.0.base-8c8102938177", "system_tests_base_php_apache_mod_7_0_zts": "datadog/system-tests:apache-mod-7.0-zts.base-01cc5715b403", From 25bd25d268b00c9662a5b28d422fe3f18f0d8889 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 09:57:29 +0200 Subject: [PATCH 09/13] fix(nodejs): use public getHeaders() in fastify for Node.js 24 --- mirror_images.yaml | 1 + utils/build/docker/base-images.lock.json | 2 +- utils/build/docker/nodejs/fastify/app.js | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mirror_images.yaml b/mirror_images.yaml index c38887a7740..b4c296d90b5 100644 --- a/mirror_images.yaml +++ b/mirror_images.yaml @@ -58,6 +58,7 @@ - "datadog/system-tests:fastapi.base-1795d4d88178" - "datadog/system-tests:fastapi.base-2917769b3665" - "datadog/system-tests:fastify.base-9613346d64d0" +- "datadog/system-tests:fastify.base-9dddb89b99c4" - "datadog/system-tests:fastify.base-bce27c61b3f5" - "datadog/system-tests:fastify.base-edcf078de5d9" - "datadog/system-tests:flask-poc.base-fa81f4f89ea4" diff --git a/utils/build/docker/base-images.lock.json b/utils/build/docker/base-images.lock.json index b9be8a5d3e7..85a786d526f 100644 --- a/utils/build/docker/base-images.lock.json +++ b/utils/build/docker/base-images.lock.json @@ -5,7 +5,7 @@ "system_tests_base_nodejs_express4": "datadog/system-tests:express4.base-93dbfc9a5699", "system_tests_base_nodejs_express4_typescript": "datadog/system-tests:express4-typescript.base-5a66898a3a49", "system_tests_base_nodejs_express5": "datadog/system-tests:express5.base-6df40f6a8621", - "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-edcf078de5d9", + "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-9dddb89b99c4", "system_tests_base_nodejs_nextjs": "datadog/system-tests:nextjs.base-312a008bf0e8", "system_tests_base_php_apache_mod_7_0": "datadog/system-tests:apache-mod-7.0.base-8c8102938177", "system_tests_base_php_apache_mod_7_0_zts": "datadog/system-tests:apache-mod-7.0-zts.base-01cc5715b403", diff --git a/utils/build/docker/nodejs/fastify/app.js b/utils/build/docker/nodejs/fastify/app.js index 932f739de25..34b64d55894 100644 --- a/utils/build/docker/nodejs/fastify/app.js +++ b/utils/build/docker/nodejs/fastify/app.js @@ -252,7 +252,7 @@ fastify.get('/make_distant_call', async (request, reply) => { resolve({ url, status_code: response.statusCode, - request_headers: response.req._headers, + request_headers: response.req.getHeaders(), response_headers: response.headers, response_body: responseBody }) @@ -699,7 +699,7 @@ fastify.get('/otel_drop_in_baggage_api_otel', async (request, reply) => { resolve({ url, status_code: response.statusCode, - request_headers: response.req._headers, + request_headers: response.req.getHeaders(), response_headers: response.headers, response_body: responseBody }) @@ -761,7 +761,7 @@ fastify.get('/otel_drop_in_baggage_api_datadog', async (request, reply) => { resolve({ url, status_code: response.statusCode, - request_headers: response.req._headers, + request_headers: response.req.getHeaders(), response_headers: response.headers, response_body: responseBody }) From 00f77e95892c12e994c53c0e566a4ccb6715c48a Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 12:53:49 +0200 Subject: [PATCH 10/13] chore(nodejs): lock mirror digests for fastify on Node.js 24 --- mirror_images.lock.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mirror_images.lock.yaml b/mirror_images.lock.yaml index e9b434bba14..5a1c27dd81a 100644 --- a/mirror_images.lock.yaml +++ b/mirror_images.lock.yaml @@ -202,10 +202,18 @@ images: digest: sha256:a4fa8c8c475c3d854a935bc753c1b13f774459f5d79b2712486d637e8659356f target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastify.base-9613346d64d0 tag: fastify.base-9613346d64d0 + datadog/system-tests:fastify.base-9dddb89b99c4: + digest: sha256:e09ccb29386b7ae3cfd07e99cf11a532d0ccd14bf7b6b5415199fc96d79799c5 + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastify.base-9dddb89b99c4 + tag: fastify.base-9dddb89b99c4 datadog/system-tests:fastify.base-bce27c61b3f5: digest: sha256:984e566d8eb604d53c1532a55559549f4c443ac73caf41664bb73241e529357c target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastify.base-bce27c61b3f5 tag: fastify.base-bce27c61b3f5 + datadog/system-tests:fastify.base-edcf078de5d9: + digest: sha256:07f1aa403fa5be8ea02687fda1c9cd58f25dc02939be00762240a74fad3e4db5 + target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:fastify.base-edcf078de5d9 + tag: fastify.base-edcf078de5d9 datadog/system-tests:flask-poc.base-fa81f4f89ea4: digest: sha256:f300cff471470574ce8263292f54ab745ffacfa8af741dd41be15a8c947e2e0e target: registry.ddbuild.io/system-tests/mirror/datadog/system-tests:flask-poc.base-fa81f4f89ea4 @@ -474,6 +482,10 @@ images: digest: sha256:c610fcdfb1d5b4740dd70c284ed3cb16bb857e0f7166196e36a5501df7a3aa32 target: registry.ddbuild.io/system-tests/mirror/node:22-alpine tag: 22-alpine + node:24-alpine: + digest: sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 + target: registry.ddbuild.io/system-tests/mirror/node:24-alpine + tag: 24-alpine otel/opentelemetry-collector-contrib:0.137.0: digest: sha256:886722fe0f37af9d1fe24d29529253ec59fbf263b3b1df4facaf221373e19d23 target: registry.ddbuild.io/system-tests/mirror/otel/opentelemetry-collector-contrib:0.137.0 From 7ecdfaff2e422841a33906f5d664b4cfb67c4006 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 12:54:03 +0200 Subject: [PATCH 11/13] test(nodejs): temporarily run Test_ThreadContextSharing end to end on fastify (Node.js 24) --- manifests/nodejs.yml | 2 +- utils/build/docker/nodejs/fastify.Dockerfile | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 85023ffe7bf..bc132b8f86d 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -1678,7 +1678,7 @@ manifest: tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: - weblog_declaration: "*": irrelevant (requires AsyncContextFrame, Node.js 22.9+; covered on fastify) - fastify: missing_feature (thread context sharing not enabled for appsec yet) + fastify: *ref_4_1_0 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: - weblog_declaration: "*": irrelevant diff --git a/utils/build/docker/nodejs/fastify.Dockerfile b/utils/build/docker/nodejs/fastify.Dockerfile index 2fd5c72c07b..bc4ac360473 100644 --- a/utils/build/docker/nodejs/fastify.Dockerfile +++ b/utils/build/docker/nodejs/fastify.Dockerfile @@ -26,3 +26,5 @@ CMD ./app.sh COPY utils/build/docker/nodejs/install_ddtrace.sh binaries* /binaries/ RUN /binaries/install_ddtrace.sh && rm -rf /root/.bun ENV DD_TRACE_HEADER_TAGS=user-agent +# TEMPORARY (do not merge): run the thread context writer end to end on Node.js 24. +ENV DD_TRACE_OTEL_CTX_ENABLED=true From bfaaa3140a1f04481aec4ff305b7652134df05f1 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 15:35:53 +0200 Subject: [PATCH 12/13] test(agent): temporarily re-enable Test_ThreadContextSharing to validate Node.js 24 --- manifests/agent.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manifests/agent.yml b/manifests/agent.yml index 2ce3cad9ebb..5ad8e8e39f2 100644 --- a/manifests/agent.yml +++ b/manifests/agent.yml @@ -7,7 +7,9 @@ manifest: tests/appsec/smoke_tests/test_apm_standalone.py: - component_version: "<7.77.0-0" declaration: irrelevant (APM Standalone option was added in 7.77.0) - tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: bug (APPSEC-70532) + tests/cws/test_thread_context_sharing.py::Test_ThreadContextSharing: + - declaration: missing_feature (Trace collection not available in agents pre 7.84) + component_version: '<7.84.0-devel' tests/debugger/test_debugger_condition_errors.py::Test_Debugger_Invalid_Condition_DSL: - component_version: "<7.77.1" weblog_declaration: From c73a29af96d5d0c5383f32f1022bf0c7ba2183c9 Mon Sep 17 00:00:00 2001 From: Carles Capell Date: Thu, 1 Oct 2026 17:02:36 +0200 Subject: [PATCH 13/13] test(nodejs): temporarily run fastify on Node.js 22 as thread context control --- mirror_images.yaml | 1 + utils/build/docker/base-images.lock.json | 2 +- utils/build/docker/nodejs/fastify.Dockerfile | 2 ++ utils/build/docker/nodejs/fastify.base.Dockerfile | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mirror_images.yaml b/mirror_images.yaml index b4c296d90b5..16fa4e9e9e4 100644 --- a/mirror_images.yaml +++ b/mirror_images.yaml @@ -61,6 +61,7 @@ - "datadog/system-tests:fastify.base-9dddb89b99c4" - "datadog/system-tests:fastify.base-bce27c61b3f5" - "datadog/system-tests:fastify.base-edcf078de5d9" +- "datadog/system-tests:fastify.base-f42683fff2b3" - "datadog/system-tests:flask-poc.base-fa81f4f89ea4" - "datadog/system-tests:golang_buddy-v2" - "datadog/system-tests:java-lambda-runtime.base-e849230b09df" diff --git a/utils/build/docker/base-images.lock.json b/utils/build/docker/base-images.lock.json index 85a786d526f..1ffdd8fbc08 100644 --- a/utils/build/docker/base-images.lock.json +++ b/utils/build/docker/base-images.lock.json @@ -5,7 +5,7 @@ "system_tests_base_nodejs_express4": "datadog/system-tests:express4.base-93dbfc9a5699", "system_tests_base_nodejs_express4_typescript": "datadog/system-tests:express4-typescript.base-5a66898a3a49", "system_tests_base_nodejs_express5": "datadog/system-tests:express5.base-6df40f6a8621", - "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-9dddb89b99c4", + "system_tests_base_nodejs_fastify": "datadog/system-tests:fastify.base-f42683fff2b3", "system_tests_base_nodejs_nextjs": "datadog/system-tests:nextjs.base-312a008bf0e8", "system_tests_base_php_apache_mod_7_0": "datadog/system-tests:apache-mod-7.0.base-8c8102938177", "system_tests_base_php_apache_mod_7_0_zts": "datadog/system-tests:apache-mod-7.0-zts.base-01cc5715b403", diff --git a/utils/build/docker/nodejs/fastify.Dockerfile b/utils/build/docker/nodejs/fastify.Dockerfile index bc4ac360473..d8deee6b05e 100644 --- a/utils/build/docker/nodejs/fastify.Dockerfile +++ b/utils/build/docker/nodejs/fastify.Dockerfile @@ -28,3 +28,5 @@ RUN /binaries/install_ddtrace.sh && rm -rf /root/.bun ENV DD_TRACE_HEADER_TAGS=user-agent # TEMPORARY (do not merge): run the thread context writer end to end on Node.js 24. ENV DD_TRACE_OTEL_CTX_ENABLED=true +# TEMPORARY (do not merge): Node.js 22 control run, AsyncContextFrame needs the flag. +ENV NODE_OPTIONS=--experimental-async-context-frame diff --git a/utils/build/docker/nodejs/fastify.base.Dockerfile b/utils/build/docker/nodejs/fastify.base.Dockerfile index 263f2a4c7dd..81375981500 100644 --- a/utils/build/docker/nodejs/fastify.base.Dockerfile +++ b/utils/build/docker/nodejs/fastify.base.Dockerfile @@ -1,4 +1,4 @@ -FROM node:24-alpine +FROM node:22-alpine COPY --from=oven/bun:1.4.0-alpine /usr/local/bin/bun /usr/local/bin/bun