dd-trace 5.54.0 → 5.56.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 (191) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ci/cypress/plugin.js +8 -0
  3. package/ci/cypress/polyfills.js +23 -0
  4. package/ci/init.js +8 -7
  5. package/initialize.mjs +2 -2
  6. package/package.json +10 -9
  7. package/packages/datadog-code-origin/index.js +22 -4
  8. package/packages/datadog-core/src/utils/src/kebabcase.js +3 -3
  9. package/packages/datadog-core/src/utils/src/set.js +8 -10
  10. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -6
  11. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +2 -3
  12. package/packages/datadog-instrumentations/src/cookie-parser.js +1 -1
  13. package/packages/datadog-instrumentations/src/couchbase.js +3 -6
  14. package/packages/datadog-instrumentations/src/cucumber.js +21 -28
  15. package/packages/datadog-instrumentations/src/dns.js +4 -4
  16. package/packages/datadog-instrumentations/src/elasticsearch.js +9 -10
  17. package/packages/datadog-instrumentations/src/fastify.js +7 -9
  18. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +14 -16
  19. package/packages/datadog-instrumentations/src/hapi.js +10 -11
  20. package/packages/datadog-instrumentations/src/helpers/fetch.js +4 -5
  21. package/packages/datadog-instrumentations/src/helpers/hook.js +1 -2
  22. package/packages/datadog-instrumentations/src/helpers/register.js +6 -5
  23. package/packages/datadog-instrumentations/src/jest.js +421 -376
  24. package/packages/datadog-instrumentations/src/koa.js +2 -3
  25. package/packages/datadog-instrumentations/src/mariadb.js +11 -4
  26. package/packages/datadog-instrumentations/src/mocha/main.js +79 -75
  27. package/packages/datadog-instrumentations/src/mocha.js +3 -1
  28. package/packages/datadog-instrumentations/src/mysql.js +11 -2
  29. package/packages/datadog-instrumentations/src/nyc.js +2 -1
  30. package/packages/datadog-instrumentations/src/openai.js +2 -2
  31. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +4 -3
  32. package/packages/datadog-instrumentations/src/pg.js +2 -3
  33. package/packages/datadog-instrumentations/src/playwright.js +19 -22
  34. package/packages/datadog-instrumentations/src/protobufjs.js +3 -4
  35. package/packages/datadog-instrumentations/src/redis.js +1 -1
  36. package/packages/datadog-instrumentations/src/restify.js +9 -13
  37. package/packages/datadog-instrumentations/src/router.js +12 -11
  38. package/packages/datadog-instrumentations/src/tedious.js +1 -2
  39. package/packages/datadog-instrumentations/src/vitest.js +15 -29
  40. package/packages/datadog-plugin-avsc/src/schema_iterator.js +12 -12
  41. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -8
  42. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +3 -5
  43. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +12 -20
  44. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -5
  45. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +3 -5
  46. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +3 -5
  47. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +3 -5
  48. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
  49. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +7 -10
  50. package/packages/datadog-plugin-azure-functions/src/index.js +5 -4
  51. package/packages/datadog-plugin-cucumber/src/index.js +3 -2
  52. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -1
  53. package/packages/datadog-plugin-dd-trace-api/src/index.js +2 -1
  54. package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
  55. package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +1 -1
  56. package/packages/datadog-plugin-graphql/src/index.js +3 -2
  57. package/packages/datadog-plugin-graphql/src/resolve.js +17 -10
  58. package/packages/datadog-plugin-http/src/client.js +5 -6
  59. package/packages/datadog-plugin-http2/src/client.js +7 -8
  60. package/packages/datadog-plugin-jest/src/index.js +3 -2
  61. package/packages/datadog-plugin-mocha/src/index.js +6 -1
  62. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  63. package/packages/datadog-plugin-mysql/src/index.js +11 -0
  64. package/packages/datadog-plugin-next/src/index.js +1 -1
  65. package/packages/datadog-plugin-openai/src/tracing.js +2 -4
  66. package/packages/datadog-plugin-oracledb/src/index.js +2 -1
  67. package/packages/datadog-plugin-playwright/src/index.js +3 -2
  68. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +8 -9
  69. package/packages/datadog-plugin-redis/src/index.js +1 -3
  70. package/packages/datadog-plugin-vitest/src/index.js +5 -4
  71. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +0 -1
  72. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +0 -1
  73. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +0 -1
  74. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -1
  75. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +1 -2
  76. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  77. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +12 -13
  78. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +44 -1
  79. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -1
  80. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -3
  81. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -1
  82. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +1 -1
  83. package/packages/dd-trace/src/appsec/iast/telemetry/verbosity.js +1 -2
  84. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/range-utils.js +10 -11
  85. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +0 -4
  86. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +0 -1
  87. package/packages/dd-trace/src/appsec/index.js +16 -5
  88. package/packages/dd-trace/src/appsec/reporter.js +11 -11
  89. package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
  90. package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -3
  91. package/packages/dd-trace/src/appsec/telemetry/index.js +31 -1
  92. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +6 -2
  93. package/packages/dd-trace/src/azure_metadata.js +8 -3
  94. package/packages/dd-trace/src/baggage.js +2 -2
  95. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +8 -7
  96. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -1
  97. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -1
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -1
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -1
  100. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +4 -3
  101. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +7 -6
  102. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
  103. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -3
  104. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -3
  105. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -1
  106. package/packages/dd-trace/src/config-helper.js +89 -0
  107. package/packages/dd-trace/src/config.js +120 -115
  108. package/packages/dd-trace/src/config_stable.js +7 -4
  109. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  110. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +6 -6
  111. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +1 -2
  112. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -2
  113. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -1
  114. package/packages/dd-trace/src/debugger/devtools_client/send.js +8 -3
  115. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -2
  116. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +3 -4
  117. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +1 -1
  118. package/packages/dd-trace/src/debugger/devtools_client/status.js +5 -1
  119. package/packages/dd-trace/src/debugger/index.js +1 -0
  120. package/packages/dd-trace/src/dogstatsd.js +2 -2
  121. package/packages/dd-trace/src/encode/0.4.js +5 -2
  122. package/packages/dd-trace/src/encode/0.5.js +3 -5
  123. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +5 -5
  124. package/packages/dd-trace/src/exporter.js +2 -1
  125. package/packages/dd-trace/src/exporters/agent/writer.js +3 -1
  126. package/packages/dd-trace/src/exporters/common/docker.js +3 -2
  127. package/packages/dd-trace/src/exporters/common/request.js +4 -1
  128. package/packages/dd-trace/src/exporters/common/util.js +3 -1
  129. package/packages/dd-trace/src/id.js +3 -3
  130. package/packages/dd-trace/src/index.js +4 -3
  131. package/packages/dd-trace/src/lambda/handler.js +2 -1
  132. package/packages/dd-trace/src/lambda/index.js +2 -1
  133. package/packages/dd-trace/src/lambda/runtime/patch.js +3 -2
  134. package/packages/dd-trace/src/lambda/runtime/ritm.js +3 -2
  135. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
  136. package/packages/dd-trace/src/llmobs/index.js +21 -5
  137. package/packages/dd-trace/src/llmobs/noop.js +18 -20
  138. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +11 -13
  139. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -2
  140. package/packages/dd-trace/src/llmobs/sdk.js +2 -1
  141. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  142. package/packages/dd-trace/src/llmobs/tagger.js +19 -6
  143. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  144. package/packages/dd-trace/src/log/index.js +5 -4
  145. package/packages/dd-trace/src/log/writer.js +1 -2
  146. package/packages/dd-trace/src/msgpack/encoder.js +3 -3
  147. package/packages/dd-trace/src/noop/span.js +1 -1
  148. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  149. package/packages/dd-trace/src/opentracing/propagation/log.js +4 -5
  150. package/packages/dd-trace/src/opentracing/propagation/text_map.js +35 -42
  151. package/packages/dd-trace/src/opentracing/span.js +7 -6
  152. package/packages/dd-trace/src/payload-tagging/config/index.js +17 -21
  153. package/packages/dd-trace/src/plugin_manager.js +4 -3
  154. package/packages/dd-trace/src/plugins/ci_plugin.js +25 -1
  155. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  156. package/packages/dd-trace/src/plugins/util/ci.js +7 -7
  157. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  158. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  159. package/packages/dd-trace/src/plugins/util/stacktrace.js +8 -1
  160. package/packages/dd-trace/src/plugins/util/test.js +4 -3
  161. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -1
  162. package/packages/dd-trace/src/plugins/util/web.js +3 -4
  163. package/packages/dd-trace/src/priority_sampler.js +46 -35
  164. package/packages/dd-trace/src/profiling/config.js +12 -32
  165. package/packages/dd-trace/src/profiling/exporter_cli.js +20 -20
  166. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  167. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +2 -1
  168. package/packages/dd-trace/src/profiling/index.js +2 -1
  169. package/packages/dd-trace/src/profiling/profiler.js +7 -4
  170. package/packages/dd-trace/src/profiling/profilers/events.js +10 -2
  171. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +3 -1
  172. package/packages/dd-trace/src/profiling/tagger.js +22 -12
  173. package/packages/dd-trace/src/proxy.js +2 -1
  174. package/packages/dd-trace/src/ritm.js +4 -4
  175. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -2
  176. package/packages/dd-trace/src/sampler.js +10 -2
  177. package/packages/dd-trace/src/serverless.js +11 -4
  178. package/packages/dd-trace/src/span_processor.js +2 -1
  179. package/packages/dd-trace/src/standalone/tracesource.js +1 -2
  180. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +1 -2
  181. package/packages/dd-trace/src/startup-log.js +5 -17
  182. package/packages/dd-trace/src/supported-configurations.json +440 -0
  183. package/packages/dd-trace/src/telemetry/dependencies.js +62 -57
  184. package/packages/dd-trace/src/telemetry/send-data.js +7 -6
  185. package/packages/dd-trace/src/telemetry/telemetry.js +16 -26
  186. package/packages/dd-trace/src/tracer.js +3 -7
  187. package/packages/dd-trace/src/util.js +0 -5
  188. package/packages/datadog-core/src/utils/src/get.js +0 -11
  189. package/packages/datadog-core/src/utils/src/has.js +0 -14
  190. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +0 -120
  191. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +0 -20
@@ -96,7 +96,7 @@ function formatHeaderName (name) {
96
96
  return name
97
97
  .trim()
98
98
  .slice(0, 200)
99
- .replace(/[^a-zA-Z0-9_\-:/]/g, '_')
99
+ .replaceAll(/[^a-zA-Z0-9_\-:/]/g, '_')
100
100
  .toLowerCase()
101
101
  }
102
102
 
@@ -116,7 +116,7 @@ function filterHeaders (headers, map) {
116
116
  for (const [headerName, tagName] of map) {
117
117
  const headerValue = headers[headerName]
118
118
  if (headerValue) {
119
- result[tagName] = '' + headerValue
119
+ result[tagName] = String(headerValue)
120
120
  }
121
121
  }
122
122
 
@@ -132,7 +132,7 @@ function filterExtendedHeaders (headers, excludedHeaderNames, tagPrefix, limit =
132
132
  for (const [headerName, headerValue] of Object.entries(headers)) {
133
133
  if (counter >= limit) break
134
134
  if (!excludedHeaderNames.has(headerName)) {
135
- result[getHeaderTag(tagPrefix, headerName)] = '' + headerValue
135
+ result[getHeaderTag(tagPrefix, headerName)] = String(headerValue)
136
136
  counter++
137
137
  }
138
138
  }
@@ -140,14 +140,16 @@ function filterExtendedHeaders (headers, excludedHeaderNames, tagPrefix, limit =
140
140
  return result
141
141
  }
142
142
 
143
- function getCollectedHeaders (req, res, shouldCollectEventHeaders) {
143
+ function getCollectedHeaders (req, res, shouldCollectEventHeaders, storedResponseHeaders = {}) {
144
144
  // Mandatory
145
145
  const mandatoryCollectedHeaders = filterHeaders(req.headers, REQUEST_HEADERS_MAP)
146
146
 
147
147
  // Basic collection
148
148
  if (!shouldCollectEventHeaders) return mandatoryCollectedHeaders
149
149
 
150
- const responseHeaders = res.getHeaders()
150
+ const responseHeaders = Object.keys(storedResponseHeaders).length === 0
151
+ ? res.getHeaders()
152
+ : { ...storedResponseHeaders, ...res.getHeaders() }
151
153
 
152
154
  const requestEventCollectedHeaders = filterHeaders(req.headers, EVENT_HEADERS_MAP)
153
155
  const responseEventCollectedHeaders = filterHeaders(responseHeaders, RESPONSE_HEADERS_MAP)
@@ -301,8 +303,6 @@ function reportAttack (attackData) {
301
303
  }
302
304
 
303
305
  function truncateRequestBody (target, depth = 0) {
304
- let wasTruncated = false
305
-
306
306
  switch (typeof target) {
307
307
  case 'string':
308
308
  if (target.length > COLLECTED_REQUEST_BODY_MAX_STRING_LENGTH) {
@@ -328,7 +328,7 @@ function truncateRequestBody (target, depth = 0) {
328
328
 
329
329
  if (Array.isArray(target)) {
330
330
  const maxArrayLength = Math.min(target.length, COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE)
331
- wasTruncated = target.length > COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE
331
+ let wasTruncated = target.length > COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE
332
332
  const truncatedArray = new Array(maxArrayLength)
333
333
  for (let i = 0; i < maxArrayLength; i++) {
334
334
  const { value, truncated } = truncateRequestBody(target[i], depth + 1)
@@ -341,7 +341,7 @@ function truncateRequestBody (target, depth = 0) {
341
341
 
342
342
  const keys = Object.keys(target)
343
343
  const maxKeysLength = Math.min(keys.length, COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE)
344
- wasTruncated = keys.length > COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE
344
+ let wasTruncated = keys.length > COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE
345
345
 
346
346
  const truncatedObject = {}
347
347
  for (let i = 0; i < maxKeysLength; i++) {
@@ -401,7 +401,7 @@ function reportDerivatives (derivatives) {
401
401
  rootSpan.addTags(tags)
402
402
  }
403
403
 
404
- function finishRequest (req, res) {
404
+ function finishRequest (req, res, storedResponseHeaders) {
405
405
  const rootSpan = web.root(req)
406
406
  if (!rootSpan) return
407
407
 
@@ -455,7 +455,7 @@ function finishRequest (req, res) {
455
455
 
456
456
  const tags = rootSpan.context()._tags
457
457
 
458
- const newTags = getCollectedHeaders(req, res, shouldCollectEventHeaders(tags))
458
+ const newTags = getCollectedHeaders(req, res, shouldCollectEventHeaders(tags), storedResponseHeaders)
459
459
 
460
460
  if (tags['appsec.event'] === 'true' && typeof req.route?.path === 'string') {
461
461
  newTags['http.endpoint'] = req.route.path
@@ -7,7 +7,7 @@ const addresses = require('../addresses')
7
7
 
8
8
  function setUserTags (user, rootSpan) {
9
9
  for (const k of Object.keys(user)) {
10
- rootSpan.setTag(`usr.${k}`, '' + user[k])
10
+ rootSpan.setTag(`usr.${k}`, String(user[k]))
11
11
  }
12
12
 
13
13
  rootSpan.setTag('_dd.appsec.user.collection_mode', 'sdk')
@@ -28,7 +28,7 @@ function setUser (tracer, user) {
28
28
  setUserTags(user, rootSpan)
29
29
 
30
30
  const persistent = {
31
- [addresses.USER_ID]: '' + user.id
31
+ [addresses.USER_ID]: String(user.id)
32
32
  }
33
33
 
34
34
  if (user.session_id && typeof user.session_id === 'string') {
@@ -196,7 +196,7 @@ function trackEvent (eventName, fields, sdkMethodName, rootSpan) {
196
196
  }
197
197
 
198
198
  for (const metadataKey of Object.keys(flatFields)) {
199
- tags[`appsec.events.${eventName}.${metadataKey}`] = '' + flatFields[metadataKey]
199
+ tags[`appsec.events.${eventName}.${metadataKey}`] = String(flatFields[metadataKey])
200
200
  }
201
201
  }
202
202
 
@@ -211,11 +211,11 @@ function runWaf (eventName, user) {
211
211
  }
212
212
 
213
213
  if (user?.id) {
214
- persistent[addresses.USER_ID] = '' + user.id
214
+ persistent[addresses.USER_ID] = String(user.id)
215
215
  }
216
216
 
217
217
  if (user?.login) {
218
- persistent[addresses.USER_LOGIN] = '' + user.login
218
+ persistent[addresses.USER_LOGIN] = String(user.login)
219
219
  }
220
220
 
221
221
  waf.run({ persistent })
@@ -15,17 +15,47 @@ const {
15
15
  incrementWafUpdates,
16
16
  incrementWafRequests
17
17
  } = require('./waf')
18
+ const telemetryMetrics = require('../../telemetry/metrics')
18
19
 
19
20
  const metricsStoreMap = new WeakMap()
20
21
 
22
+ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
23
+
21
24
  let enabled = false
25
+ let interval
26
+ const SUPPORTED_ORIGINS = new Set(['env_var', 'code', 'remote_config', 'unknown'])
22
27
 
23
- function enable (telemetryConfig) {
28
+ function enable (config) {
29
+ const telemetryConfig = config.telemetry
24
30
  enabled = telemetryConfig?.enabled && telemetryConfig.metrics
31
+
32
+ if (enabled) {
33
+ let origin = 'remote_config'
34
+
35
+ if (config.appsec.enabled) {
36
+ origin = config.getOrigin('appsec.enabled')
37
+
38
+ if (!SUPPORTED_ORIGINS.has(origin)) {
39
+ origin = 'unknown'
40
+ }
41
+ }
42
+
43
+ const gauge = appsecMetrics.gauge('enabled', { origin })
44
+ gauge.track()
45
+
46
+ interval = setInterval(() => {
47
+ gauge.track()
48
+ }, telemetryConfig.heartbeatInterval)
49
+ interval.unref?.()
50
+ }
25
51
  }
26
52
 
27
53
  function disable () {
28
54
  enabled = false
55
+ if (interval) {
56
+ clearInterval(interval)
57
+ interval = undefined
58
+ }
29
59
  }
30
60
 
31
61
  function newStore () {
@@ -49,8 +49,10 @@ class WAFContextWrapper {
49
49
  if (persistent !== null && typeof persistent === 'object') {
50
50
  const persistentInputs = {}
51
51
 
52
+ let hasPersistentInputs = false
52
53
  for (const key of Object.keys(persistent)) {
53
54
  if (!this.addressesToSkip.has(key) && this.knownAddresses.has(key)) {
55
+ hasPersistentInputs = true
54
56
  persistentInputs[key] = persistent[key]
55
57
  if (preventDuplicateAddresses.has(key)) {
56
58
  newAddressesToSkip.add(key)
@@ -58,7 +60,7 @@ class WAFContextWrapper {
58
60
  }
59
61
  }
60
62
 
61
- if (Object.keys(persistentInputs).length) {
63
+ if (hasPersistentInputs) {
62
64
  payload.persistent = persistentInputs
63
65
  payloadHasData = true
64
66
  }
@@ -67,13 +69,15 @@ class WAFContextWrapper {
67
69
  if (ephemeral !== null && typeof ephemeral === 'object') {
68
70
  const ephemeralInputs = {}
69
71
 
72
+ let hasEphemeral = false
70
73
  for (const key of Object.keys(ephemeral)) {
71
74
  if (this.knownAddresses.has(key)) {
75
+ hasEphemeral = true
72
76
  ephemeralInputs[key] = ephemeral[key]
73
77
  }
74
78
  }
75
79
 
76
- if (Object.keys(ephemeralInputs).length) {
80
+ if (hasEphemeral) {
77
81
  payload.ephemeral = ephemeralInputs
78
82
  payloadHasData = true
79
83
  }
@@ -4,6 +4,7 @@
4
4
 
5
5
  const os = require('os')
6
6
  const { getIsAzureFunction } = require('./serverless')
7
+ const { getEnvironmentVariable, getEnvironmentVariables } = require('../../dd-trace/src/config-helper')
7
8
 
8
9
  function extractSubscriptionID (ownerName) {
9
10
  if (ownerName !== undefined) {
@@ -45,7 +46,7 @@ function buildMetadata () {
45
46
  WEBSITE_OS,
46
47
  WEBSITE_RESOURCE_GROUP,
47
48
  WEBSITE_SITE_NAME
48
- } = process.env
49
+ } = getEnvironmentVariables()
49
50
 
50
51
  const subscriptionID = extractSubscriptionID(WEBSITE_OWNER_NAME)
51
52
 
@@ -78,11 +79,15 @@ function getAzureAppMetadata () {
78
79
  // DD_AZURE_APP_SERVICES is an environment variable introduced by the .NET APM team and is set automatically for
79
80
  // anyone using the Datadog APM Extensions (.NET, Java, or Node) for Windows Azure App Services
80
81
  // See: https://github.com/DataDog/datadog-aas-extension/blob/01f94b5c28b7fa7a9ab264ca28bd4e03be603900/node/src/applicationHost.xdt#L20-L21
81
- return process.env.DD_AZURE_APP_SERVICES === undefined ? undefined : buildMetadata()
82
+ if (getEnvironmentVariable('DD_AZURE_APP_SERVICES') !== undefined) {
83
+ return buildMetadata()
84
+ }
82
85
  }
83
86
 
84
87
  function getAzureFunctionMetadata () {
85
- return getIsAzureFunction() ? buildMetadata() : undefined
88
+ if (getIsAzureFunction()) {
89
+ return buildMetadata()
90
+ }
86
91
  }
87
92
 
88
93
  // Modeled after https://github.com/DataDog/libdatadog/blob/92272e90a7919f07178f3246ef8f82295513cfed/profiling/src/exporter/mod.rs#L187
@@ -13,7 +13,7 @@ function getBaggageItem (key) {
13
13
  }
14
14
 
15
15
  function getAllBaggageItems () {
16
- return storage('baggage').getStore()
16
+ return storage('baggage').getStore() ?? {}
17
17
  }
18
18
 
19
19
  function removeBaggageItem (keyToRemove) {
@@ -23,7 +23,7 @@ function removeBaggageItem (keyToRemove) {
23
23
  }
24
24
 
25
25
  function removeAllBaggageItems () {
26
- storage('baggage').enterWith({})
26
+ storage('baggage').enterWith()
27
27
  return storage('baggage').getStore()
28
28
  }
29
29
 
@@ -4,6 +4,7 @@ const { join } = require('path')
4
4
  const { Worker, threadId: parentThreadId } = require('worker_threads')
5
5
  const { randomUUID } = require('crypto')
6
6
  const log = require('../../log')
7
+ const { getEnvironmentVariables } = require('../../config-helper')
7
8
 
8
9
  const probeIdToResolveBreakpointSet = new Map()
9
10
  const probeIdToResolveBreakpointRemove = new Map()
@@ -72,13 +73,13 @@ class TestVisDynamicInstrumentation {
72
73
  // for PnP support, hence why we deviate from the DI pattern here.
73
74
  // To avoid infinite initialization loops, we're disabling DI and tracing in the worker.
74
75
  env: {
75
- ...process.env,
76
- DD_CIVISIBILITY_ENABLED: 0,
77
- DD_TRACE_ENABLED: 0,
78
- DD_TEST_FAILED_TEST_REPLAY_ENABLED: 0,
79
- DD_CIVISIBILITY_MANUAL_API_ENABLED: 0,
80
- DD_TRACING_ENABLED: 0,
81
- DD_TRACE_TELEMETRY_ENABLED: 0
76
+ ...getEnvironmentVariables(),
77
+ DD_CIVISIBILITY_ENABLED: 'false',
78
+ DD_TRACE_ENABLED: 'false',
79
+ DD_TEST_FAILED_TEST_REPLAY_ENABLED: 'false',
80
+ DD_CIVISIBILITY_MANUAL_API_ENABLED: 'false',
81
+ DD_TRACING_ENABLED: 'false',
82
+ DD_INSTRUMENTATION_TELEMETRY_ENABLED: 'false'
82
83
  },
83
84
  workerData: {
84
85
  config: this._config.serialize(),
@@ -1,6 +1,7 @@
1
1
  const request = require('../../exporters/common/request')
2
2
  const id = require('../../id')
3
3
  const log = require('../../log')
4
+ const { getEnvironmentVariable } = require('../../config-helper')
4
5
 
5
6
  const {
6
7
  incrementCountMetric,
@@ -48,7 +49,7 @@ function getKnownTests ({
48
49
  options.path = `${evpProxyPrefix}/api/v2/ci/libraries/tests`
49
50
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
50
51
  } else {
51
- const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
52
+ const apiKey = getEnvironmentVariable('DD_API_KEY')
52
53
  if (!apiKey) {
53
54
  return done(new Error('Known tests were not fetched because Datadog API key is not defined.'))
54
55
  }
@@ -2,6 +2,7 @@
2
2
  const request = require('../../../exporters/common/request')
3
3
  const log = require('../../../log')
4
4
  const { safeJSONStringify } = require('../../../exporters/common/util')
5
+ const { getEnvironmentVariable } = require('../../../config-helper')
5
6
 
6
7
  const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
7
8
  const BaseWriter = require('../../../exporters/common/writer')
@@ -28,7 +29,7 @@ class Writer extends BaseWriter {
28
29
  path: '/api/v2/citestcov',
29
30
  method: 'POST',
30
31
  headers: {
31
- 'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
32
+ 'dd-api-key': getEnvironmentVariable('DD_API_KEY'),
32
33
  ...form.getHeaders()
33
34
  },
34
35
  timeout: 15_000,
@@ -3,6 +3,7 @@ const request = require('../../../exporters/common/request')
3
3
  const log = require('../../../log')
4
4
  const { safeJSONStringify } = require('../../../exporters/common/util')
5
5
  const { JSONEncoder } = require('../../encode/json-encoder')
6
+ const { getEnvironmentVariable } = require('../../../config-helper')
6
7
 
7
8
  const BaseWriter = require('../../../exporters/common/writer')
8
9
 
@@ -23,7 +24,7 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
23
24
  path: '/api/v2/logs',
24
25
  method: 'POST',
25
26
  headers: {
26
- 'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
27
+ 'dd-api-key': getEnvironmentVariable('DD_API_KEY'),
27
28
  'Content-Type': 'application/json'
28
29
  },
29
30
  // TODO: what's a good value for timeout for the logs intake?
@@ -2,6 +2,7 @@
2
2
  const request = require('../../../exporters/common/request')
3
3
  const { safeJSONStringify } = require('../../../exporters/common/util')
4
4
  const log = require('../../../log')
5
+ const { getEnvironmentVariable } = require('../../../config-helper')
5
6
 
6
7
  const { AgentlessCiVisibilityEncoder } = require('../../../encode/agentless-ci-visibility')
7
8
  const BaseWriter = require('../../../exporters/common/writer')
@@ -29,7 +30,7 @@ class Writer extends BaseWriter {
29
30
  path: '/api/v2/citestcycle',
30
31
  method: 'POST',
31
32
  headers: {
32
- 'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
33
+ 'dd-api-key': getEnvironmentVariable('DD_API_KEY'),
33
34
  'Content-Type': 'application/msgpack'
34
35
  },
35
36
  timeout: 15_000,
@@ -3,6 +3,7 @@ const path = require('path')
3
3
 
4
4
  const FormData = require('../../../exporters/common/form-data')
5
5
  const request = require('../../../exporters/common/request')
6
+ const { getEnvironmentVariable } = require('../../../config-helper')
6
7
 
7
8
  const log = require('../../../log')
8
9
  const { isFalse } = require('../../../util')
@@ -38,7 +39,7 @@ function validateCommits (commits) {
38
39
  throw new Error('Invalid commit type response')
39
40
  }
40
41
  if (isValidSha1(commitSha) || isValidSha256(commitSha)) {
41
- return commitSha.replace(/[^0-9a-f]+/g, '')
42
+ return commitSha.replaceAll(/[^0-9a-f]+/g, '')
42
43
  }
43
44
  throw new Error('Invalid commit format')
44
45
  })
@@ -48,7 +49,7 @@ function getCommonRequestOptions (url) {
48
49
  return {
49
50
  method: 'POST',
50
51
  headers: {
51
- 'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY
52
+ 'dd-api-key': getEnvironmentVariable('DD_API_KEY')
52
53
  },
53
54
  timeout: 15_000,
54
55
  url
@@ -285,7 +286,7 @@ function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryU
285
286
  }
286
287
  // Otherwise we unshallow and get commits to upload again
287
288
  log.debug('It is shallow clone, unshallowing...')
288
- if (!isFalse(process.env.DD_CIVISIBILITY_GIT_UNSHALLOW_ENABLED)) {
289
+ if (!isFalse(getEnvironmentVariable('DD_CIVISIBILITY_GIT_UNSHALLOW_ENABLED'))) {
289
290
  unshallowRepository()
290
291
  }
291
292
 
@@ -9,18 +9,19 @@ const {
9
9
  JEST_WORKER_LOGS_PAYLOAD_CODE,
10
10
  PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE
11
11
  } = require('../../../plugins/util/test')
12
+ const { getEnvironmentVariable } = require('../../../config-helper')
12
13
 
13
14
  function getInterprocessTraceCode () {
14
- if (process.env.JEST_WORKER_ID) {
15
+ if (getEnvironmentVariable('JEST_WORKER_ID')) {
15
16
  return JEST_WORKER_TRACE_PAYLOAD_CODE
16
17
  }
17
- if (process.env.CUCUMBER_WORKER_ID) {
18
+ if (getEnvironmentVariable('CUCUMBER_WORKER_ID')) {
18
19
  return CUCUMBER_WORKER_TRACE_PAYLOAD_CODE
19
20
  }
20
- if (process.env.MOCHA_WORKER_ID) {
21
+ if (getEnvironmentVariable('MOCHA_WORKER_ID')) {
21
22
  return MOCHA_WORKER_TRACE_PAYLOAD_CODE
22
23
  }
23
- if (process.env.DD_PLAYWRIGHT_WORKER) {
24
+ if (getEnvironmentVariable('DD_PLAYWRIGHT_WORKER')) {
24
25
  return PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE
25
26
  }
26
27
  return null
@@ -28,14 +29,14 @@ function getInterprocessTraceCode () {
28
29
 
29
30
  // TODO: make it available with cucumber
30
31
  function getInterprocessCoverageCode () {
31
- if (process.env.JEST_WORKER_ID) {
32
+ if (getEnvironmentVariable('JEST_WORKER_ID')) {
32
33
  return JEST_WORKER_COVERAGE_PAYLOAD_CODE
33
34
  }
34
35
  return null
35
36
  }
36
37
 
37
38
  function getInterprocessLogsCode () {
38
- if (process.env.JEST_WORKER_ID) {
39
+ if (getEnvironmentVariable('JEST_WORKER_ID')) {
39
40
  return JEST_WORKER_LOGS_PAYLOAD_CODE
40
41
  }
41
42
  return null
@@ -1,5 +1,6 @@
1
1
  const request = require('../../exporters/common/request')
2
2
  const log = require('../../log')
3
+ const { getEnvironmentVariable } = require('../../config-helper')
3
4
  const {
4
5
  incrementCountMetric,
5
6
  distributionMetric,
@@ -46,7 +47,7 @@ function getSkippableSuites ({
46
47
  options.path = `${evpProxyPrefix}/api/v2/ci/tests/skippable`
47
48
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
48
49
  } else {
49
- const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
50
+ const apiKey = getEnvironmentVariable('DD_API_KEY')
50
51
  if (!apiKey) {
51
52
  return done(new Error('Skippable suites were not fetched because Datadog API key is not defined.'))
52
53
  }
@@ -1,5 +1,6 @@
1
1
  const Plugin = require('../../plugins/plugin')
2
2
  const log = require('../../log')
3
+ const { getEnvironmentVariable } = require('../../config-helper')
3
4
 
4
5
  function getWinstonLogSubmissionParameters (config) {
5
6
  const { site, service } = config
@@ -9,16 +10,16 @@ function getWinstonLogSubmissionParameters (config) {
9
10
  path: `/api/v2/logs?ddsource=winston&service=${service}`,
10
11
  ssl: true,
11
12
  headers: {
12
- 'DD-API-KEY': process.env.DD_API_KEY
13
+ 'DD-API-KEY': getEnvironmentVariable('DD_API_KEY')
13
14
  }
14
15
  }
15
16
 
16
- if (!process.env.DD_AGENTLESS_LOG_SUBMISSION_URL) {
17
+ if (!getEnvironmentVariable('DD_AGENTLESS_LOG_SUBMISSION_URL')) {
17
18
  return defaultParameters
18
19
  }
19
20
 
20
21
  try {
21
- const url = new URL(process.env.DD_AGENTLESS_LOG_SUBMISSION_URL)
22
+ const url = new URL(getEnvironmentVariable('DD_AGENTLESS_LOG_SUBMISSION_URL'))
22
23
  return {
23
24
  host: url.hostname,
24
25
  port: url.port,
@@ -1,6 +1,7 @@
1
1
  const request = require('../../exporters/common/request')
2
2
  const id = require('../../id')
3
3
  const log = require('../../log')
4
+ const { getEnvironmentVariable } = require('../../config-helper')
4
5
  const {
5
6
  incrementCountMetric,
6
7
  distributionMetric,
@@ -45,7 +46,7 @@ function getLibraryConfiguration ({
45
46
  options.path = `${evpProxyPrefix}/api/v2/libraries/tests/services/setting`
46
47
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
47
48
  } else {
48
- const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
49
+ const apiKey = getEnvironmentVariable('DD_API_KEY')
49
50
  if (!apiKey) {
50
51
  return done(new Error('Request to settings endpoint was not done because Datadog API key is not defined.'))
51
52
  }
@@ -123,11 +124,11 @@ function getLibraryConfiguration ({
123
124
 
124
125
  log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
125
126
 
126
- if (process.env.DD_CIVISIBILITY_DANGEROUSLY_FORCE_COVERAGE) {
127
+ if (getEnvironmentVariable('DD_CIVISIBILITY_DANGEROUSLY_FORCE_COVERAGE')) {
127
128
  settings.isCodeCoverageEnabled = true
128
129
  log.debug(() => 'Dangerously set code coverage to true')
129
130
  }
130
- if (process.env.DD_CIVISIBILITY_DANGEROUSLY_FORCE_TEST_SKIPPING) {
131
+ if (getEnvironmentVariable('DD_CIVISIBILITY_DANGEROUSLY_FORCE_TEST_SKIPPING')) {
131
132
  settings.isSuitesSkippingEnabled = true
132
133
  log.debug(() => 'Dangerously set test skipping to true')
133
134
  }
@@ -1,5 +1,6 @@
1
1
  const request = require('../../exporters/common/request')
2
2
  const id = require('../../id')
3
+ const { getEnvironmentVariable } = require('../../config-helper')
3
4
 
4
5
  function getTestManagementTests ({
5
6
  url,
@@ -28,7 +29,7 @@ function getTestManagementTests ({
28
29
  options.path = `${evpProxyPrefix}/api/v2/test/libraries/test-management/tests`
29
30
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
30
31
  } else {
31
- const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
32
+ const apiKey = getEnvironmentVariable('DD_API_KEY')
32
33
  if (!apiKey) {
33
34
  return done(new Error('Test management tests were not fetched because Datadog API key is not defined.'))
34
35
  }
@@ -0,0 +1,89 @@
1
+ 'use strict'
2
+
3
+ /* eslint-disable eslint-rules/eslint-process-env */
4
+
5
+ const { deprecate } = require('util')
6
+ const { supportedConfigurations, aliases, deprecations } = require('./supported-configurations.json')
7
+
8
+ const aliasToCanonical = {}
9
+ for (const canonical of Object.keys(aliases)) {
10
+ for (const alias of aliases[canonical]) {
11
+ if (aliasToCanonical[alias]) {
12
+ throw new Error(`The alias ${alias} is already used for ${aliasToCanonical[alias]}.`)
13
+ }
14
+ aliasToCanonical[alias] = canonical
15
+ }
16
+ }
17
+
18
+ const deprecationMethods = {}
19
+ for (const deprecation of Object.keys(deprecations)) {
20
+ deprecationMethods[deprecation] = deprecate(
21
+ () => {},
22
+ `The environment variable ${deprecation} is deprecated.` +
23
+ (aliasToCanonical[deprecation]
24
+ ? ` Please use ${aliasToCanonical[deprecation]} instead.`
25
+ : ` ${deprecations[deprecation]}`),
26
+ `DATADOG_${deprecation}`
27
+ )
28
+ }
29
+
30
+ module.exports = {
31
+ /**
32
+ * Returns the environment variables that are supported by the tracer
33
+ * (including all non-Datadog/OTEL specific environment variables)
34
+ *
35
+ * @returns {Partial<process.env>} The environment variables
36
+ */
37
+ getEnvironmentVariables () {
38
+ const configs = {}
39
+ for (const [key, value] of Object.entries(process.env)) {
40
+ if (key.startsWith('DD_') || key.startsWith('OTEL_') || aliasToCanonical[key]) {
41
+ if (supportedConfigurations[key]) {
42
+ configs[key] = value
43
+ } else if (aliasToCanonical[key] && configs[aliasToCanonical[key]] === undefined) {
44
+ // The alias should only be used if the actual configuration is not set
45
+ // In case that more than a single alias exist, use the one defined first in our own order
46
+ for (const alias of aliases[aliasToCanonical[key]]) {
47
+ if (process.env[alias] !== undefined) {
48
+ configs[aliasToCanonical[key]] = value
49
+ break
50
+ }
51
+ }
52
+ // TODO(BridgeAR) Implement logging. It would have to use a timeout to
53
+ // lazily log the message after all loading being done otherwise.
54
+ // debug(
55
+ // `Missing configuration ${env} in supported-configurations file. The environment variable is ignored.`
56
+ // )
57
+ }
58
+ deprecationMethods[key]?.()
59
+ } else {
60
+ configs[key] = value
61
+ }
62
+ }
63
+ return configs
64
+ },
65
+
66
+ /**
67
+ * Returns the environment variable, if it's supported or a non Datadog
68
+ * configuration. Otherwise, it throws an error.
69
+ *
70
+ * @param {string} name Environment variable name
71
+ * @returns {string|undefined}
72
+ * @throws {Error} if the configuration is not supported
73
+ */
74
+ getEnvironmentVariable (name) {
75
+ if ((name.startsWith('DD_') || name.startsWith('OTEL_') || aliasToCanonical[name]) &&
76
+ !supportedConfigurations[name]) {
77
+ throw new Error(`Missing ${name} env/configuration in "supported-configurations.json" file.`)
78
+ }
79
+ const config = process.env[name]
80
+ if (config === undefined && aliases[name]) {
81
+ for (const alias of aliases[name]) {
82
+ if (process.env[alias] !== undefined) {
83
+ return process.env[alias]
84
+ }
85
+ }
86
+ }
87
+ return config
88
+ }
89
+ }