dd-trace 5.35.0 → 5.37.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 (125) hide show
  1. package/LICENSE-3rdparty.csv +2 -1
  2. package/index.d.ts +8 -7
  3. package/loader-hook.mjs +0 -4
  4. package/package.json +15 -14
  5. package/packages/datadog-core/index.js +1 -1
  6. package/packages/datadog-core/src/storage.js +76 -31
  7. package/packages/datadog-instrumentations/src/cucumber.js +54 -1
  8. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  9. package/packages/datadog-instrumentations/src/helpers/register.js +2 -2
  10. package/packages/datadog-instrumentations/src/jest.js +105 -11
  11. package/packages/datadog-instrumentations/src/mocha/main.js +46 -4
  12. package/packages/datadog-instrumentations/src/mocha/utils.js +35 -2
  13. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -0
  14. package/packages/datadog-instrumentations/src/mysql2.js +3 -3
  15. package/packages/datadog-instrumentations/src/openai.js +8 -0
  16. package/packages/datadog-instrumentations/src/playwright.js +70 -22
  17. package/packages/datadog-instrumentations/src/vitest.js +60 -6
  18. package/packages/datadog-plugin-aerospike/src/index.js +1 -1
  19. package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
  20. package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
  21. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
  22. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
  23. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
  24. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
  25. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  26. package/packages/datadog-plugin-couchbase/src/index.js +2 -2
  27. package/packages/datadog-plugin-cucumber/src/index.js +31 -14
  28. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +72 -7
  29. package/packages/datadog-plugin-cypress/src/support.js +36 -29
  30. package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
  31. package/packages/datadog-plugin-graphql/src/utils.js +8 -1
  32. package/packages/datadog-plugin-grpc/src/client.js +1 -1
  33. package/packages/datadog-plugin-grpc/src/server.js +1 -1
  34. package/packages/datadog-plugin-hapi/src/index.js +1 -1
  35. package/packages/datadog-plugin-http/src/client.js +1 -1
  36. package/packages/datadog-plugin-http/src/server.js +1 -1
  37. package/packages/datadog-plugin-http2/src/client.js +3 -3
  38. package/packages/datadog-plugin-http2/src/server.js +1 -1
  39. package/packages/datadog-plugin-jest/src/index.js +17 -12
  40. package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
  41. package/packages/datadog-plugin-mariadb/src/index.js +3 -3
  42. package/packages/datadog-plugin-mocha/src/index.js +35 -16
  43. package/packages/datadog-plugin-mongodb-core/src/index.js +28 -2
  44. package/packages/datadog-plugin-next/src/index.js +4 -4
  45. package/packages/datadog-plugin-openai/src/tracing.js +2 -3
  46. package/packages/datadog-plugin-playwright/src/index.js +35 -9
  47. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  48. package/packages/datadog-plugin-router/src/index.js +2 -2
  49. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  50. package/packages/datadog-plugin-vitest/src/index.js +36 -12
  51. package/packages/dd-trace/src/appsec/graphql.js +6 -6
  52. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +3 -7
  53. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +15 -1
  54. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +17 -30
  55. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
  56. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -11
  57. package/packages/dd-trace/src/appsec/iast/analyzers/stored-injection-analyzer.js +11 -0
  58. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +2 -6
  59. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +24 -4
  60. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
  61. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
  62. package/packages/dd-trace/src/appsec/iast/index.js +4 -2
  63. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +187 -0
  64. package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +96 -0
  65. package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
  66. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -2
  67. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
  68. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
  69. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
  71. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
  72. package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +1 -1
  73. package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks.js +28 -0
  74. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  75. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +5 -0
  76. package/packages/dd-trace/src/appsec/iast/utils.js +24 -0
  77. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +8 -13
  78. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -0
  79. package/packages/dd-trace/src/appsec/index.js +4 -4
  80. package/packages/dd-trace/src/appsec/rasp/command_injection.js +5 -5
  81. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
  82. package/packages/dd-trace/src/appsec/rasp/lfi.js +3 -3
  83. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +4 -4
  84. package/packages/dd-trace/src/appsec/rasp/ssrf.js +3 -3
  85. package/packages/dd-trace/src/appsec/reporter.js +3 -3
  86. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  87. package/packages/dd-trace/src/appsec/waf/index.js +1 -1
  88. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
  89. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +31 -56
  90. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +20 -2
  91. package/packages/dd-trace/src/ci-visibility/quarantined-tests/get-quarantined-tests.js +62 -0
  92. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -2
  93. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
  94. package/packages/dd-trace/src/config.js +18 -3
  95. package/packages/dd-trace/src/data_streams_context.js +2 -2
  96. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
  97. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +50 -0
  98. package/packages/dd-trace/src/debugger/devtools_client/state.js +38 -10
  99. package/packages/dd-trace/src/exporters/common/agents.js +1 -1
  100. package/packages/dd-trace/src/exporters/common/request.js +3 -3
  101. package/packages/dd-trace/src/iitm.js +2 -2
  102. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
  103. package/packages/dd-trace/src/llmobs/tagger.js +12 -2
  104. package/packages/dd-trace/src/log/writer.js +3 -3
  105. package/packages/dd-trace/src/noop/span.js +1 -1
  106. package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
  107. package/packages/dd-trace/src/opentracing/span.js +3 -3
  108. package/packages/dd-trace/src/plugin_manager.js +3 -1
  109. package/packages/dd-trace/src/plugins/apollo.js +1 -1
  110. package/packages/dd-trace/src/plugins/ci_plugin.js +51 -4
  111. package/packages/dd-trace/src/plugins/database.js +14 -4
  112. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  113. package/packages/dd-trace/src/plugins/plugin.js +8 -8
  114. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  115. package/packages/dd-trace/src/plugins/util/git.js +3 -3
  116. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -3
  117. package/packages/dd-trace/src/plugins/util/test.js +10 -4
  118. package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
  119. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  120. package/packages/dd-trace/src/proxy.js +5 -1
  121. package/packages/dd-trace/src/ritm.js +2 -1
  122. package/packages/dd-trace/src/scope.js +5 -5
  123. package/packages/dd-trace/src/spanleak.js +0 -1
  124. package/packages/dd-trace/src/tracer.js +0 -14
  125. package/packages/memwatch/package.json +0 -9
@@ -11,12 +11,15 @@ const {
11
11
  TEST_SOURCE_START,
12
12
  TEST_CODE_OWNERS,
13
13
  TEST_SOURCE_FILE,
14
- TEST_CONFIGURATION_BROWSER_NAME,
14
+ TEST_PARAMETERS,
15
15
  TEST_IS_NEW,
16
16
  TEST_IS_RETRY,
17
17
  TEST_EARLY_FLAKE_ENABLED,
18
18
  TELEMETRY_TEST_SESSION,
19
- TEST_RETRY_REASON
19
+ TEST_RETRY_REASON,
20
+ TEST_MANAGEMENT_IS_QUARANTINED,
21
+ TEST_MANAGEMENT_ENABLED,
22
+ TEST_BROWSER_NAME
20
23
  } = require('../../dd-trace/src/plugins/util/test')
21
24
  const { RESOURCE_NAME } = require('../../../ext/tags')
22
25
  const { COMPONENT } = require('../../dd-trace/src/constants')
@@ -38,7 +41,12 @@ class PlaywrightPlugin extends CiPlugin {
38
41
  this.numFailedTests = 0
39
42
  this.numFailedSuites = 0
40
43
 
41
- this.addSub('ci:playwright:session:finish', ({ status, isEarlyFlakeDetectionEnabled, onDone }) => {
44
+ this.addSub('ci:playwright:session:finish', ({
45
+ status,
46
+ isEarlyFlakeDetectionEnabled,
47
+ isQuarantinedTestsEnabled,
48
+ onDone
49
+ }) => {
42
50
  this.testModuleSpan.setTag(TEST_STATUS, status)
43
51
  this.testSessionSpan.setTag(TEST_STATUS, status)
44
52
 
@@ -56,6 +64,10 @@ class PlaywrightPlugin extends CiPlugin {
56
64
  this.testSessionSpan.setTag('error', error)
57
65
  }
58
66
 
67
+ if (isQuarantinedTestsEnabled) {
68
+ this.testSessionSpan.setTag(TEST_MANAGEMENT_ENABLED, 'true')
69
+ }
70
+
59
71
  this.testModuleSpan.finish()
60
72
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
61
73
  this.testSessionSpan.finish()
@@ -68,7 +80,7 @@ class PlaywrightPlugin extends CiPlugin {
68
80
  })
69
81
 
70
82
  this.addSub('ci:playwright:test-suite:start', (testSuiteAbsolutePath) => {
71
- const store = storage.getStore()
83
+ const store = storage('legacy').getStore()
72
84
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.rootDir)
73
85
  const testSourceFile = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
74
86
 
@@ -102,7 +114,7 @@ class PlaywrightPlugin extends CiPlugin {
102
114
  })
103
115
 
104
116
  this.addSub('ci:playwright:test-suite:finish', ({ status, error }) => {
105
- const store = storage.getStore()
117
+ const store = storage('legacy').getStore()
106
118
  const span = store && store.span
107
119
  if (!span) return
108
120
  if (error) {
@@ -121,15 +133,24 @@ class PlaywrightPlugin extends CiPlugin {
121
133
  })
122
134
 
123
135
  this.addSub('ci:playwright:test:start', ({ testName, testSuiteAbsolutePath, testSourceLine, browserName }) => {
124
- const store = storage.getStore()
136
+ const store = storage('legacy').getStore()
125
137
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.rootDir)
126
138
  const testSourceFile = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
127
139
  const span = this.startTestSpan(testName, testSuite, testSourceFile, testSourceLine, browserName)
128
140
 
129
141
  this.enter(span, store)
130
142
  })
131
- this.addSub('ci:playwright:test:finish', ({ testStatus, steps, error, extraTags, isNew, isEfdRetry, isRetry }) => {
132
- const store = storage.getStore()
143
+ this.addSub('ci:playwright:test:finish', ({
144
+ testStatus,
145
+ steps,
146
+ error,
147
+ extraTags,
148
+ isNew,
149
+ isEfdRetry,
150
+ isRetry,
151
+ isQuarantined
152
+ }) => {
153
+ const store = storage('legacy').getStore()
133
154
  const span = store && store.span
134
155
  if (!span) return
135
156
 
@@ -151,6 +172,9 @@ class PlaywrightPlugin extends CiPlugin {
151
172
  if (isRetry) {
152
173
  span.setTag(TEST_IS_RETRY, 'true')
153
174
  }
175
+ if (isQuarantined) {
176
+ span.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
177
+ }
154
178
 
155
179
  steps.forEach(step => {
156
180
  const stepStartTime = step.startTime.getTime()
@@ -202,7 +226,9 @@ class PlaywrightPlugin extends CiPlugin {
202
226
  extraTags[TEST_SOURCE_FILE] = testSourceFile || testSuite
203
227
  }
204
228
  if (browserName) {
205
- extraTags[TEST_CONFIGURATION_BROWSER_NAME] = browserName
229
+ // Added as parameter too because it should affect the test fingerprint
230
+ extraTags[TEST_PARAMETERS] = JSON.stringify({ arguments: { browser: browserName }, metadata: {} })
231
+ extraTags[TEST_BROWSER_NAME] = browserName
206
232
  }
207
233
 
208
234
  return super.startTestSpan(testName, testSuite, testSuiteSpan, extraTags)
@@ -11,7 +11,7 @@ class RheaConsumerPlugin extends ConsumerPlugin {
11
11
  super(...args)
12
12
 
13
13
  this.addTraceSub('dispatch', ({ state }) => {
14
- const span = storage.getStore().span
14
+ const span = storage('legacy').getStore().span
15
15
  span.setTag('amqp.delivery.state', state)
16
16
  })
17
17
  }
@@ -29,7 +29,7 @@ class RouterPlugin extends WebPlugin {
29
29
  context.middleware.push(span)
30
30
  }
31
31
 
32
- const store = storage.getStore()
32
+ const store = storage('legacy').getStore()
33
33
  this._storeStack.push(store)
34
34
  this.enter(span, store)
35
35
 
@@ -94,7 +94,7 @@ class RouterPlugin extends WebPlugin {
94
94
  }
95
95
 
96
96
  _getStoreSpan () {
97
- const store = storage.getStore()
97
+ const store = storage('legacy').getStore()
98
98
 
99
99
  return store && store.span
100
100
  }
@@ -39,7 +39,7 @@ class SeleniumPlugin extends CiPlugin {
39
39
  browserVersion,
40
40
  isRumActive
41
41
  }) => {
42
- const store = storage.getStore()
42
+ const store = storage('legacy').getStore()
43
43
  const span = store?.span
44
44
  if (!span) {
45
45
  return
@@ -18,7 +18,9 @@ const {
18
18
  TEST_IS_NEW,
19
19
  TEST_EARLY_FLAKE_ENABLED,
20
20
  TEST_EARLY_FLAKE_ABORT_REASON,
21
- TEST_RETRY_REASON
21
+ TEST_RETRY_REASON,
22
+ TEST_MANAGEMENT_ENABLED,
23
+ TEST_MANAGEMENT_IS_QUARANTINED
22
24
  } = require('../../dd-trace/src/plugins/util/test')
23
25
  const { COMPONENT } = require('../../dd-trace/src/constants')
24
26
  const {
@@ -48,6 +50,20 @@ class VitestPlugin extends CiPlugin {
48
50
  onDone(!testsForThisTestSuite.includes(testName))
49
51
  })
50
52
 
53
+ this.addSub('ci:vitest:test:is-quarantined', ({ quarantinedTests, testSuiteAbsolutePath, testName, onDone }) => {
54
+ const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
55
+ const isQuarantined = quarantinedTests
56
+ ?.vitest
57
+ ?.suites
58
+ ?.[testSuite]
59
+ ?.tests
60
+ ?.[testName]
61
+ ?.properties
62
+ ?.quarantined
63
+
64
+ onDone(isQuarantined ?? false)
65
+ })
66
+
51
67
  this.addSub('ci:vitest:is-early-flake-detection-faulty', ({
52
68
  knownTests,
53
69
  testFilepaths,
@@ -66,11 +82,12 @@ class VitestPlugin extends CiPlugin {
66
82
  testSuiteAbsolutePath,
67
83
  isRetry,
68
84
  isNew,
85
+ isQuarantined,
69
86
  mightHitProbe,
70
87
  isRetryReasonEfd
71
88
  }) => {
72
89
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
73
- const store = storage.getStore()
90
+ const store = storage('legacy').getStore()
74
91
 
75
92
  const extraTags = {
76
93
  [TEST_SOURCE_FILE]: testSuite
@@ -84,6 +101,9 @@ class VitestPlugin extends CiPlugin {
84
101
  if (isRetryReasonEfd) {
85
102
  extraTags[TEST_RETRY_REASON] = 'efd'
86
103
  }
104
+ if (isQuarantined) {
105
+ extraTags[TEST_MANAGEMENT_IS_QUARANTINED] = 'true'
106
+ }
87
107
 
88
108
  const span = this.startTestSpan(
89
109
  testName,
@@ -102,7 +122,7 @@ class VitestPlugin extends CiPlugin {
102
122
  })
103
123
 
104
124
  this.addSub('ci:vitest:test:finish-time', ({ status, task }) => {
105
- const store = storage.getStore()
125
+ const store = storage('legacy').getStore()
106
126
  const span = store?.span
107
127
 
108
128
  // we store the finish time to finish at a later hook
@@ -114,7 +134,7 @@ class VitestPlugin extends CiPlugin {
114
134
  })
115
135
 
116
136
  this.addSub('ci:vitest:test:pass', ({ task }) => {
117
- const store = storage.getStore()
137
+ const store = storage('legacy').getStore()
118
138
  const span = store?.span
119
139
 
120
140
  if (span) {
@@ -128,15 +148,15 @@ class VitestPlugin extends CiPlugin {
128
148
  })
129
149
 
130
150
  this.addSub('ci:vitest:test:error', ({ duration, error, shouldSetProbe, promises }) => {
131
- const store = storage.getStore()
151
+ const store = storage('legacy').getStore()
132
152
  const span = store?.span
133
153
 
134
154
  if (span) {
135
155
  if (shouldSetProbe && this.di) {
136
156
  const probeInformation = this.addDiProbe(error)
137
157
  if (probeInformation) {
138
- const { probeId, stackIndex, setProbePromise } = probeInformation
139
- this.runningTestProbeId = probeId
158
+ const { file, line, stackIndex, setProbePromise } = probeInformation
159
+ this.runningTestProbe = { file, line }
140
160
  this.testErrorStackIndex = stackIndex
141
161
  promises.setProbePromise = setProbePromise
142
162
  }
@@ -221,13 +241,13 @@ class VitestPlugin extends CiPlugin {
221
241
  }
222
242
  })
223
243
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
224
- const store = storage.getStore()
244
+ const store = storage('legacy').getStore()
225
245
  this.enter(testSuiteSpan, store)
226
246
  this.testSuiteSpan = testSuiteSpan
227
247
  })
228
248
 
229
249
  this.addSub('ci:vitest:test-suite:finish', ({ status, onFinish }) => {
230
- const store = storage.getStore()
250
+ const store = storage('legacy').getStore()
231
251
  const span = store?.span
232
252
  if (span) {
233
253
  span.setTag(TEST_STATUS, status)
@@ -237,13 +257,13 @@ class VitestPlugin extends CiPlugin {
237
257
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
238
258
  // TODO: too frequent flush - find for method in worker to decrease frequency
239
259
  this.tracer._exporter.flush(onFinish)
240
- if (this.runningTestProbeId) {
241
- this.removeDiProbe(this.runningTestProbeId)
260
+ if (this.runningTestProbe) {
261
+ this.removeDiProbe(this.runningTestProbe)
242
262
  }
243
263
  })
244
264
 
245
265
  this.addSub('ci:vitest:test-suite:error', ({ error }) => {
246
- const store = storage.getStore()
266
+ const store = storage('legacy').getStore()
247
267
  const span = store?.span
248
268
  if (span && error) {
249
269
  span.setTag('error', error)
@@ -257,6 +277,7 @@ class VitestPlugin extends CiPlugin {
257
277
  testCodeCoverageLinesTotal,
258
278
  isEarlyFlakeDetectionEnabled,
259
279
  isEarlyFlakeDetectionFaulty,
280
+ isQuarantinedTestsEnabled,
260
281
  onFinish
261
282
  }) => {
262
283
  this.testSessionSpan.setTag(TEST_STATUS, status)
@@ -275,6 +296,9 @@ class VitestPlugin extends CiPlugin {
275
296
  if (isEarlyFlakeDetectionFaulty) {
276
297
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'faulty')
277
298
  }
299
+ if (isQuarantinedTestsEnabled) {
300
+ this.testSessionSpan.setTag(TEST_MANAGEMENT_ENABLED, 'true')
301
+ }
278
302
  this.testModuleSpan.finish()
279
303
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
280
304
  this.testSessionSpan.finish()
@@ -30,7 +30,7 @@ function disable () {
30
30
  }
31
31
 
32
32
  function onGraphqlStartResolve ({ context, resolverInfo }) {
33
- const req = storage.getStore()?.req
33
+ const req = storage('legacy').getStore()?.req
34
34
 
35
35
  if (!req) return
36
36
 
@@ -49,7 +49,7 @@ function onGraphqlStartResolve ({ context, resolverInfo }) {
49
49
  }
50
50
 
51
51
  function enterInApolloMiddleware (data) {
52
- const req = data?.req || storage.getStore()?.req
52
+ const req = data?.req || storage('legacy').getStore()?.req
53
53
  if (!req) return
54
54
 
55
55
  graphqlRequestData.set(req, {
@@ -59,7 +59,7 @@ function enterInApolloMiddleware (data) {
59
59
  }
60
60
 
61
61
  function enterInApolloServerCoreRequest () {
62
- const req = storage.getStore()?.req
62
+ const req = storage('legacy').getStore()?.req
63
63
  if (!req) return
64
64
 
65
65
  graphqlRequestData.set(req, {
@@ -69,13 +69,13 @@ function enterInApolloServerCoreRequest () {
69
69
  }
70
70
 
71
71
  function exitFromApolloMiddleware (data) {
72
- const req = data?.req || storage.getStore()?.req
72
+ const req = data?.req || storage('legacy').getStore()?.req
73
73
  const requestData = graphqlRequestData.get(req)
74
74
  if (requestData) requestData.inApolloMiddleware = false
75
75
  }
76
76
 
77
77
  function enterInApolloRequest () {
78
- const req = storage.getStore()?.req
78
+ const req = storage('legacy').getStore()?.req
79
79
 
80
80
  const requestData = graphqlRequestData.get(req)
81
81
  if (requestData?.inApolloMiddleware) {
@@ -85,7 +85,7 @@ function enterInApolloRequest () {
85
85
  }
86
86
 
87
87
  function beforeWriteApolloGraphqlResponse ({ abortController, abortData }) {
88
- const req = storage.getStore()?.req
88
+ const req = storage('legacy').getStore()?.req
89
89
  if (!req) return
90
90
 
91
91
  const requestData = graphqlRequestData.get(req)
@@ -1,12 +1,12 @@
1
1
  'use strict'
2
2
 
3
- const InjectionAnalyzer = require('./injection-analyzer')
4
3
  const { CODE_INJECTION } = require('../vulnerabilities')
4
+ const StoredInjectionAnalyzer = require('./stored-injection-analyzer')
5
5
  const { INSTRUMENTED_SINK } = require('../telemetry/iast-metric')
6
6
  const { storage } = require('../../../../../datadog-core')
7
7
  const { getIastContext } = require('../iast-context')
8
8
 
9
- class CodeInjectionAnalyzer extends InjectionAnalyzer {
9
+ class CodeInjectionAnalyzer extends StoredInjectionAnalyzer {
10
10
  constructor () {
11
11
  super(CODE_INJECTION)
12
12
  this.evalInstrumentedInc = false
@@ -15,7 +15,7 @@ class CodeInjectionAnalyzer extends InjectionAnalyzer {
15
15
  onConfigure () {
16
16
  this.addSub('datadog:eval:call', ({ script }) => {
17
17
  if (!this.evalInstrumentedInc) {
18
- const store = storage.getStore()
18
+ const store = storage('legacy').getStore()
19
19
  const iastContext = getIastContext(store)
20
20
  const tags = INSTRUMENTED_SINK.formatTags(CODE_INJECTION)
21
21
 
@@ -31,10 +31,6 @@ class CodeInjectionAnalyzer extends InjectionAnalyzer {
31
31
  this.addSub('datadog:vm:run-script:start', ({ code }) => this.analyze(code))
32
32
  this.addSub('datadog:vm:source-text-module:start', ({ code }) => this.analyze(code))
33
33
  }
34
-
35
- _areRangesVulnerable () {
36
- return true
37
- }
38
34
  }
39
35
 
40
36
  module.exports = new CodeInjectionAnalyzer()
@@ -5,8 +5,13 @@ const { SQL_ROW_VALUE } = require('../taint-tracking/source-types')
5
5
 
6
6
  class InjectionAnalyzer extends Analyzer {
7
7
  _isVulnerable (value, iastContext) {
8
- const ranges = value && getRanges(iastContext, value)
8
+ let ranges = value && getRanges(iastContext, value)
9
9
  if (ranges?.length > 0) {
10
+ ranges = this._filterSecureRanges(ranges)
11
+ if (!ranges?.length) {
12
+ this._incrementSuppressedMetric(iastContext)
13
+ }
14
+
10
15
  return this._areRangesVulnerable(ranges)
11
16
  }
12
17
 
@@ -21,6 +26,15 @@ class InjectionAnalyzer extends Analyzer {
21
26
  _areRangesVulnerable (ranges) {
22
27
  return ranges?.some(range => range.iinfo.type !== SQL_ROW_VALUE)
23
28
  }
29
+
30
+ _filterSecureRanges (ranges) {
31
+ return ranges?.filter(range => !this._isRangeSecure(range))
32
+ }
33
+
34
+ _isRangeSecure (range) {
35
+ const { secureMarks } = range
36
+ return (secureMarks & this._secureMark) === this._secureMark
37
+ }
24
38
  }
25
39
 
26
40
  module.exports = InjectionAnalyzer
@@ -4,29 +4,13 @@ const InjectionAnalyzer = require('./injection-analyzer')
4
4
  const { NOSQL_MONGODB_INJECTION } = require('../vulnerabilities')
5
5
  const { getRanges, addSecureMark } = require('../taint-tracking/operations')
6
6
  const { getNodeModulesPaths } = require('../path-line')
7
- const { getNextSecureMark } = require('../taint-tracking/secure-marks-generator')
8
7
  const { storage } = require('../../../../../datadog-core')
9
8
  const { getIastContext } = require('../iast-context')
10
9
  const { HTTP_REQUEST_PARAMETER, HTTP_REQUEST_BODY } = require('../taint-tracking/source-types')
11
10
 
12
11
  const EXCLUDED_PATHS_FROM_STACK = getNodeModulesPaths('mongodb', 'mongoose', 'mquery')
13
- const MONGODB_NOSQL_SECURE_MARK = getNextSecureMark()
14
-
15
- function iterateObjectStrings (target, fn, levelKeys = [], depth = 20, visited = new Set()) {
16
- if (target !== null && typeof target === 'object') {
17
- Object.keys(target).forEach((key) => {
18
- const nextLevelKeys = [...levelKeys, key]
19
- const val = target[key]
20
-
21
- if (typeof val === 'string') {
22
- fn(val, nextLevelKeys, target, key)
23
- } else if (depth > 0 && !visited.has(val)) {
24
- iterateObjectStrings(val, fn, nextLevelKeys, depth - 1, visited)
25
- visited.add(val)
26
- }
27
- })
28
- }
29
- }
12
+ const { NOSQL_MONGODB_INJECTION_MARK } = require('../taint-tracking/secure-marks')
13
+ const { iterateObjectStrings } = require('../utils')
30
14
 
31
15
  class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
32
16
  constructor () {
@@ -38,7 +22,7 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
38
22
  this.configureSanitizers()
39
23
 
40
24
  const onStart = ({ filters }) => {
41
- const store = storage.getStore()
25
+ const store = storage('legacy').getStore()
42
26
  if (store && !store.nosqlAnalyzed && filters?.length) {
43
27
  filters.forEach(filter => {
44
28
  this.analyze({ filter }, store)
@@ -51,14 +35,14 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
51
35
  const onStartAndEnterWithStore = (message) => {
52
36
  const store = onStart(message || {})
53
37
  if (store) {
54
- storage.enterWith({ ...store, nosqlAnalyzed: true, nosqlParentStore: store })
38
+ storage('legacy').enterWith({ ...store, nosqlAnalyzed: true, nosqlParentStore: store })
55
39
  }
56
40
  }
57
41
 
58
42
  const onFinish = () => {
59
- const store = storage.getStore()
43
+ const store = storage('legacy').getStore()
60
44
  if (store?.nosqlParentStore) {
61
- storage.enterWith(store.nosqlParentStore)
45
+ storage('legacy').enterWith(store.nosqlParentStore)
62
46
  }
63
47
  }
64
48
 
@@ -74,7 +58,7 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
74
58
 
75
59
  configureSanitizers () {
76
60
  this.addNotSinkSub('datadog:express-mongo-sanitize:filter:finish', ({ sanitizedProperties, req }) => {
77
- const store = storage.getStore()
61
+ const store = storage('legacy').getStore()
78
62
  const iastContext = getIastContext(store)
79
63
 
80
64
  if (iastContext) { // do nothing if we are not in an iast request
@@ -88,7 +72,7 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
88
72
  const currentLevelKey = levelKeys[i]
89
73
 
90
74
  if (i === levelsLength - 1) {
91
- parentObj[currentLevelKey] = addSecureMark(iastContext, value, MONGODB_NOSQL_SECURE_MARK)
75
+ parentObj[currentLevelKey] = addSecureMark(iastContext, value, NOSQL_MONGODB_INJECTION_MARK)
92
76
  } else {
93
77
  parentObj = parentObj[currentLevelKey]
94
78
  }
@@ -100,13 +84,13 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
100
84
  })
101
85
 
102
86
  this.addNotSinkSub('datadog:express-mongo-sanitize:sanitize:finish', ({ sanitizedObject }) => {
103
- const store = storage.getStore()
87
+ const store = storage('legacy').getStore()
104
88
  const iastContext = getIastContext(store)
105
89
 
106
90
  if (iastContext) { // do nothing if we are not in an iast request
107
91
  iterateObjectStrings(sanitizedObject, function (value, levelKeys, parent, lastKey) {
108
92
  try {
109
- parent[lastKey] = addSecureMark(iastContext, value, MONGODB_NOSQL_SECURE_MARK)
93
+ parent[lastKey] = addSecureMark(iastContext, value, NOSQL_MONGODB_INJECTION_MARK)
110
94
  } catch {
111
95
  // if it is a readonly property, do nothing
112
96
  }
@@ -121,8 +105,7 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
121
105
 
122
106
  _isVulnerableRange (range) {
123
107
  const rangeType = range?.iinfo?.type
124
- const isVulnerableType = rangeType === HTTP_REQUEST_PARAMETER || rangeType === HTTP_REQUEST_BODY
125
- return isVulnerableType && (range.secureMarks & MONGODB_NOSQL_SECURE_MARK) !== MONGODB_NOSQL_SECURE_MARK
108
+ return rangeType === HTTP_REQUEST_PARAMETER || rangeType === HTTP_REQUEST_BODY
126
109
  }
127
110
 
128
111
  _isVulnerable (value, iastContext) {
@@ -137,10 +120,15 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
137
120
  const allRanges = []
138
121
 
139
122
  iterateObjectStrings(value.filter, (val, nextLevelKeys) => {
140
- const ranges = getRanges(iastContext, val)
123
+ let ranges = getRanges(iastContext, val)
141
124
  if (ranges?.length) {
142
125
  const filteredRanges = []
143
126
 
127
+ ranges = this._filterSecureRanges(ranges)
128
+ if (!ranges.length) {
129
+ this._incrementSuppressedMetric(iastContext)
130
+ }
131
+
144
132
  for (const range of ranges) {
145
133
  if (this._isVulnerableRange(range)) {
146
134
  isVulnerable = true
@@ -175,4 +163,3 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
175
163
  }
176
164
 
177
165
  module.exports = new NosqlInjectionMongodbAnalyzer()
178
- module.exports.MONGODB_NOSQL_SECURE_MARK = MONGODB_NOSQL_SECURE_MARK
@@ -29,7 +29,7 @@ class PathTraversalAnalyzer extends InjectionAnalyzer {
29
29
 
30
30
  onConfigure () {
31
31
  this.addSub('apm:fs:operation:start', (obj) => {
32
- const store = storage.getStore()
32
+ const store = storage('legacy').getStore()
33
33
  const outOfReqOrChild = !store?.fs?.root
34
34
 
35
35
  // we could filter out all the nested fs.operations based on store.fs.root
@@ -84,7 +84,7 @@ class PathTraversalAnalyzer extends InjectionAnalyzer {
84
84
  }
85
85
 
86
86
  analyze (value) {
87
- const iastContext = getIastContext(storage.getStore())
87
+ const iastContext = getIastContext(storage('legacy').getStore())
88
88
  if (!iastContext) {
89
89
  return
90
90
  }
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
 
3
- const InjectionAnalyzer = require('./injection-analyzer')
4
3
  const { SQL_INJECTION } = require('../vulnerabilities')
5
4
  const { getRanges } = require('../taint-tracking/operations')
6
5
  const { storage } = require('../../../../../datadog-core')
7
6
  const { getNodeModulesPaths } = require('../path-line')
7
+ const StoredInjectionAnalyzer = require('./stored-injection-analyzer')
8
8
 
9
9
  const EXCLUDED_PATHS = getNodeModulesPaths('mysql', 'mysql2', 'sequelize', 'pg-pool', 'knex')
10
10
 
11
- class SqlInjectionAnalyzer extends InjectionAnalyzer {
11
+ class SqlInjectionAnalyzer extends StoredInjectionAnalyzer {
12
12
  constructor () {
13
13
  super(SQL_INJECTION)
14
14
  }
@@ -38,18 +38,18 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {
38
38
  }
39
39
 
40
40
  getStoreAndAnalyze (query, dialect) {
41
- const parentStore = storage.getStore()
41
+ const parentStore = storage('legacy').getStore()
42
42
  if (parentStore) {
43
43
  this.analyze(query, parentStore, dialect)
44
44
 
45
- storage.enterWith({ ...parentStore, sqlAnalyzed: true, sqlParentStore: parentStore })
45
+ storage('legacy').enterWith({ ...parentStore, sqlAnalyzed: true, sqlParentStore: parentStore })
46
46
  }
47
47
  }
48
48
 
49
49
  returnToParentStore () {
50
- const store = storage.getStore()
50
+ const store = storage('legacy').getStore()
51
51
  if (store && store.sqlParentStore) {
52
- storage.enterWith(store.sqlParentStore)
52
+ storage('legacy').enterWith(store.sqlParentStore)
53
53
  }
54
54
  }
55
55
 
@@ -59,7 +59,7 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {
59
59
  }
60
60
 
61
61
  analyze (value, store, dialect) {
62
- store = store || storage.getStore()
62
+ store = store || storage('legacy').getStore()
63
63
  if (!(store && store.sqlAnalyzed)) {
64
64
  super.analyze(value, store, dialect)
65
65
  }
@@ -82,10 +82,6 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {
82
82
  return knexDialect.toUpperCase()
83
83
  }
84
84
  }
85
-
86
- _areRangesVulnerable () {
87
- return true
88
- }
89
85
  }
90
86
 
91
87
  module.exports = new SqlInjectionAnalyzer()
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ const InjectionAnalyzer = require('./injection-analyzer')
4
+
5
+ class StoredInjectionAnalyzer extends InjectionAnalyzer {
6
+ _areRangesVulnerable (ranges) {
7
+ return ranges?.length > 0
8
+ }
9
+ }
10
+
11
+ module.exports = StoredInjectionAnalyzer
@@ -1,9 +1,9 @@
1
1
  'use strict'
2
2
 
3
- const InjectionAnalyzer = require('./injection-analyzer')
4
3
  const { TEMPLATE_INJECTION } = require('../vulnerabilities')
4
+ const StoredInjectionAnalyzer = require('./stored-injection-analyzer')
5
5
 
6
- class TemplateInjectionAnalyzer extends InjectionAnalyzer {
6
+ class TemplateInjectionAnalyzer extends StoredInjectionAnalyzer {
7
7
  constructor () {
8
8
  super(TEMPLATE_INJECTION)
9
9
  }
@@ -13,10 +13,6 @@ class TemplateInjectionAnalyzer extends InjectionAnalyzer {
13
13
  this.addSub('datadog:handlebars:register-partial:start', ({ partial }) => this.analyze(partial))
14
14
  this.addSub('datadog:pug:compile:start', ({ source }) => this.analyze(source))
15
15
  }
16
-
17
- _areRangesVulnerable () {
18
- return true
19
- }
20
16
  }
21
17
 
22
18
  module.exports = new TemplateInjectionAnalyzer()