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
@@ -8,6 +8,7 @@ const dc = require('dc-polyfill')
8
8
  const { fileURLToPath } = require('url')
9
9
  const { isTrue } = require('../../src/util')
10
10
 
11
+ /** @type {Set<string>} */
11
12
  const savedDependenciesToSend = new Set()
12
13
  const detectedDependencyKeys = new Set()
13
14
  const detectedDependencyVersions = new Set()
@@ -15,63 +16,66 @@ const detectedDependencyVersions = new Set()
15
16
  const FILE_URI_START = 'file://'
16
17
  const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
17
18
 
18
- let immediate, config, application, host, initialLoad
19
+ let config, application, host, initialLoad
19
20
  let isFirstModule = true
20
21
  let getRetryData
21
22
  let updateRetryData
22
23
 
23
- function createBatchPayload (payload) {
24
- const batchPayload = payload.map(item => {
25
- return {
26
- request_type: item.reqType,
27
- payload: item.payload
28
- }
29
- })
30
-
31
- return batchPayload
32
- }
33
24
  function waitAndSend (config, application, host) {
34
- if (!immediate) {
35
- immediate = setImmediate(() => {
36
- immediate = null
37
- if (savedDependenciesToSend.size > 0) {
38
- const dependencies = [...savedDependenciesToSend.values()]
39
- // if a dependency is from the initial load, *always* send the event
40
- // Otherwise, only send if dependencyCollection is enabled
41
- .filter(dep => {
42
- const initialLoadModule = isTrue(dep.split(' ')[2])
43
- const sendModule = initialLoadModule || (config.telemetry?.dependencyCollection)
44
-
45
- if (!sendModule) savedDependenciesToSend.delete(dep) // we'll never send it
46
- return sendModule
47
- })
48
- .splice(0, 2000) // v2 documentation specifies up to 2000 dependencies can be sent at once
49
- .map(pair => {
50
- savedDependenciesToSend.delete(pair)
51
- const [name, version] = pair.split(' ')
52
- return { name, version }
53
- })
54
- let currPayload
55
- const retryData = getRetryData()
56
- if (retryData) {
57
- currPayload = { reqType: 'app-dependencies-loaded', payload: { dependencies } }
58
- } else {
59
- if (!dependencies.length) return // no retry data and no dependencies, nothing to send
60
- currPayload = { dependencies }
25
+ setImmediate(() => {
26
+ if (savedDependenciesToSend.size === 0) {
27
+ return
28
+ }
29
+ const dependencies = []
30
+ let send = 0
31
+ for (const dependency of savedDependenciesToSend) {
32
+ const [name, version, initialLoadModule] = dependency.split(' ')
33
+ // If a dependency is from the initial load, *always* send the event
34
+ // Otherwise, only send if dependencyCollection is enabled
35
+ const sendModule = isTrue(initialLoadModule) || config.telemetry?.dependencyCollection
36
+
37
+ savedDependenciesToSend.delete(dependency)
38
+
39
+ if (sendModule) {
40
+ dependencies.push({ name, version })
41
+ send++
42
+ if (send === 2000) {
43
+ // v2 documentation specifies up to 2000 dependencies can be sent at once
44
+ break
61
45
  }
46
+ }
47
+ }
62
48
 
63
- const payload = retryData ? createBatchPayload([currPayload, retryData]) : currPayload
64
- const reqType = retryData ? 'message-batch' : 'app-dependencies-loaded'
49
+ /**
50
+ * @type { { dependencies: typeof dependencies } | {
51
+ * request_type: string,
52
+ * payload: typeof dependencies
53
+ * }[]}
54
+ */
55
+ let payload = { dependencies }
56
+ let reqType = 'app-dependencies-loaded'
57
+ const retryData = getRetryData()
58
+
59
+ if (retryData) {
60
+ payload = [{
61
+ request_type: 'app-dependencies-loaded',
62
+ payload
63
+ }, {
64
+ request_type: retryData.reqType,
65
+ payload: retryData.payload
66
+ }]
67
+ reqType = 'message-batch'
68
+ } else if (!dependencies.length) {
69
+ // No retry data and no dependencies, nothing to send
70
+ return
71
+ }
65
72
 
66
- sendData(config, application, host, reqType, payload, updateRetryData)
73
+ sendData(config, application, host, reqType, payload, updateRetryData)
67
74
 
68
- if (savedDependenciesToSend.size > 0) {
69
- waitAndSend(config, application, host)
70
- }
71
- }
72
- })
73
- immediate.unref()
74
- }
75
+ if (savedDependenciesToSend.size > 0) {
76
+ waitAndSend(config, application, host)
77
+ }
78
+ }).unref()
75
79
  }
76
80
 
77
81
  function loadAllTheLoadedModules () {
@@ -91,7 +95,7 @@ function onModuleLoad (data) {
91
95
 
92
96
  if (data) {
93
97
  let filename = data.filename
94
- if (filename && filename.startsWith(FILE_URI_START)) {
98
+ if (filename?.startsWith(FILE_URI_START)) {
95
99
  try {
96
100
  filename = fileURLToPath(filename)
97
101
  } catch {
@@ -99,10 +103,10 @@ function onModuleLoad (data) {
99
103
  }
100
104
  }
101
105
  const parseResult = filename && parse(filename)
102
- const request = data.request || (parseResult && parseResult.name)
103
- const dependencyKey = parseResult && parseResult.basedir ? parseResult.basedir : request
106
+ const request = data.request || parseResult?.name
107
+ const dependencyKey = parseResult?.basedir ?? request
104
108
 
105
- if (filename && request && isDependency(filename, request) && !detectedDependencyKeys.has(dependencyKey)) {
109
+ if (filename && request && isDependency(request) && !detectedDependencyKeys.has(dependencyKey)) {
106
110
  detectedDependencyKeys.add(dependencyKey)
107
111
 
108
112
  if (parseResult) {
@@ -135,20 +139,21 @@ function start (_config = {}, _application, _host, getRetryDataFunction, updateR
135
139
  updateRetryData = updateRetryDatafunction
136
140
  moduleLoadStartChannel.subscribe(onModuleLoad)
137
141
 
138
- // try and capture intially loaded modules in the first tick
142
+ // Try and capture initially loaded modules in the first tick
139
143
  // since, ideally, the tracer (and this module) should be loaded first,
140
144
  // this should capture any first-tick dependencies
141
145
  queueMicrotask(() => { initialLoad = false })
142
146
  }
143
147
 
144
- function isDependency (filename, request) {
145
- const isDependencyWithSlash = isDependencyWithSeparator(filename, request, '/')
148
+ function isDependency (request) {
149
+ const isDependencyWithSlash = isDependencyWithSeparator(request, '/')
146
150
  if (isDependencyWithSlash && process.platform === 'win32') {
147
- return isDependencyWithSeparator(filename, request, path.sep)
151
+ return isDependencyWithSeparator(request, path.sep)
148
152
  }
149
153
  return isDependencyWithSlash
150
154
  }
151
- function isDependencyWithSeparator (filename, request, sep) {
155
+
156
+ function isDependencyWithSeparator (request, sep) {
152
157
  return request.indexOf(`..${sep}`) !== 0 &&
153
158
  request.indexOf(`.${sep}`) !== 0 &&
154
159
  request.indexOf(sep) !== 0 &&
@@ -1,6 +1,7 @@
1
1
  const request = require('../exporters/common/request')
2
2
  const log = require('../log')
3
3
  const { isTrue } = require('../util')
4
+ const { getEnvironmentVariable } = require('../config-helper')
4
5
 
5
6
  let agentTelemetry = true
6
7
 
@@ -36,10 +37,9 @@ function getPayload (payload) {
36
37
  // 'logs' request type payload is meant to send library logs to Datadog’s backend.
37
38
  if (Array.isArray(payload)) {
38
39
  return payload
39
- } else {
40
- const { logger, tags, serviceMapping, ...trimmedPayload } = payload
41
- return trimmedPayload
42
40
  }
41
+ const { logger, tags, serviceMapping, ...trimmedPayload } = payload
42
+ return trimmedPayload
43
43
  }
44
44
 
45
45
  function sendData (config, application, host, reqType, payload = {}, cb = () => {}) {
@@ -51,7 +51,8 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
51
51
 
52
52
  let url = config.url
53
53
 
54
- const isCiVisibilityAgentlessMode = isCiVisibility && isTrue(process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED)
54
+ const isCiVisibilityAgentlessMode = isCiVisibility &&
55
+ isTrue(getEnvironmentVariable('DD_CIVISIBILITY_AGENTLESS_ENABLED'))
55
56
 
56
57
  if (isCiVisibilityAgentlessMode) {
57
58
  try {
@@ -85,14 +86,14 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
85
86
  })
86
87
 
87
88
  request(data, options, (error) => {
88
- if (error && process.env.DD_API_KEY && config.site) {
89
+ if (error && getEnvironmentVariable('DD_API_KEY') && config.site) {
89
90
  if (agentTelemetry) {
90
91
  log.warn('Agent telemetry failed, started agentless telemetry')
91
92
  agentTelemetry = false
92
93
  }
93
94
  // figure out which data center to send to
94
95
  const backendUrl = getAgentlessTelemetryEndpoint(config.site)
95
- const backendHeader = { ...options.headers, 'DD-API-KEY': process.env.DD_API_KEY }
96
+ const backendHeader = { ...options.headers, 'DD-API-KEY': getEnvironmentVariable('DD_API_KEY') }
96
97
  const backendOptions = {
97
98
  ...options,
98
99
  url: backendUrl,
@@ -22,12 +22,14 @@ let heartbeatTimeout
22
22
  let heartbeatInterval
23
23
  let extendedInterval
24
24
  let integrations
25
- let configWithOrigin = []
25
+ const configWithOrigin = new Map()
26
26
  let retryData = null
27
27
  const extendedHeartbeatPayload = {}
28
28
 
29
29
  const sentIntegrations = new Set()
30
30
 
31
+ let seqId = 0
32
+
31
33
  function getRetryData () {
32
34
  return retryData
33
35
  }
@@ -113,7 +115,7 @@ function getInstallSignature (config) {
113
115
  function appStarted (config) {
114
116
  const app = {
115
117
  products: getProducts(config),
116
- configuration: configWithOrigin
118
+ configuration: [...configWithOrigin.values()]
117
119
  }
118
120
  const installSignature = getInstallSignature(config)
119
121
  if (installSignature) {
@@ -282,7 +284,7 @@ function stop () {
282
284
  }
283
285
 
284
286
  function updateIntegrations () {
285
- if (!config || !config.telemetry.enabled) {
287
+ if (!config?.telemetry.enabled) {
286
288
  return
287
289
  }
288
290
  const integrations = getIntegrations()
@@ -322,6 +324,8 @@ const nameMapping = {
322
324
  traceId128BitLoggingEnabled: 'DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED'
323
325
  }
324
326
 
327
+ const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])
328
+
325
329
  function updateConfig (changes, config) {
326
330
  if (!config.telemetry.enabled) return
327
331
  if (changes.length === 0) return
@@ -331,17 +335,12 @@ function updateConfig (changes, config) {
331
335
  const application = createAppObject(config)
332
336
  const host = createHostObject()
333
337
 
334
- const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])
335
-
336
- const configuration = []
337
- const names = [] // list of config names whose values have been changed
338
+ const changed = configWithOrigin.size > 0
338
339
 
339
340
  for (const change of changes) {
340
341
  const name = nameMapping[change.name] || change.name
341
-
342
- names.push(name)
343
342
  const { origin, value } = change
344
- const entry = { name, value, origin }
343
+ const entry = { name, value, origin, seq_id: seqId++ }
345
344
 
346
345
  if (namesNeedFormatting.has(entry.name)) {
347
346
  entry.value = formatMapForTelemetry(entry.value)
@@ -354,21 +353,17 @@ function updateConfig (changes, config) {
354
353
  } else if (Array.isArray(entry.value)) {
355
354
  entry.value = value.join(',')
356
355
  }
357
- configuration.push(entry)
358
- }
359
356
 
360
- function isNotModified (entry) {
361
- return !names.includes(entry.name)
357
+ // Use composite key to support multiple origins for same config name
358
+ configWithOrigin.set(`${name}|${origin}`, entry)
362
359
  }
363
360
 
364
- if (configWithOrigin.length) {
361
+ if (changed) {
365
362
  // update configWithOrigin to contain up-to-date full list of config values for app-extended-heartbeat
366
- configWithOrigin = configWithOrigin.filter(isNotModified)
367
- configWithOrigin = [...configWithOrigin, ...configuration]
368
- const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
363
+ const { reqType, payload } = createPayload('app-client-configuration-change', {
364
+ configuration: [...configWithOrigin.values()]
365
+ })
369
366
  sendData(config, application, host, reqType, payload, updateRetryData)
370
- } else {
371
- configWithOrigin = configuration
372
367
  }
373
368
  }
374
369
 
@@ -376,12 +371,7 @@ function profilingEnabledToBoolean (profilingEnabled) {
376
371
  if (typeof profilingEnabled === 'boolean') {
377
372
  return profilingEnabled
378
373
  }
379
- if (['auto', 'true'].includes(profilingEnabled)) {
380
- return true
381
- }
382
- if (profilingEnabled === 'false') {
383
- return false
384
- }
374
+ return profilingEnabled === 'true' || profilingEnabled === 'auto'
385
375
  }
386
376
 
387
377
  module.exports = {
@@ -46,9 +46,7 @@ class DatadogTracer extends Tracer {
46
46
  }
47
47
 
48
48
  trace (name, options, fn) {
49
- options = Object.assign({
50
- childOf: this.scope().active()
51
- }, options)
49
+ options = { childOf: this.scope().active(), ...options }
52
50
 
53
51
  const span = this.startSpan(name, options)
54
52
 
@@ -76,9 +74,8 @@ class DatadogTracer extends Tracer {
76
74
  throw err
77
75
  }
78
76
  )
79
- } else {
80
- span.finish()
81
77
  }
78
+ span.finish()
82
79
 
83
80
  return result
84
81
  } catch (e) {
@@ -110,9 +107,8 @@ class DatadogTracer extends Tracer {
110
107
 
111
108
  return fn.apply(this, arguments)
112
109
  })
113
- } else {
114
- return tracer.trace(name, optionsObj, () => fn.apply(this, arguments))
115
110
  }
111
+ return tracer.trace(name, optionsObj, () => fn.apply(this, arguments))
116
112
  }
117
113
  }
118
114
 
@@ -69,10 +69,6 @@ function calculateDDBasePath (dirname) {
69
69
  return dirSteps.slice(0, packagesIndex + 1).join(path.sep) + path.sep
70
70
  }
71
71
 
72
- function hasOwn (object, prop) {
73
- return Object.prototype.hasOwnProperty.call(object, prop)
74
- }
75
-
76
72
  function normalizeProfilingEnabledValue (configValue) {
77
73
  return isTrue(configValue)
78
74
  ? 'true'
@@ -87,6 +83,5 @@ module.exports = {
87
83
  isError,
88
84
  globMatch,
89
85
  ddBasePath: calculateDDBasePath(__dirname),
90
- hasOwn,
91
86
  normalizeProfilingEnabledValue
92
87
  }
@@ -1,11 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = function get (object, path) {
4
- const pathArr = path.split('.')
5
- let val = object
6
- for (const p of pathArr) {
7
- if (val === undefined) return val
8
- val = val[p]
9
- }
10
- return val
11
- }
@@ -1,14 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = function has (object, path) {
4
- const pathArr = path.split('.')
5
- let property = object
6
- for (const n of pathArr) {
7
- if (property.hasOwnProperty(n)) {
8
- property = property[n]
9
- } else {
10
- return false
11
- }
12
- }
13
- return true
14
- }
@@ -1,120 +0,0 @@
1
- 'use strict'
2
-
3
- const InjectionAnalyzer = require('./injection-analyzer')
4
- const { HEADER_INJECTION } = require('../vulnerabilities')
5
- const { getNodeModulesPaths } = require('../path-line')
6
- const { HEADER_NAME_VALUE_SEPARATOR } = require('../vulnerabilities-formatter/constants')
7
- const { getRanges } = require('../taint-tracking/operations')
8
- const {
9
- HTTP_REQUEST_COOKIE_VALUE,
10
- HTTP_REQUEST_HEADER_VALUE
11
- } = require('../taint-tracking/source-types')
12
-
13
- const EXCLUDED_PATHS = getNodeModulesPaths('express')
14
- const EXCLUDED_HEADER_NAMES = new Set([
15
- 'location',
16
- 'sec-websocket-location',
17
- 'sec-websocket-accept',
18
- 'upgrade',
19
- 'connection'
20
- ])
21
-
22
- class HeaderInjectionAnalyzer extends InjectionAnalyzer {
23
- constructor () {
24
- super(HEADER_INJECTION)
25
- }
26
-
27
- onConfigure () {
28
- this.addSub('datadog:http:server:response:set-header:finish', ({ name, value }) => {
29
- if (Array.isArray(value)) {
30
- for (const headerValue of value) {
31
- this.analyze({ name, value: headerValue })
32
- }
33
- } else {
34
- this.analyze({ name, value })
35
- }
36
- })
37
- }
38
-
39
- _isVulnerable ({ name, value }, iastContext) {
40
- const lowerCasedHeaderName = name?.trim().toLowerCase()
41
-
42
- if (this.isExcludedHeaderName(lowerCasedHeaderName) || typeof value !== 'string') return
43
-
44
- const ranges = getRanges(iastContext, value)
45
- return ranges?.length > 0 && !this.shouldIgnoreHeader(lowerCasedHeaderName, ranges)
46
- }
47
-
48
- _getEvidence (headerInfo, iastContext) {
49
- const prefix = headerInfo.name + HEADER_NAME_VALUE_SEPARATOR
50
- const prefixLength = prefix.length
51
-
52
- const evidence = super._getEvidence(headerInfo.value, iastContext)
53
- evidence.value = prefix + evidence.value
54
- evidence.ranges = evidence.ranges.map(range => {
55
- return {
56
- ...range,
57
- start: range.start + prefixLength,
58
- end: range.end + prefixLength
59
- }
60
- })
61
-
62
- return evidence
63
- }
64
-
65
- isExcludedHeaderName (name) {
66
- return EXCLUDED_HEADER_NAMES.has(name)
67
- }
68
-
69
- isAllRangesFromHeader (ranges, headerName) {
70
- return ranges
71
- .every(range =>
72
- range.iinfo.type === HTTP_REQUEST_HEADER_VALUE && range.iinfo.parameterName?.toLowerCase() === headerName
73
- )
74
- }
75
-
76
- isAllRangesFromSource (ranges, source) {
77
- return ranges
78
- .every(range => range.iinfo.type === source)
79
- }
80
-
81
- /**
82
- * Exclude access-control-allow-*: when the header starts with access-control-allow- and the
83
- * source of the tainted range is a request header
84
- */
85
- isAccessControlAllowExclusion (name, ranges) {
86
- if (name?.startsWith('access-control-allow-')) {
87
- return this.isAllRangesFromSource(ranges, HTTP_REQUEST_HEADER_VALUE)
88
- }
89
-
90
- return false
91
- }
92
-
93
- /** Exclude when the header is reflected from the request */
94
- isSameHeaderExclusion (name, ranges) {
95
- return ranges.length === 1 && name === ranges[0].iinfo.parameterName?.toLowerCase()
96
- }
97
-
98
- shouldIgnoreHeader (headerName, ranges) {
99
- switch (headerName) {
100
- case 'set-cookie':
101
- /** Exclude set-cookie header if the source of all the tainted ranges are cookies */
102
- return this.isAllRangesFromSource(ranges, HTTP_REQUEST_COOKIE_VALUE)
103
- case 'pragma':
104
- /** Ignore pragma headers when the source is the cache control header. */
105
- return this.isAllRangesFromHeader(ranges, 'cache-control')
106
- case 'transfer-encoding':
107
- case 'content-encoding':
108
- /** Ignore transfer and content encoding headers when the source is the accept encoding header. */
109
- return this.isAllRangesFromHeader(ranges, 'accept-encoding')
110
- }
111
-
112
- return this.isAccessControlAllowExclusion(headerName, ranges) || this.isSameHeaderExclusion(headerName, ranges)
113
- }
114
-
115
- _getExcludedPaths () {
116
- return EXCLUDED_PATHS
117
- }
118
- }
119
-
120
- module.exports = new HeaderInjectionAnalyzer()
@@ -1,20 +0,0 @@
1
- 'use strict'
2
-
3
- const { HEADER_NAME_VALUE_SEPARATOR } = require('../../constants')
4
-
5
- module.exports = function extractSensitiveRanges (evidence, namePattern, valuePattern) {
6
- const evidenceValue = evidence.value
7
- const sections = evidenceValue.split(HEADER_NAME_VALUE_SEPARATOR)
8
- const headerName = sections[0]
9
- const headerValue = sections.slice(1).join(HEADER_NAME_VALUE_SEPARATOR)
10
- namePattern.lastIndex = 0
11
- valuePattern.lastIndex = 0
12
- if (namePattern.test(headerName) || valuePattern.test(headerValue)) {
13
- return [{
14
- start: headerName.length + HEADER_NAME_VALUE_SEPARATOR.length,
15
- end: evidenceValue.length
16
- }]
17
- }
18
-
19
- return []
20
- }