dd-trace 5.97.0 → 5.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ext/tags.js +1 -0
  3. package/index.d.ts +35 -3
  4. package/package.json +48 -46
  5. package/packages/datadog-instrumentations/src/crypto.js +45 -0
  6. package/packages/datadog-instrumentations/src/cucumber.js +65 -3
  7. package/packages/datadog-instrumentations/src/cypress-config.js +153 -53
  8. package/packages/datadog-instrumentations/src/dns.js +24 -56
  9. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  10. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +74 -0
  11. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +4 -1
  12. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +10 -3
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +59 -0
  16. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +11 -2
  17. package/packages/datadog-instrumentations/src/jest.js +104 -12
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +8 -0
  19. package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +7 -0
  20. package/packages/datadog-instrumentations/src/pino.js +4 -28
  21. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +27 -0
  22. package/packages/datadog-instrumentations/src/playwright.js +5 -17
  23. package/packages/datadog-instrumentations/src/redis.js +12 -6
  24. package/packages/datadog-instrumentations/src/stripe.js +38 -24
  25. package/packages/datadog-instrumentations/src/vitest.js +32 -4
  26. package/packages/datadog-instrumentations/src/zlib.js +29 -0
  27. package/packages/datadog-plugin-aws-sdk/src/base.js +2 -3
  28. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
  29. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  30. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  31. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
  32. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
  33. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  34. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +8 -15
  35. package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -9
  36. package/packages/datadog-plugin-cucumber/src/index.js +8 -2
  37. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +114 -6
  38. package/packages/datadog-plugin-cypress/src/index.js +59 -2
  39. package/packages/datadog-plugin-cypress/src/source-map-utils.js +48 -1
  40. package/packages/datadog-plugin-fs/src/index.js +1 -1
  41. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
  42. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
  43. package/packages/datadog-plugin-http/src/client.js +1 -1
  44. package/packages/datadog-plugin-http/src/server.js +21 -13
  45. package/packages/datadog-plugin-http2/src/client.js +1 -1
  46. package/packages/datadog-plugin-http2/src/server.js +10 -2
  47. package/packages/datadog-plugin-jest/src/index.js +2 -2
  48. package/packages/datadog-plugin-mocha/src/index.js +1 -2
  49. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/index.js +24 -0
  50. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +55 -0
  51. package/packages/datadog-plugin-mongodb-core/src/index.js +4 -9
  52. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  53. package/packages/datadog-plugin-next/src/index.js +8 -2
  54. package/packages/datadog-plugin-pg/src/index.js +1 -1
  55. package/packages/datadog-plugin-playwright/src/index.js +2 -3
  56. package/packages/datadog-plugin-tedious/src/index.js +1 -1
  57. package/packages/datadog-plugin-vitest/src/index.js +14 -6
  58. package/packages/datadog-plugin-ws/src/close.js +3 -1
  59. package/packages/datadog-plugin-ws/src/producer.js +2 -0
  60. package/packages/datadog-plugin-ws/src/receiver.js +2 -1
  61. package/packages/dd-trace/src/aiguard/channels.js +8 -0
  62. package/packages/dd-trace/src/aiguard/index.js +7 -3
  63. package/packages/dd-trace/src/aiguard/sdk.js +66 -22
  64. package/packages/dd-trace/src/aiguard/tags.js +1 -0
  65. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
  66. package/packages/dd-trace/src/appsec/blocking.js +62 -34
  67. package/packages/dd-trace/src/appsec/graphql.js +6 -6
  68. package/packages/dd-trace/src/appsec/index.js +9 -11
  69. package/packages/dd-trace/src/appsec/rasp/command_injection.js +4 -5
  70. package/packages/dd-trace/src/appsec/rasp/lfi.js +8 -4
  71. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +5 -10
  72. package/packages/dd-trace/src/appsec/rasp/ssrf.js +5 -6
  73. package/packages/dd-trace/src/appsec/recommended.json +2438 -13
  74. package/packages/dd-trace/src/appsec/reporter.js +6 -5
  75. package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
  76. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -5
  77. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +6 -10
  78. package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
  79. package/packages/dd-trace/src/appsec/store.js +50 -0
  80. package/packages/dd-trace/src/appsec/waf/index.js +3 -5
  81. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
  82. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
  83. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
  84. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  85. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -4
  86. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
  87. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -5
  88. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +3 -4
  89. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +6 -6
  90. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +2 -2
  91. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
  92. package/packages/dd-trace/src/config/config-types.d.ts +0 -4
  93. package/packages/dd-trace/src/config/defaults.js +10 -11
  94. package/packages/dd-trace/src/config/generated-config-types.d.ts +14 -8
  95. package/packages/dd-trace/src/config/index.js +49 -32
  96. package/packages/dd-trace/src/config/parsers.js +26 -9
  97. package/packages/dd-trace/src/config/supported-configurations.json +86 -33
  98. package/packages/dd-trace/src/constants.js +1 -0
  99. package/packages/dd-trace/src/debugger/config.js +2 -0
  100. package/packages/dd-trace/src/debugger/devtools_client/send.js +25 -5
  101. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
  102. package/packages/dd-trace/src/encode/0.4.js +11 -11
  103. package/packages/dd-trace/src/encode/span-stats.js +4 -1
  104. package/packages/dd-trace/src/exporters/agent/index.js +0 -1
  105. package/packages/dd-trace/src/exporters/agent/writer.js +1 -2
  106. package/packages/dd-trace/src/exporters/agentless/writer.js +3 -3
  107. package/packages/dd-trace/src/exporters/common/util.js +2 -2
  108. package/packages/dd-trace/src/id.js +2 -0
  109. package/packages/dd-trace/src/index.js +2 -5
  110. package/packages/dd-trace/src/lambda/handler.js +1 -3
  111. package/packages/dd-trace/src/llmobs/plugins/{anthropic.js → anthropic/index.js} +5 -63
  112. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +106 -0
  113. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +3 -2
  114. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -2
  115. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +2 -1
  116. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +0 -49
  117. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +2 -1
  118. package/packages/dd-trace/src/llmobs/plugins/langchain/messages.js +76 -0
  119. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -26
  120. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/index.js +68 -0
  121. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +57 -0
  122. package/packages/dd-trace/src/llmobs/sdk.js +2 -2
  123. package/packages/dd-trace/src/log/index.js +0 -10
  124. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +103 -0
  125. package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -0
  126. package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
  127. package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
  128. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  129. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
  130. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  131. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +3 -2
  132. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +19 -51
  133. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
  134. package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
  135. package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
  136. package/packages/dd-trace/src/opentelemetry/trace/index.js +70 -0
  137. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +74 -0
  138. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +342 -0
  139. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -11
  140. package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -10
  141. package/packages/dd-trace/src/opentracing/span.js +1 -1
  142. package/packages/dd-trace/src/opentracing/tracer.js +17 -5
  143. package/packages/dd-trace/src/plugins/index.js +1 -0
  144. package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
  145. package/packages/dd-trace/src/plugins/plugin.js +6 -11
  146. package/packages/dd-trace/src/plugins/storage.js +2 -2
  147. package/packages/dd-trace/src/plugins/tracing.js +22 -5
  148. package/packages/dd-trace/src/plugins/util/test.js +128 -5
  149. package/packages/dd-trace/src/plugins/util/url.js +2 -1
  150. package/packages/dd-trace/src/plugins/util/web.js +6 -88
  151. package/packages/dd-trace/src/profiling/profiler.js +34 -77
  152. package/packages/dd-trace/src/profiling/profilers/event_plugins/crypto.js +32 -0
  153. package/packages/dd-trace/src/profiling/profilers/event_plugins/zlib.js +19 -0
  154. package/packages/dd-trace/src/profiling/profilers/events.js +35 -0
  155. package/packages/dd-trace/src/proxy.js +3 -4
  156. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +17 -13
  157. package/packages/dd-trace/src/service-naming/index.js +1 -1
  158. package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
  159. package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
  160. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
  161. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
  162. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +21 -1
  163. package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
  164. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
  165. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +15 -1
  166. package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
  167. package/packages/dd-trace/src/span_processor.js +1 -2
  168. package/packages/dd-trace/src/span_stats.js +5 -1
  169. package/packages/dd-trace/src/tagger.js +2 -2
  170. package/packages/dd-trace/src/telemetry/send-data.js +5 -7
  171. package/vendor/dist/@apm-js-collab/code-transformer/index.js +28 -6
  172. package/vendor/dist/protobufjs/index.js +1 -1
  173. package/packages/dd-trace/src/log/utils.js +0 -16
  174. package/vendor/dist/ignore/LICENSE +0 -21
  175. package/vendor/dist/ignore/index.js +0 -1
@@ -5,7 +5,6 @@ const realDateNow = Date.now.bind(Date)
5
5
 
6
6
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
7
7
  const { storage } = require('../../datadog-core')
8
- const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
9
8
 
10
9
  const {
11
10
  TEST_STATUS,
@@ -406,7 +405,7 @@ class MochaPlugin extends CiPlugin {
406
405
  finishAllTraceSpans(this.testSessionSpan)
407
406
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
408
407
  provider: this.ciProviderName,
409
- autoInjected: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
408
+ autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
410
409
  })
411
410
  }
412
411
  this.libraryConfig = null
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
+ const mcpLLMObsPlugins = require('../../dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk')
5
+ const tracingPlugins = require('./tracing')
6
+
7
+ const plugins = {}
8
+
9
+ // CRITICAL: LLMObs plugins MUST come first
10
+ for (const Plugin of mcpLLMObsPlugins) {
11
+ plugins[Plugin.id] = Plugin
12
+ }
13
+
14
+ // Tracing plugins second
15
+ for (const Plugin of tracingPlugins) {
16
+ plugins[Plugin.id] = Plugin
17
+ }
18
+
19
+ class ModelcontextprotocolSdkPlugin extends CompositePlugin {
20
+ static id = 'modelcontextprotocol-sdk'
21
+ static plugins = plugins
22
+ }
23
+
24
+ module.exports = ModelcontextprotocolSdkPlugin
@@ -0,0 +1,55 @@
1
+ 'use strict'
2
+
3
+ const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
4
+
5
+ class McpToolCallPlugin extends TracingPlugin {
6
+ static id = 'modelcontextprotocol_client'
7
+ static prefix = 'tracing:orchestrion:@modelcontextprotocol/sdk:Client_callTool'
8
+
9
+ bindStart (ctx) {
10
+ const params = ctx.arguments?.[0]
11
+ const toolName = params?.name
12
+
13
+ this.startSpan('mcp.client.tool.call', {
14
+ resource: toolName,
15
+ type: 'mcp',
16
+ kind: 'client',
17
+ }, ctx)
18
+
19
+ return ctx.currentStore
20
+ }
21
+
22
+ asyncEnd (ctx) {
23
+ const result = ctx.result
24
+ if (result?.isError) {
25
+ const span = ctx.currentStore?.span
26
+ const errorText = result.content?.find?.(c => c.type === 'text')?.text || 'Tool call returned isError: true'
27
+ span?.setTag('error', new Error(errorText))
28
+ }
29
+ super.finish(ctx)
30
+ }
31
+ }
32
+
33
+ class McpListToolsPlugin extends TracingPlugin {
34
+ static id = 'modelcontextprotocol_list_tools'
35
+ static prefix = 'tracing:orchestrion:@modelcontextprotocol/sdk:Client_listTools'
36
+
37
+ bindStart (ctx) {
38
+ this.startSpan('mcp.tools.list', {
39
+ resource: 'tools/list',
40
+ type: 'mcp',
41
+ kind: 'client',
42
+ }, ctx)
43
+
44
+ return ctx.currentStore
45
+ }
46
+
47
+ asyncEnd (ctx) {
48
+ super.finish(ctx)
49
+ }
50
+ }
51
+
52
+ module.exports = [
53
+ McpToolCallPlugin,
54
+ McpListToolsPlugin,
55
+ ]
@@ -1,8 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { isTrue } = require('../../dd-trace/src/util')
4
3
  const DatabasePlugin = require('../../dd-trace/src/plugins/database')
5
- const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
6
4
 
7
5
  class MongodbCorePlugin extends DatabasePlugin {
8
6
  static id = 'mongodb-core'
@@ -20,11 +18,8 @@ class MongodbCorePlugin extends DatabasePlugin {
20
18
  configure (config) {
21
19
  super.configure(config)
22
20
 
23
- const heartbeatFromEnv = getValueFromEnvSources('DD_TRACE_MONGODB_HEARTBEAT_ENABLED')
24
-
25
21
  this.config.heartbeatEnabled = config.heartbeatEnabled ??
26
- (heartbeatFromEnv && isTrue(heartbeatFromEnv)) ??
27
- true
22
+ this._tracerConfig.DD_TRACE_MONGODB_HEARTBEAT_ENABLED
28
23
  }
29
24
 
30
25
  bindStart (ctx) {
@@ -35,9 +30,9 @@ class MongodbCorePlugin extends DatabasePlugin {
35
30
  }
36
31
  const query = getQuery(ops)
37
32
  const resource = truncate(getResource(this, ns, query, name))
38
- const service = this.serviceName({ pluginConfig: this.config })
33
+ const serviceResult = this.serviceName({ pluginConfig: this.config })
39
34
  const span = this.startSpan(this.operationName(), {
40
- service,
35
+ service: serviceResult,
41
36
  resource,
42
37
  type: 'mongodb',
43
38
  kind: 'client',
@@ -49,7 +44,7 @@ class MongodbCorePlugin extends DatabasePlugin {
49
44
  'out.port': options.port,
50
45
  },
51
46
  }, ctx)
52
- const comment = this.injectDbmComment(span, ops.comment, service)
47
+ const comment = this.injectDbmComment(span, ops.comment, serviceResult.name)
53
48
  if (comment) {
54
49
  ops.comment = comment
55
50
  }
@@ -33,7 +33,7 @@ class MySQLPlugin extends DatabasePlugin {
33
33
  [CLIENT_PORT_KEY]: ctx.conf.port,
34
34
  },
35
35
  }, ctx)
36
- ctx.sql = this.injectDbmQuery(span, ctx.sql, service)
36
+ ctx.sql = this.injectDbmQuery(span, ctx.sql, service.name)
37
37
 
38
38
  return ctx.currentStore
39
39
  }
@@ -3,7 +3,7 @@
3
3
  const ServerPlugin = require('../../dd-trace/src/plugins/server')
4
4
  const { storage } = require('../../datadog-core')
5
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
- const { COMPONENT } = require('../../dd-trace/src/constants')
6
+ const { COMPONENT, SVC_SRC_KEY } = require('../../dd-trace/src/constants')
7
7
  const web = require('../../dd-trace/src/plugins/util/web')
8
8
 
9
9
  const errorPages = new Set(['/404', '/500', '/_error', '/_not-found', '/_not-found/page'])
@@ -19,15 +19,21 @@ class NextPlugin extends ServerPlugin {
19
19
  bindStart ({ req, res }) {
20
20
  const store = storage('legacy').getStore()
21
21
  const childOf = store ? store.span : store
22
+ const { name: schemaServiceName, source: schemaServiceSource } = this.serviceName()
23
+ const serviceName = this.config.service || schemaServiceName
24
+ let serviceSource = this.config.service ? 'opt.plugin' : schemaServiceSource
25
+ if (!serviceName || serviceName === this.tracer._service) serviceSource = undefined
26
+
22
27
  const span = this.tracer.startSpan(this.operationName(), {
23
28
  childOf,
24
29
  tags: {
25
30
  [COMPONENT]: this.constructor.id,
26
- 'service.name': this.config.service || this.serviceName(),
31
+ 'service.name': serviceName,
27
32
  'resource.name': req.method,
28
33
  'span.type': 'web',
29
34
  'span.kind': 'server',
30
35
  'http.method': req.method,
36
+ ...(serviceSource === undefined ? {} : { [SVC_SRC_KEY]: serviceSource }),
31
37
  },
32
38
  integrationName: this.constructor.id,
33
39
  })
@@ -32,7 +32,7 @@ class PGPlugin extends DatabasePlugin {
32
32
  span.setTag('db.stream', 1)
33
33
  }
34
34
 
35
- query.__ddInjectableQuery = this.injectDbmQuery(span, query.text, service, !!query.name)
35
+ query.__ddInjectableQuery = this.injectDbmQuery(span, query.text, service.name, !!query.name)
36
36
 
37
37
  return ctx.currentStore
38
38
  }
@@ -3,7 +3,6 @@
3
3
  const { storage } = require('../../datadog-core')
4
4
  const id = require('../../dd-trace/src/id')
5
5
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
6
- const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
7
6
 
8
7
  const {
9
8
  finishAllTraceSpans,
@@ -108,7 +107,7 @@ class PlaywrightPlugin extends CiPlugin {
108
107
  finishAllTraceSpans(this.testSessionSpan)
109
108
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
110
109
  provider: this.ciProviderName,
111
- autoInjected: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
110
+ autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
112
111
  })
113
112
  appClosingTelemetry()
114
113
  this.tracer._exporter.flush(onDone)
@@ -420,7 +419,7 @@ class PlaywrightPlugin extends CiPlugin {
420
419
  span.finish()
421
420
 
422
421
  finishAllTraceSpans(span)
423
- if (getValueFromEnvSources('DD_PLAYWRIGHT_WORKER')) {
422
+ if (this._tracerConfig.DD_PLAYWRIGHT_WORKER) {
424
423
  this.tracer._exporter.flush(onDone)
425
424
  }
426
425
  })
@@ -28,7 +28,7 @@ class TediousPlugin extends DatabasePlugin {
28
28
 
29
29
  // SQL Server includes comments when caching queries
30
30
  // For that reason we allow service mode but not full mode
31
- ctx.sql = this.injectDbmQuery(span, ctx.queryOrProcedure, service, true)
31
+ ctx.sql = this.injectDbmQuery(span, ctx.queryOrProcedure, service.name, true)
32
32
  return ctx.currentStore
33
33
  }
34
34
  }
@@ -2,7 +2,6 @@
2
2
 
3
3
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
4
4
  const { storage } = require('../../datadog-core')
5
- const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
6
5
 
7
6
  const {
8
7
  TEST_STATUS,
@@ -34,6 +33,7 @@ const {
34
33
  isModifiedTest,
35
34
  TEST_IS_MODIFIED,
36
35
  TEST_HAS_DYNAMIC_NAME,
36
+ TEST_FINAL_STATUS,
37
37
  } = require('../../dd-trace/src/plugins/util/test')
38
38
  const { COMPONENT } = require('../../dd-trace/src/constants')
39
39
  const {
@@ -213,10 +213,13 @@ class VitestPlugin extends CiPlugin {
213
213
  return ctx.currentStore
214
214
  })
215
215
 
216
- this.addSub('ci:vitest:test:pass', ({ span, task }) => {
216
+ this.addSub('ci:vitest:test:pass', ({ span, task, finalStatus }) => {
217
217
  if (span) {
218
218
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', this.getTestTelemetryTags(span))
219
219
  span.setTag(TEST_STATUS, 'pass')
220
+ if (finalStatus) {
221
+ span.setTag(TEST_FINAL_STATUS, finalStatus)
222
+ }
220
223
  span.finish(this.taskToFinishTime.get(task))
221
224
  finishAllTraceSpans(span)
222
225
  }
@@ -230,6 +233,7 @@ class VitestPlugin extends CiPlugin {
230
233
  promises,
231
234
  hasFailedAllRetries,
232
235
  attemptToFixFailed,
236
+ finalStatus,
233
237
  }) => {
234
238
  if (!span) {
235
239
  return
@@ -255,6 +259,9 @@ class VitestPlugin extends CiPlugin {
255
259
  if (attemptToFixFailed) {
256
260
  span.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'false')
257
261
  }
262
+ if (finalStatus) {
263
+ span.setTag(TEST_FINAL_STATUS, finalStatus)
264
+ }
258
265
  if (duration) {
259
266
  span.finish(span._startTime + duration - MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION) // milliseconds
260
267
  } else {
@@ -273,6 +280,7 @@ class VitestPlugin extends CiPlugin {
273
280
  [TEST_SOURCE_FILE]: testSuite,
274
281
  [TEST_SOURCE_START]: 1, // we can't get the proper start line in vitest
275
282
  [TEST_STATUS]: 'skip',
283
+ [TEST_FINAL_STATUS]: 'skip',
276
284
  ...(isDisabled ? { [TEST_MANAGEMENT_IS_DISABLED]: 'true' } : {}),
277
285
  ...(isNew ? { [TEST_IS_NEW]: 'true' } : {}),
278
286
  }
@@ -285,12 +293,12 @@ class VitestPlugin extends CiPlugin {
285
293
  const { testSuiteAbsolutePath, frameworkVersion } = ctx
286
294
 
287
295
  // TODO: Handle case where the command is not set
288
- this.command = getValueFromEnvSources('DD_CIVISIBILITY_TEST_COMMAND')
296
+ this.command = this._tracerConfig.DD_CIVISIBILITY_TEST_COMMAND
289
297
  this.frameworkVersion = frameworkVersion
290
298
  const testSessionSpanContext = this.tracer.extract('text_map', {
291
299
  // TODO: Handle case where the session ID or module ID is not set
292
- 'x-datadog-trace-id': getValueFromEnvSources('DD_CIVISIBILITY_TEST_SESSION_ID'),
293
- 'x-datadog-parent-id': getValueFromEnvSources('DD_CIVISIBILITY_TEST_MODULE_ID'),
300
+ 'x-datadog-trace-id': this._tracerConfig.DD_CIVISIBILITY_TEST_SESSION_ID,
301
+ 'x-datadog-parent-id': this._tracerConfig.DD_CIVISIBILITY_TEST_MODULE_ID,
294
302
  })
295
303
 
296
304
  const trimmedCommand = DD_MAJOR < 6 ? this.command : 'vitest run'
@@ -415,7 +423,7 @@ class VitestPlugin extends CiPlugin {
415
423
  finishAllTraceSpans(this.testSessionSpan)
416
424
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
417
425
  provider: this.ciProviderName,
418
- autoInjected: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
426
+ autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
419
427
  })
420
428
  this.tracer._exporter.flush(onFinish)
421
429
  })
@@ -47,7 +47,7 @@ class WSClosePlugin extends TracingPlugin {
47
47
  }
48
48
 
49
49
  if (isPeerClose && traceWebsocketMessagesInheritSampling && traceWebsocketMessagesSeparateTraces) {
50
- span.setTag('_dd.dm.service', spanTags['service.name'] || service)
50
+ span.setTag('_dd.dm.service', spanTags['service.name'] || service.name)
51
51
  span.setTag('_dd.dm.resource', spanTags['resource.name'] || `websocket ${path}`)
52
52
  span.setTag('_dd.dm.inherited', 1)
53
53
  }
@@ -57,11 +57,13 @@ class WSClosePlugin extends TracingPlugin {
57
57
  }
58
58
 
59
59
  bindAsyncStart (ctx) {
60
+ if (!ctx.span) return ctx.parentStore
60
61
  if (!ctx.isPeerClose) ctx.span.finish()
61
62
  return ctx.parentStore
62
63
  }
63
64
 
64
65
  asyncStart (ctx) {
66
+ if (!ctx.span) return
65
67
  ctx.span.finish()
66
68
  }
67
69
 
@@ -46,11 +46,13 @@ class WSProducerPlugin extends TracingPlugin {
46
46
  }
47
47
 
48
48
  bindAsyncStart (ctx) {
49
+ if (!ctx.span) return ctx.parentStore
49
50
  ctx.span.finish()
50
51
  return ctx.parentStore
51
52
  }
52
53
 
53
54
  asyncStart (ctx) {
55
+ if (!ctx.span) return
54
56
  ctx.span.finish()
55
57
  }
56
58
 
@@ -48,7 +48,7 @@ class WSReceiverPlugin extends TracingPlugin {
48
48
  }, ctx)
49
49
 
50
50
  if (traceWebsocketMessagesInheritSampling && traceWebsocketMessagesSeparateTraces) {
51
- span.setTag('_dd.dm.service', spanTags['service.name'] || service)
51
+ span.setTag('_dd.dm.service', spanTags['service.name'] || service.name)
52
52
  span.setTag('_dd.dm.resource', spanTags['resource.name'] || `websocket ${path}`)
53
53
  span.setTag('_dd.dm.inherited', 1)
54
54
  }
@@ -62,6 +62,7 @@ class WSReceiverPlugin extends TracingPlugin {
62
62
  }
63
63
 
64
64
  asyncStart (ctx) {
65
+ if (!ctx.span) return
65
66
  ctx.span.finish()
66
67
  }
67
68
 
@@ -0,0 +1,8 @@
1
+ 'use strict'
2
+
3
+ const dc = require('dc-polyfill')
4
+
5
+ module.exports = {
6
+ aiguardChannel: dc.channel('dd-trace:ai:aiguard'),
7
+ incomingHttpRequestStart: dc.channel('dd-trace:incomingHttpRequestStart'),
8
+ }
@@ -1,15 +1,17 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('dc-polyfill')
4
3
  const log = require('../log')
4
+ const { incomingHttpRequestStart, aiguardChannel } = require('./channels')
5
5
  const AIGuard = require('./sdk')
6
6
 
7
- const aiguardChannel = channel('dd-trace:ai:aiguard')
8
-
9
7
  let isEnabled = false
10
8
  let aiguard
11
9
  let block
12
10
 
11
+ function onIncomingHttpRequestStart () {
12
+ // No-op: subscribing ensures the HTTP plugin spreads req onto the store
13
+ }
14
+
13
15
  function enable (tracer, config) {
14
16
  if (isEnabled) return
15
17
 
@@ -17,6 +19,7 @@ function enable (tracer, config) {
17
19
  aiguard = new AIGuard(tracer, config)
18
20
  block = config.experimental?.aiguard?.block !== false
19
21
 
22
+ incomingHttpRequestStart.subscribe(onIncomingHttpRequestStart)
20
23
  aiguardChannel.subscribe(onEvaluate)
21
24
 
22
25
  isEnabled = true
@@ -29,6 +32,7 @@ function enable (tracer, config) {
29
32
  function disable () {
30
33
  if (!isEnabled) return
31
34
 
35
+ incomingHttpRequestStart.unsubscribe(onIncomingHttpRequestStart)
32
36
  aiguardChannel.unsubscribe(onEvaluate)
33
37
 
34
38
  aiguard = undefined
@@ -1,7 +1,10 @@
1
1
  'use strict'
2
2
 
3
3
  const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
4
+ const { HTTP_CLIENT_IP, NETWORK_CLIENT_IP } = require('../../../../ext/tags')
5
+ const { getActiveRequest } = require('../appsec/store')
4
6
  const log = require('../log')
7
+ const { extractIp } = require('../plugins/util/ip_extractor')
5
8
  const telemetryMetrics = require('../telemetry/metrics')
6
9
  const tracerVersion = require('../../../../package.json').version
7
10
  const { keepTrace } = require('../priority_sampler')
@@ -13,6 +16,7 @@ const {
13
16
  AI_GUARD_TARGET_TAG_KEY,
14
17
  AI_GUARD_REASON_TAG_KEY,
15
18
  AI_GUARD_ACTION_TAG_KEY,
19
+ AI_GUARD_EVENT_TAG_KEY,
16
20
  AI_GUARD_BLOCKED_TAG_KEY,
17
21
  AI_GUARD_META_STRUCT_KEY,
18
22
  AI_GUARD_TOOL_NAME_TAG_KEY,
@@ -25,11 +29,12 @@ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
25
29
  const ALLOW = 'ALLOW'
26
30
 
27
31
  class AIGuardAbortError extends Error {
28
- constructor (reason, tags, sds) {
32
+ constructor (reason, tags, tagProbs, sds) {
29
33
  super(reason)
30
34
  this.name = 'AIGuardAbortError'
31
35
  this.reason = reason
32
36
  this.tags = tags
37
+ this.tagProbabilities = tagProbs
33
38
  this.sds = sds || []
34
39
  }
35
40
  }
@@ -56,6 +61,7 @@ class AIGuard extends NoopAIGuard {
56
61
  #maxMessagesLength
57
62
  #maxContentSize
58
63
  #meta
64
+ #config
59
65
 
60
66
  /**
61
67
  * @param {import('../tracer')} tracer - Tracer instance
@@ -83,6 +89,7 @@ class AIGuard extends NoopAIGuard {
83
89
  this.#maxMessagesLength = config.experimental.aiguard.maxMessagesLength
84
90
  this.#maxContentSize = config.experimental.aiguard.maxContentSize
85
91
  this.#meta = { service: config.service, env: config.env }
92
+ this.#config = config
86
93
  this.#initialized = true
87
94
  }
88
95
 
@@ -138,6 +145,42 @@ class AIGuard extends NoopAIGuard {
138
145
  return null
139
146
  }
140
147
 
148
+ #setRootSpanClientIpTags (rootSpan) {
149
+ if (!rootSpan) return
150
+
151
+ const currentTags = rootSpan.context()._tags
152
+ const needsHttpClientIp = !Object.hasOwn(currentTags, HTTP_CLIENT_IP)
153
+ const needsNetworkClientIp = !Object.hasOwn(currentTags, NETWORK_CLIENT_IP)
154
+
155
+ if (!needsHttpClientIp && !needsNetworkClientIp) return
156
+
157
+ const req = getActiveRequest()
158
+
159
+ if (!req) return
160
+
161
+ const newTags = {}
162
+
163
+ if (needsHttpClientIp) {
164
+ const clientIp = extractIp(this.#config, req)
165
+
166
+ if (clientIp) {
167
+ newTags[HTTP_CLIENT_IP] = clientIp
168
+ }
169
+ }
170
+
171
+ if (needsNetworkClientIp) {
172
+ const networkClientIp = req.socket?.remoteAddress
173
+
174
+ if (networkClientIp) {
175
+ newTags[NETWORK_CLIENT_IP] = networkClientIp
176
+ }
177
+ }
178
+
179
+ if (Object.keys(newTags).length > 0) {
180
+ rootSpan.addTags(newTags)
181
+ }
182
+ }
183
+
141
184
  evaluate (messages, opts) {
142
185
  if (!this.#initialized) {
143
186
  return super.evaluate(messages, opts)
@@ -161,9 +204,11 @@ class AIGuard extends NoopAIGuard {
161
204
  }
162
205
  const rootSpan = span.context()?._trace?.started?.[0]
163
206
  if (rootSpan) {
207
+ this.#setRootSpanClientIpTags(rootSpan)
164
208
  // keepTrace must be called before executeRequest so the sampling decision
165
209
  // is propagated correctly to outgoing HTTP client calls.
166
210
  keepTrace(rootSpan, AI_GUARD)
211
+ rootSpan.setTag(AI_GUARD_EVENT_TAG_KEY, 'true')
167
212
  }
168
213
  let response
169
214
  try {
@@ -188,38 +233,37 @@ class AIGuard extends NoopAIGuard {
188
233
  `AI Guard service call failed, status ${response.status}`,
189
234
  { errors: response.body?.errors })
190
235
  }
191
- let action, reason, tags, sdsFindings, blockingEnabled
192
- try {
193
- const attr = response.body.data.attributes
194
- if (!attr.action) {
195
- throw new Error('Action missing from response')
196
- }
197
- action = attr.action
198
- reason = attr.reason
199
- tags = attr.tags
200
- sdsFindings = attr.sds_findings || []
201
- blockingEnabled = attr.is_blocking_enabled ?? false
202
- } catch (e) {
236
+ const attr = response.body?.data?.attributes
237
+ if (!attr?.action) {
203
238
  appsecMetrics.count(AI_GUARD_TELEMETRY_REQUESTS, { error: true }).inc(1)
204
- throw new AIGuardClientError(`AI Guard service returned unexpected response : ${response.body}`, { cause: e })
239
+ throw new AIGuardClientError(`AI Guard service returned unexpected response : ${response.body}`)
240
+ }
241
+ const action = attr.action
242
+ const reason = attr.reason
243
+ const tags = attr.tags ?? []
244
+ if (tags.length > 0) {
245
+ metaStruct.attack_categories = tags
205
246
  }
247
+ const sdsFindings = attr.sds_findings ?? []
248
+ if (sdsFindings.length > 0) {
249
+ metaStruct.sds = sdsFindings
250
+ }
251
+ const tagProbabilities = attr.tag_probs ?? {}
252
+ if (attr.tag_probs) {
253
+ metaStruct.tag_probs = tagProbabilities
254
+ }
255
+ const blockingEnabled = attr.is_blocking_enabled ?? false
206
256
  const shouldBlock = block && blockingEnabled && action !== ALLOW
207
257
  appsecMetrics.count(AI_GUARD_TELEMETRY_REQUESTS, { action, error: false, block: shouldBlock }).inc(1)
208
258
  span.setTag(AI_GUARD_ACTION_TAG_KEY, action)
209
259
  if (reason) {
210
260
  span.setTag(AI_GUARD_REASON_TAG_KEY, reason)
211
261
  }
212
- if (tags?.length > 0) {
213
- metaStruct.attack_categories = tags
214
- }
215
- if (sdsFindings?.length > 0) {
216
- metaStruct.sds = sdsFindings
217
- }
218
262
  if (shouldBlock) {
219
263
  span.setTag(AI_GUARD_BLOCKED_TAG_KEY, 'true')
220
- throw new AIGuardAbortError(reason, tags, sdsFindings)
264
+ throw new AIGuardAbortError(reason, tags, tagProbabilities, sdsFindings)
221
265
  }
222
- return { action, reason, tags, sds: sdsFindings }
266
+ return { action, reason, tags, tagProbabilities, sds: sdsFindings }
223
267
  })
224
268
  }
225
269
  }
@@ -7,6 +7,7 @@ module.exports = {
7
7
  AI_GUARD_ACTION_TAG_KEY: 'ai_guard.action',
8
8
  AI_GUARD_REASON_TAG_KEY: 'ai_guard.reason',
9
9
  AI_GUARD_BLOCKED_TAG_KEY: 'ai_guard.blocked',
10
+ AI_GUARD_EVENT_TAG_KEY: 'ai_guard.event',
10
11
  AI_GUARD_META_STRUCT_KEY: 'ai_guard',
11
12
 
12
13
  AI_GUARD_TELEMETRY_REQUESTS: 'ai_guard.requests',
@@ -1,11 +1,12 @@
1
1
  /* eslint-disable @stylistic/max-len */
2
+ /* eslint-disable @stylistic/quotes */
2
3
  'use strict'
3
4
 
4
- const html = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>You\'ve been blocked</title><style>a,body,div,html,span{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background:-webkit-radial-gradient(26% 19%,circle,#fff,#f4f7f9);background:radial-gradient(circle at 26% 19%,#fff,#f4f7f9);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;width:100%;min-height:100vh;line-height:1;flex-direction:column}p{display:block}main{text-align:center;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;flex-direction:column}p{font-size:18px;line-height:normal;color:#646464;font-family:sans-serif;font-weight:400}a{color:#4842b7}footer{width:100%;text-align:center}footer p{font-size:16px}</style></head><body><main><p>Sorry, you cannot access this page. Please contact the customer service team.</p></main><footer><p>Security provided by <a href="https://www.datadoghq.com/product/security-platform/application-security-monitoring/" target="_blank">Datadog</a></p></footer></body></html>'
5
+ const html = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>You've been blocked</title><style>a,body,div,html,span{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background:-webkit-radial-gradient(26% 19%,circle,#fff,#f4f7f9);background:radial-gradient(circle at 26% 19%,#fff,#f4f7f9);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;width:100%;min-height:100vh;line-height:1;flex-direction:column}p{display:block}main{text-align:center;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;flex-direction:column}p{font-size:18px;line-height:normal;color:#646464;font-family:sans-serif;font-weight:400}a{color:#4842b7}footer{width:100%;text-align:center}footer p{font-size:16px}.security-response-id{font-size:14px;color:#999;margin-top:20px;font-family:monospace}</style></head><body><main><p>Sorry, you cannot access this page. Please contact the customer service team.</p><p class="security-response-id">Security Response ID: [security_response_id]</p></main><footer><p>Security provided by <a href="https://www.datadoghq.com/product/security-platform/application-security-monitoring/" target="_blank" rel="noopener noreferrer">Datadog</a></p></footer></body></html>`
5
6
 
6
- const json = '{"errors":[{"title":"You\'ve been blocked","detail":"Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."}]}'
7
+ const json = `{"errors":[{"title":"You've been blocked","detail":"Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."}],"security_response_id":"[security_response_id]"}`
7
8
 
8
- const graphqlJson = '{"errors":[{"message":"You\'ve been blocked","extensions":{"detail":"Sorry, you cannot perform this operation. Please contact the customer service team. Security provided by Datadog."}}]}'
9
+ const graphqlJson = `{"errors":[{"message":"You've been blocked","extensions":{"detail":"Sorry, you cannot perform this operation. Please contact the customer service team. Security provided by Datadog."}}],"security_response_id":"[security_response_id]"}`
9
10
 
10
11
  module.exports = {
11
12
  html,