dd-trace 5.96.0 → 5.98.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 (173) hide show
  1. package/index.d.ts +60 -2
  2. package/package.json +9 -7
  3. package/packages/datadog-esbuild/index.js +20 -9
  4. package/packages/datadog-instrumentations/src/child_process.js +7 -17
  5. package/packages/datadog-instrumentations/src/crypto.js +1 -2
  6. package/packages/datadog-instrumentations/src/cucumber.js +69 -4
  7. package/packages/datadog-instrumentations/src/cypress-config.js +318 -0
  8. package/packages/datadog-instrumentations/src/cypress.js +86 -4
  9. package/packages/datadog-instrumentations/src/dns.js +1 -2
  10. package/packages/datadog-instrumentations/src/express.js +4 -4
  11. package/packages/datadog-instrumentations/src/fs.js +27 -29
  12. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
  14. package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
  17. package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
  18. package/packages/datadog-instrumentations/src/http/client.js +2 -3
  19. package/packages/datadog-instrumentations/src/http/server.js +2 -5
  20. package/packages/datadog-instrumentations/src/http2/client.js +1 -3
  21. package/packages/datadog-instrumentations/src/http2/server.js +1 -3
  22. package/packages/datadog-instrumentations/src/jest.js +117 -16
  23. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  24. package/packages/datadog-instrumentations/src/mocha/utils.js +12 -1
  25. package/packages/datadog-instrumentations/src/net.js +2 -8
  26. package/packages/datadog-instrumentations/src/pino.js +1 -1
  27. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  28. package/packages/datadog-instrumentations/src/prisma.js +1 -2
  29. package/packages/datadog-instrumentations/src/redis.js +12 -6
  30. package/packages/datadog-instrumentations/src/selenium.js +4 -1
  31. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  32. package/packages/datadog-instrumentations/src/url.js +1 -3
  33. package/packages/datadog-instrumentations/src/vitest.js +5 -1
  34. package/packages/datadog-instrumentations/src/vm.js +1 -3
  35. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -4
  36. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
  37. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  38. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  39. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
  40. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
  41. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  42. package/packages/datadog-plugin-cucumber/src/index.js +13 -3
  43. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +166 -6
  44. package/packages/datadog-plugin-cypress/src/index.js +59 -2
  45. package/packages/datadog-plugin-fs/src/index.js +1 -1
  46. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
  47. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
  48. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  49. package/packages/datadog-plugin-http/src/client.js +1 -1
  50. package/packages/datadog-plugin-http/src/server.js +10 -2
  51. package/packages/datadog-plugin-http2/src/client.js +1 -1
  52. package/packages/datadog-plugin-http2/src/server.js +10 -2
  53. package/packages/datadog-plugin-jest/src/index.js +4 -2
  54. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
  55. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  56. package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
  57. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  58. package/packages/datadog-plugin-next/src/index.js +10 -16
  59. package/packages/datadog-plugin-openai/src/services.js +1 -0
  60. package/packages/datadog-plugin-pg/src/index.js +1 -1
  61. package/packages/datadog-plugin-tedious/src/index.js +1 -1
  62. package/packages/datadog-plugin-ws/src/close.js +1 -1
  63. package/packages/datadog-plugin-ws/src/receiver.js +1 -1
  64. package/packages/datadog-webpack/index.js +3 -3
  65. package/packages/dd-trace/index.js +12 -10
  66. package/packages/dd-trace/src/agent/url.js +2 -2
  67. package/packages/dd-trace/src/aiguard/sdk.js +26 -22
  68. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
  69. package/packages/dd-trace/src/appsec/blocking.js +64 -33
  70. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  71. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  73. package/packages/dd-trace/src/appsec/remote_config.js +1 -0
  74. package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
  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 +2 -2
  78. package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
  79. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
  80. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  81. package/packages/dd-trace/src/config/defaults.js +315 -146
  82. package/packages/dd-trace/src/config/generated-config-types.d.ts +9 -1
  83. package/packages/dd-trace/src/config/helper.js +59 -10
  84. package/packages/dd-trace/src/config/index.js +587 -1496
  85. package/packages/dd-trace/src/config/parsers.js +256 -0
  86. package/packages/dd-trace/src/config/remote_config.js +59 -2
  87. package/packages/dd-trace/src/config/supported-configurations.json +406 -432
  88. package/packages/dd-trace/src/constants.js +1 -0
  89. package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
  90. package/packages/dd-trace/src/crashtracking/index.js +1 -7
  91. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
  92. package/packages/dd-trace/src/debugger/index.js +1 -1
  93. package/packages/dd-trace/src/dogstatsd.js +12 -9
  94. package/packages/dd-trace/src/encode/0.4.js +8 -7
  95. package/packages/dd-trace/src/encode/span-stats.js +4 -1
  96. package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
  97. package/packages/dd-trace/src/exporters/common/request.js +9 -0
  98. package/packages/dd-trace/src/exporters/common/writer.js +12 -2
  99. package/packages/dd-trace/src/heap_snapshots.js +3 -0
  100. package/packages/dd-trace/src/index.js +5 -2
  101. package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
  102. package/packages/dd-trace/src/llmobs/index.js +4 -1
  103. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
  104. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
  105. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
  106. package/packages/dd-trace/src/llmobs/sdk.js +12 -8
  107. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  108. package/packages/dd-trace/src/llmobs/tagger.js +9 -6
  109. package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
  110. package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
  111. package/packages/dd-trace/src/log/index.js +20 -59
  112. package/packages/dd-trace/src/log/writer.js +7 -19
  113. package/packages/dd-trace/src/noop/proxy.js +8 -0
  114. package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
  115. package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
  116. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  117. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  118. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +17 -2
  119. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
  120. package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
  121. package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
  122. package/packages/dd-trace/src/opentelemetry/trace/index.js +75 -0
  123. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +66 -0
  124. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +332 -0
  125. package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
  126. package/packages/dd-trace/src/opentracing/tracer.js +9 -4
  127. package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
  128. package/packages/dd-trace/src/plugin_manager.js +8 -6
  129. package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
  130. package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
  131. package/packages/dd-trace/src/plugins/plugin.js +11 -13
  132. package/packages/dd-trace/src/plugins/storage.js +2 -2
  133. package/packages/dd-trace/src/plugins/tracing.js +22 -5
  134. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  135. package/packages/dd-trace/src/plugins/util/web.js +6 -88
  136. package/packages/dd-trace/src/process-tags/index.js +3 -0
  137. package/packages/dd-trace/src/profiler.js +27 -2
  138. package/packages/dd-trace/src/profiling/config.js +73 -241
  139. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
  140. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
  141. package/packages/dd-trace/src/profiling/profiler.js +78 -109
  142. package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
  143. package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
  144. package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
  145. package/packages/dd-trace/src/propagation-hash/index.js +2 -1
  146. package/packages/dd-trace/src/proxy.js +40 -6
  147. package/packages/dd-trace/src/remote_config/index.js +3 -0
  148. package/packages/dd-trace/src/require-package-json.js +8 -4
  149. package/packages/dd-trace/src/ritm.js +58 -26
  150. package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
  151. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +18 -11
  152. package/packages/dd-trace/src/sampler.js +1 -1
  153. package/packages/dd-trace/src/service-naming/index.js +1 -1
  154. package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
  155. package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
  156. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
  157. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
  158. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +17 -1
  159. package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
  160. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
  161. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +11 -1
  162. package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
  163. package/packages/dd-trace/src/span_stats.js +5 -1
  164. package/packages/dd-trace/src/standalone/index.js +3 -0
  165. package/packages/dd-trace/src/telemetry/index.js +2 -3
  166. package/packages/dd-trace/src/telemetry/send-data.js +5 -19
  167. package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
  168. package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
  169. package/packages/dd-trace/src/tracer.js +2 -2
  170. package/packages/dd-trace/src/util.js +0 -9
  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
@@ -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
  }
@@ -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
  }
@@ -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
  }
@@ -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
  }
@@ -21,12 +21,12 @@ for (const hook of Object.values(hooks)) {
21
21
 
22
22
  const modulesOfInterest = new Set()
23
23
 
24
- for (const instrumentation of Object.values(instrumentations)) {
24
+ for (const [name, instrumentation] of Object.entries(instrumentations)) {
25
25
  for (const entry of instrumentation) {
26
26
  if (entry.file) {
27
- modulesOfInterest.add(`${entry.name}/${entry.file}`) // e.g. "redis/my/file.js"
27
+ modulesOfInterest.add(`${name}/${entry.file}`) // e.g. "redis/my/file.js"
28
28
  } else {
29
- modulesOfInterest.add(entry.name) // e.g. "redis"
29
+ modulesOfInterest.add(name) // e.g. "redis"
30
30
  }
31
31
  }
32
32
  }
@@ -1,23 +1,16 @@
1
1
  'use strict'
2
2
 
3
3
  if (!global._ddtrace) {
4
- const TracerProxy = require('./src')
5
-
6
- Object.defineProperty(global, '_ddtrace', {
7
- value: new TracerProxy(),
8
- enumerable: false,
9
- configurable: true,
10
- writable: true,
11
- })
12
-
13
4
  const ddTraceSymbol = Symbol.for('dd-trace')
14
5
 
6
+ // Set up beforeExitHandlers before loading the tracer so that modules loaded
7
+ // during require('./src') can register handlers.
15
8
  Object.defineProperty(globalThis, ddTraceSymbol, {
16
9
  value: {
17
10
  beforeExitHandlers: new Set(),
18
11
  },
19
12
  enumerable: false,
20
- configurable: true, // Allow this to be overridden by loading the tracer
13
+ configurable: true,
21
14
  writable: false,
22
15
  })
23
16
 
@@ -29,6 +22,15 @@ if (!global._ddtrace) {
29
22
  }
30
23
  })
31
24
 
25
+ const TracerProxy = require('./src')
26
+
27
+ Object.defineProperty(global, '_ddtrace', {
28
+ value: new TracerProxy(),
29
+ enumerable: false,
30
+ configurable: true,
31
+ writable: true,
32
+ })
33
+
32
34
  global._ddtrace.default = global._ddtrace
33
35
  global._ddtrace.tracer = global._ddtrace
34
36
  }
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { URL, format } = require('url')
4
- const defaults = require('../config/defaults')
4
+ const { defaults } = require('../config/defaults')
5
5
 
6
6
  module.exports = { getAgentUrl }
7
7
 
@@ -12,7 +12,7 @@ module.exports = { getAgentUrl }
12
12
 
13
13
  /**
14
14
  * Gets the agent URL from config, constructing it from hostname/port if needed
15
- * @param {ReturnType<import('../config')>} config - Tracer configuration object
15
+ * @param {Partial<import('../config/config-base')>} config - Tracer configuration object
16
16
  * @returns {URL} The agent URL
17
17
  */
18
18
  function getAgentUrl (config) {
@@ -25,11 +25,12 @@ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
25
25
  const ALLOW = 'ALLOW'
26
26
 
27
27
  class AIGuardAbortError extends Error {
28
- constructor (reason, tags, sds) {
28
+ constructor (reason, tags, tagProbs, sds) {
29
29
  super(reason)
30
30
  this.name = 'AIGuardAbortError'
31
31
  this.reason = reason
32
32
  this.tags = tags
33
+ this.tagProbabilities = tagProbs
33
34
  this.sds = sds || []
34
35
  }
35
36
  }
@@ -57,6 +58,10 @@ class AIGuard extends NoopAIGuard {
57
58
  #maxContentSize
58
59
  #meta
59
60
 
61
+ /**
62
+ * @param {import('../tracer')} tracer - Tracer instance
63
+ * @param {import('../config/config-base')} config - Tracer configuration
64
+ */
60
65
  constructor (tracer, config) {
61
66
  super()
62
67
 
@@ -184,38 +189,37 @@ class AIGuard extends NoopAIGuard {
184
189
  `AI Guard service call failed, status ${response.status}`,
185
190
  { errors: response.body?.errors })
186
191
  }
187
- let action, reason, tags, sdsFindings, blockingEnabled
188
- try {
189
- const attr = response.body.data.attributes
190
- if (!attr.action) {
191
- throw new Error('Action missing from response')
192
- }
193
- action = attr.action
194
- reason = attr.reason
195
- tags = attr.tags
196
- sdsFindings = attr.sds_findings || []
197
- blockingEnabled = attr.is_blocking_enabled ?? false
198
- } catch (e) {
192
+ const attr = response.body?.data?.attributes
193
+ if (!attr?.action) {
199
194
  appsecMetrics.count(AI_GUARD_TELEMETRY_REQUESTS, { error: true }).inc(1)
200
- throw new AIGuardClientError(`AI Guard service returned unexpected response : ${response.body}`, { cause: e })
195
+ throw new AIGuardClientError(`AI Guard service returned unexpected response : ${response.body}`)
196
+ }
197
+ const action = attr.action
198
+ const reason = attr.reason
199
+ const tags = attr.tags ?? []
200
+ if (tags.length > 0) {
201
+ metaStruct.attack_categories = tags
201
202
  }
203
+ const sdsFindings = attr.sds_findings ?? []
204
+ if (sdsFindings.length > 0) {
205
+ metaStruct.sds = sdsFindings
206
+ }
207
+ const tagProbabilities = attr.tag_probs ?? {}
208
+ if (attr.tag_probs) {
209
+ metaStruct.tag_probs = tagProbabilities
210
+ }
211
+ const blockingEnabled = attr.is_blocking_enabled ?? false
202
212
  const shouldBlock = block && blockingEnabled && action !== ALLOW
203
213
  appsecMetrics.count(AI_GUARD_TELEMETRY_REQUESTS, { action, error: false, block: shouldBlock }).inc(1)
204
214
  span.setTag(AI_GUARD_ACTION_TAG_KEY, action)
205
215
  if (reason) {
206
216
  span.setTag(AI_GUARD_REASON_TAG_KEY, reason)
207
217
  }
208
- if (tags?.length > 0) {
209
- metaStruct.attack_categories = tags
210
- }
211
- if (sdsFindings?.length > 0) {
212
- metaStruct.sds = sdsFindings
213
- }
214
218
  if (shouldBlock) {
215
219
  span.setTag(AI_GUARD_BLOCKED_TAG_KEY, 'true')
216
- throw new AIGuardAbortError(reason, tags, sdsFindings)
220
+ throw new AIGuardAbortError(reason, tags, tagProbabilities, sdsFindings)
217
221
  }
218
- return { action, reason, tags, sds: sdsFindings }
222
+ return { action, reason, tags, tagProbabilities, sds: sdsFindings }
219
223
  })
220
224
  }
221
225
  }
@@ -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,
@@ -6,9 +6,27 @@ const { updateBlockFailureMetric } = require('./telemetry')
6
6
 
7
7
  const detectedSpecificEndpoints = {}
8
8
 
9
- let templateHtml = blockedTemplates.html
10
- let templateJson = blockedTemplates.json
11
- let templateGraphqlJson = blockedTemplates.graphqlJson
9
+ const templateKeyword = '[security_response_id]'
10
+
11
+ const templates = {
12
+ html: {
13
+ body: null,
14
+ idIndex: -1,
15
+ type: 'text/html; charset=utf-8',
16
+ },
17
+ json: {
18
+ body: null,
19
+ idIndex: -1,
20
+ type: 'application/json',
21
+ },
22
+ graphqlJson: {
23
+ body: null,
24
+ idIndex: -1,
25
+ type: 'application/json',
26
+ },
27
+ }
28
+
29
+ setTemplates()
12
30
 
13
31
  let defaultBlockingActionParameters
14
32
 
@@ -17,7 +35,7 @@ const responseBlockedSet = new WeakSet()
17
35
  const blockDelegations = new WeakMap()
18
36
 
19
37
  const specificBlockingTypes = {
20
- GRAPHQL: 'graphql',
38
+ GRAPHQL: 'graphqlJson',
21
39
  }
22
40
 
23
41
  function getSpecificKey (method, url) {
@@ -33,21 +51,14 @@ function getBlockWithRedirectData (actionParameters) {
33
51
  if (!statusCode || statusCode < 300 || statusCode >= 400) {
34
52
  statusCode = 303
35
53
  }
36
- const headers = {
37
- Location: actionParameters.location,
38
- }
39
54
 
40
- return { headers, statusCode }
41
- }
55
+ const headers = { Location: actionParameters.location }
42
56
 
43
- function getSpecificBlockingData (type) {
44
- switch (type) {
45
- case specificBlockingTypes.GRAPHQL:
46
- return {
47
- type: 'application/json',
48
- body: templateGraphqlJson,
49
- }
57
+ if (headers.Location) {
58
+ headers.Location = headers.Location.replace(templateKeyword, actionParameters.security_response_id ?? '')
50
59
  }
60
+
61
+ return { headers, statusCode }
51
62
  }
52
63
 
53
64
  function getBlockWithContentData (req, specificType, actionParameters) {
@@ -56,7 +67,7 @@ function getBlockWithContentData (req, specificType, actionParameters) {
56
67
 
57
68
  const specificBlockingType = specificType || detectedSpecificEndpoints[getSpecificKey(req.method, req.url)]
58
69
  if (specificBlockingType) {
59
- const specificBlockingContent = getSpecificBlockingData(specificBlockingType)
70
+ const specificBlockingContent = getTemplate(specificBlockingType, actionParameters)
60
71
  type = specificBlockingContent?.type
61
72
  body = specificBlockingContent?.body
62
73
  }
@@ -65,23 +76,17 @@ function getBlockWithContentData (req, specificType, actionParameters) {
65
76
  // parse the Accept header, ex: Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
66
77
  const accept = req.headers.accept?.split(',').map((str) => str.split(';', 1)[0].trim())
67
78
 
79
+ let templateName = 'json'
80
+
68
81
  if (!actionParameters || actionParameters.type === 'auto') {
69
82
  if (accept?.includes('text/html') && !accept.includes('application/json')) {
70
- type = 'text/html; charset=utf-8'
71
- body = templateHtml
72
- } else {
73
- type = 'application/json'
74
- body = templateJson
75
- }
76
- } else {
77
- if (actionParameters.type === 'html') {
78
- type = 'text/html; charset=utf-8'
79
- body = templateHtml
80
- } else {
81
- type = 'application/json'
82
- body = templateJson
83
+ templateName = 'html'
83
84
  }
85
+ } else if (actionParameters.type === 'html') {
86
+ templateName = 'html'
84
87
  }
88
+
89
+ ({ type, body } = getTemplate(templateName, actionParameters))
85
90
  }
86
91
 
87
92
  const statusCode = actionParameters?.status_code || 403
@@ -164,12 +169,38 @@ function getBlockingAction (actions) {
164
169
  return actions?.redirect_request || actions?.block_request
165
170
  }
166
171
 
172
+ /**
173
+ * @param {import('../config/config-base')} [config] - Tracer configuration
174
+ */
167
175
  function setTemplates (config) {
168
- templateHtml = config.appsec.blockedTemplateHtml || blockedTemplates.html
176
+ templates.html.body = config?.appsec?.blockedTemplateHtml
177
+ templates.json.body = config?.appsec?.blockedTemplateJson
178
+ templates.graphqlJson.body = config?.appsec?.blockedTemplateGraphql
179
+
180
+ for (const type of Object.keys(templates)) {
181
+ const template = templates[type]
182
+
183
+ // set default template if not set by config
184
+ if (!template.body) template.body = blockedTemplates[type]
185
+
186
+ template.idIndex = template.body.indexOf(templateKeyword)
187
+
188
+ if (template.idIndex !== -1) {
189
+ template.body = [
190
+ template.body.slice(0, template.idIndex),
191
+ template.body.slice(template.idIndex + templateKeyword.length),
192
+ ]
193
+ }
194
+ }
195
+ }
196
+
197
+ function getTemplate (type, actionParameters) {
198
+ const template = templates[type]
199
+ if (template.idIndex === -1) return template
169
200
 
170
- templateJson = config.appsec.blockedTemplateJson || blockedTemplates.json
201
+ const body = template.body[0] + (actionParameters?.security_response_id ?? '') + template.body[1]
171
202
 
172
- templateGraphqlJson = config.appsec.blockedTemplateGraphql || blockedTemplates.graphqlJson
203
+ return { body, type: template.type }
173
204
  }
174
205
 
175
206
  function isBlocked (res) {
@@ -168,7 +168,7 @@ class IastPlugin extends Plugin {
168
168
  loadChannel.subscribe(this.onInstrumentationLoadedListener)
169
169
 
170
170
  // check for already instrumented modules
171
- for (const name in instrumentations) {
171
+ for (const name of Object.keys(instrumentations)) {
172
172
  this._onInstrumentationLoaded(name)
173
173
  }
174
174
  }
@@ -3,7 +3,7 @@
3
3
 
4
4
  const log = require('../../../../log')
5
5
  const vulnerabilities = require('../../vulnerabilities')
6
- const defaults = require('../../../../config/defaults')
6
+ const { defaults } = require('../../../../config/defaults')
7
7
 
8
8
  const { contains, intersects, remove } = require('./range-utils')
9
9
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const crypto = require('crypto')
4
4
 
5
- const defaults = require('../../../config/defaults')
5
+ const { defaults } = require('../../../config/defaults')
6
6
 
7
7
  const STRINGIFY_RANGE_KEY = 'DD_' + crypto.randomBytes(20).toString('hex')
8
8
  const STRINGIFY_SENSITIVE_KEY = STRINGIFY_RANGE_KEY + 'SENSITIVE'
@@ -76,6 +76,7 @@ function enableOrDisableAppsec (action, rcConfig, config, appsec) {
76
76
  appsec.disable()
77
77
  }
78
78
 
79
+ // TODO: Use configWithOrigin /generateTelemetry instead of manually constructing the change.
79
80
  updateConfig([
80
81
  {
81
82
  name: 'appsec.enabled',
@@ -26,6 +26,10 @@ class EventTrackingV2 {
26
26
  }
27
27
 
28
28
  class AppsecSdk {
29
+ /**
30
+ * @param {import('../../tracer')} tracer - Tracer instance
31
+ * @param {import('../../config/config-base')} config - Tracer configuration
32
+ */
29
33
  constructor (tracer, config) {
30
34
  this._tracer = tracer
31
35
  if (config) {
@@ -19,7 +19,7 @@ function setUser (tracer, user) {
19
19
  return
20
20
  }
21
21
 
22
- const rootSpan = getRootSpan(tracer)
22
+ const rootSpan = getRootSpan()
23
23
  if (!rootSpan) {
24
24
  log.warn('[ASM] Root span not available in setUser')
25
25
  return
@@ -21,7 +21,7 @@ function trackUserLoginSuccessEvent (tracer, user, metadata) {
21
21
 
22
22
  incrementSdkEventMetric('login_success', 'v1')
23
23
 
24
- const rootSpan = getRootSpan(tracer)
24
+ const rootSpan = getRootSpan()
25
25
  if (!rootSpan) {
26
26
  log.warn('[ASM] Root span not available in trackUserLoginSuccessEvent')
27
27
  return
@@ -54,7 +54,7 @@ function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
54
54
  ...metadata,
55
55
  }
56
56
 
57
- trackEvent('users.login.failure', fields, 'trackUserLoginFailureEvent', getRootSpan(tracer))
57
+ trackEvent('users.login.failure', fields, 'trackUserLoginFailureEvent', getRootSpan())
58
58
 
59
59
  runWaf('users.login.failure', { login: userId })
60
60
 
@@ -67,7 +67,7 @@ function trackCustomEvent (tracer, eventName, metadata) {
67
67
  return
68
68
  }
69
69
 
70
- trackEvent(eventName, metadata, 'trackCustomEvent', getRootSpan(tracer))
70
+ trackEvent(eventName, metadata, 'trackCustomEvent', getRootSpan())
71
71
 
72
72
  incrementSdkEventMetric('custom', 'v1')
73
73
 
@@ -84,7 +84,7 @@ function trackUserLoginSuccessV2 (tracer, login, user, metadata) {
84
84
 
85
85
  incrementSdkEventMetric('login_success', 'v2')
86
86
 
87
- const rootSpan = getRootSpan(tracer)
87
+ const rootSpan = getRootSpan()
88
88
  if (!rootSpan) {
89
89
  log.warn('[ASM] Root span not available in eventTrackingV2.trackUserLoginSuccess')
90
90
  return
@@ -122,7 +122,7 @@ function trackUserLoginFailureV2 (tracer, login, exists, metadata) {
122
122
 
123
123
  incrementSdkEventMetric('login_failure', 'v2')
124
124
 
125
- const rootSpan = getRootSpan(tracer)
125
+ const rootSpan = getRootSpan()
126
126
  if (!rootSpan) {
127
127
  log.warn('[ASM] Root span not available in eventTrackingV2.trackUserLoginFailure')
128
128
  return
@@ -19,7 +19,7 @@ function checkUserAndSetUser (tracer, user) {
19
19
  return false
20
20
  }
21
21
 
22
- const rootSpan = getRootSpan(tracer)
22
+ const rootSpan = getRootSpan()
23
23
  if (rootSpan) {
24
24
  if (!rootSpan.context()._tags['usr.id']) {
25
25
  setUserTags(user, rootSpan)
@@ -45,7 +45,7 @@ function blockRequest (tracer, req, res) {
45
45
  return false
46
46
  }
47
47
 
48
- const rootSpan = getRootSpan(tracer)
48
+ const rootSpan = getRootSpan()
49
49
  if (!rootSpan) {
50
50
  log.warn('[ASM] Root span not available in blockRequest')
51
51
  return false
@@ -1,7 +1,9 @@
1
1
  'use strict'
2
2
 
3
- function getRootSpan (tracer) {
4
- let span = tracer.scope().active()
3
+ const { storage } = require('../../../../datadog-core')
4
+
5
+ function getRootSpan () {
6
+ let span = storage('legacy').getStore()?.span
5
7
  if (!span) return
6
8
 
7
9
  const context = span.context()
@@ -11,6 +11,9 @@ const probeIdToResolveBreakpointSet = new Map()
11
11
  const probeIdToResolveBreakpointRemove = new Map()
12
12
 
13
13
  class TestVisDynamicInstrumentation {
14
+ /**
15
+ * @param {import('../../config/config-base')} config - Tracer configuration
16
+ */
14
17
  constructor (config) {
15
18
  this._config = config
16
19
  this.worker = null
@@ -83,7 +86,6 @@ class TestVisDynamicInstrumentation {
83
86
  DD_TRACE_ENABLED: 'false',
84
87
  DD_TEST_FAILED_TEST_REPLAY_ENABLED: 'false',
85
88
  DD_CIVISIBILITY_MANUAL_API_ENABLED: 'false',
86
- DD_TRACING_ENABLED: 'false',
87
89
  DD_INSTRUMENTATION_TELEMETRY_ENABLED: 'false',
88
90
  },
89
91
  workerData: {
@@ -150,6 +152,9 @@ class TestVisDynamicInstrumentation {
150
152
 
151
153
  let dynamicInstrumentation
152
154
 
155
+ /**
156
+ * @param {import('../../config/config-base')} config - Tracer configuration
157
+ */
153
158
  module.exports = function createAndGetTestVisDynamicInstrumentation (config) {
154
159
  if (dynamicInstrumentation) {
155
160
  return dynamicInstrumentation
@@ -54,6 +54,10 @@ class TestApiManualPlugin extends CiPlugin {
54
54
  })
55
55
  }
56
56
 
57
+ /**
58
+ * @param {import('../../config/config-base')} config - Tracer configuration
59
+ * @param {boolean} shouldGetEnvironmentData - Whether to get environment data
60
+ */
57
61
  configure (config, shouldGetEnvironmentData) {
58
62
  this._config = config
59
63
  super.configure(config, shouldGetEnvironmentData)