dd-trace 3.54.0 → 3.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 (53) hide show
  1. package/index.d.ts +15 -0
  2. package/package.json +3 -2
  3. package/packages/datadog-instrumentations/src/fetch.js +6 -45
  4. package/packages/datadog-instrumentations/src/helpers/fetch.js +17 -0
  5. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -1
  6. package/packages/datadog-instrumentations/src/jest.js +161 -14
  7. package/packages/datadog-instrumentations/src/kafkajs.js +4 -7
  8. package/packages/datadog-instrumentations/src/mongoose.js +2 -1
  9. package/packages/datadog-instrumentations/src/oracledb.js +1 -1
  10. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +6 -1
  11. package/packages/datadog-instrumentations/src/selenium.js +69 -0
  12. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  13. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -2
  14. package/packages/datadog-plugin-cypress/src/support.js +19 -3
  15. package/packages/datadog-plugin-fetch/src/index.js +17 -11
  16. package/packages/datadog-plugin-jest/src/index.js +7 -2
  17. package/packages/datadog-plugin-mocha/src/index.js +4 -5
  18. package/packages/datadog-plugin-openai/src/services.js +2 -1
  19. package/packages/datadog-plugin-playwright/src/index.js +2 -2
  20. package/packages/datadog-plugin-selenium/src/index.js +71 -0
  21. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  22. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +70 -0
  23. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +14 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +12 -0
  25. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-rule-type.js +6 -0
  26. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-analyzer.js +5 -50
  27. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +742 -0
  28. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +539 -66
  29. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +6 -2
  30. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  31. package/packages/dd-trace/src/appsec/reporter.js +11 -10
  32. package/packages/dd-trace/src/appsec/telemetry.js +36 -7
  33. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  34. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +9 -2
  35. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
  36. package/packages/dd-trace/src/config.js +97 -10
  37. package/packages/dd-trace/src/dogstatsd.js +13 -11
  38. package/packages/dd-trace/src/index.js +5 -1
  39. package/packages/dd-trace/src/noop/dogstatsd.js +11 -0
  40. package/packages/dd-trace/src/noop/proxy.js +3 -0
  41. package/packages/dd-trace/src/opentracing/propagation/text_map.js +10 -4
  42. package/packages/dd-trace/src/opentracing/span.js +2 -0
  43. package/packages/dd-trace/src/plugins/index.js +2 -0
  44. package/packages/dd-trace/src/plugins/util/git.js +33 -11
  45. package/packages/dd-trace/src/plugins/util/test.js +34 -3
  46. package/packages/dd-trace/src/profiling/config.js +8 -4
  47. package/packages/dd-trace/src/profiling/profiler.js +4 -0
  48. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +33 -0
  49. package/packages/dd-trace/src/profiling/ssi-telemetry.js +167 -0
  50. package/packages/dd-trace/src/proxy.js +7 -1
  51. package/packages/dd-trace/src/tagger.js +13 -3
  52. package/packages/dd-trace/src/telemetry/index.js +5 -4
  53. package/packages/dd-trace/src/telemetry/metrics.js +2 -2
@@ -4,6 +4,16 @@ let knownTestsForSuite = []
4
4
  let suiteTests = []
5
5
  let earlyFlakeDetectionNumRetries = 0
6
6
 
7
+ // If the test is using multi domain with cy.origin, trying to access
8
+ // window properties will result in a cross origin error.
9
+ function safeGetRum (window) {
10
+ try {
11
+ return window.DD_RUM
12
+ } catch (e) {
13
+ return null
14
+ }
15
+ }
16
+
7
17
  function isNewTest (test) {
8
18
  return !knownTestsForSuite.includes(test.fullTitle())
9
19
  }
@@ -62,7 +72,7 @@ before(function () {
62
72
 
63
73
  after(() => {
64
74
  cy.window().then(win => {
65
- if (win.DD_RUM) {
75
+ if (safeGetRum(win)) {
66
76
  win.dispatchEvent(new Event('beforeunload'))
67
77
  }
68
78
  })
@@ -84,9 +94,15 @@ afterEach(function () {
84
94
  testInfo.testSourceLine = Cypress.mocha.getRunner().currentRunnable.invocationDetails.line
85
95
  } catch (e) {}
86
96
 
87
- if (win.DD_RUM) {
97
+ if (safeGetRum(win)) {
88
98
  testInfo.isRUMActive = true
89
99
  }
90
- cy.task('dd:afterEach', { test: testInfo, coverage: win.__coverage__ })
100
+ let coverage
101
+ try {
102
+ coverage = win.__coverage__
103
+ } catch (e) {
104
+ // ignore error and continue
105
+ }
106
+ cy.task('dd:afterEach', { test: testInfo, coverage })
91
107
  })
92
108
  })
@@ -4,28 +4,34 @@ const HttpClientPlugin = require('../../datadog-plugin-http/src/client')
4
4
 
5
5
  class FetchPlugin extends HttpClientPlugin {
6
6
  static get id () { return 'fetch' }
7
- static get prefix () { return 'apm:fetch:request' }
7
+ static get prefix () { return 'tracing:apm:fetch:request' }
8
8
 
9
- addTraceSub (eventName, handler) {
10
- this.addSub(`apm:${this.constructor.id}:${this.operation}:${eventName}`, handler)
11
- }
12
-
13
- bindStart (message) {
14
- const req = message.req
9
+ bindStart (ctx) {
10
+ const req = ctx.req
15
11
  const options = new URL(req.url)
16
12
  const headers = options.headers = Object.fromEntries(req.headers.entries())
17
13
 
18
14
  options.method = req.method
19
15
 
20
- message.args = { options }
16
+ ctx.args = { options }
21
17
 
22
- const store = super.bindStart(message)
18
+ const store = super.bindStart(ctx)
23
19
 
24
- message.headers = headers
25
- message.req = new globalThis.Request(req, { headers })
20
+ ctx.headers = headers
21
+ ctx.req = new globalThis.Request(req, { headers })
26
22
 
27
23
  return store
28
24
  }
25
+
26
+ error (ctx) {
27
+ if (ctx.error.name === 'AbortError') return
28
+ return super.error(ctx)
29
+ }
30
+
31
+ asyncEnd (ctx) {
32
+ ctx.res = ctx.result
33
+ return this.finish(ctx)
34
+ }
29
35
  }
30
36
 
31
37
  module.exports = FetchPlugin
@@ -18,7 +18,8 @@ const {
18
18
  TEST_SOURCE_FILE,
19
19
  TEST_IS_NEW,
20
20
  TEST_IS_RETRY,
21
- TEST_EARLY_FLAKE_IS_ENABLED,
21
+ TEST_EARLY_FLAKE_ENABLED,
22
+ TEST_EARLY_FLAKE_ABORT_REASON,
22
23
  JEST_DISPLAY_NAME
23
24
  } = require('../../dd-trace/src/plugins/util/test')
24
25
  const { COMPONENT } = require('../../dd-trace/src/constants')
@@ -89,6 +90,7 @@ class JestPlugin extends CiPlugin {
89
90
  hasForcedToRunSuites,
90
91
  error,
91
92
  isEarlyFlakeDetectionEnabled,
93
+ isEarlyFlakeDetectionFaulty,
92
94
  onDone
93
95
  }) => {
94
96
  this.testSessionSpan.setTag(TEST_STATUS, status)
@@ -115,7 +117,10 @@ class JestPlugin extends CiPlugin {
115
117
  )
116
118
 
117
119
  if (isEarlyFlakeDetectionEnabled) {
118
- this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true')
120
+ this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
121
+ }
122
+ if (isEarlyFlakeDetectionFaulty) {
123
+ this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'faulty')
119
124
  }
120
125
 
121
126
  this.testModuleSpan.finish()
@@ -20,7 +20,7 @@ const {
20
20
  removeEfdStringFromTestName,
21
21
  TEST_IS_NEW,
22
22
  TEST_IS_RETRY,
23
- TEST_EARLY_FLAKE_IS_ENABLED
23
+ TEST_EARLY_FLAKE_ENABLED
24
24
  } = require('../../dd-trace/src/plugins/util/test')
25
25
  const { COMPONENT } = require('../../dd-trace/src/constants')
26
26
  const {
@@ -144,10 +144,9 @@ class MochaPlugin extends CiPlugin {
144
144
 
145
145
  this.addSub('ci:mocha:test:finish', (status) => {
146
146
  const store = storage.getStore()
147
+ const span = store?.span
147
148
 
148
- if (store && store.span) {
149
- const span = store.span
150
-
149
+ if (span) {
151
150
  span.setTag(TEST_STATUS, status)
152
151
 
153
152
  span.finish()
@@ -223,7 +222,7 @@ class MochaPlugin extends CiPlugin {
223
222
  )
224
223
 
225
224
  if (isEarlyFlakeDetectionEnabled) {
226
- this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true')
225
+ this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
227
226
  }
228
227
 
229
228
  this.testModuleSpan.finish()
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const { DogStatsDClient, NoopDogStatsDClient } = require('../../dd-trace/src/dogstatsd')
3
+ const { DogStatsDClient } = require('../../dd-trace/src/dogstatsd')
4
+ const NoopDogStatsDClient = require('../../dd-trace/src/noop/dogstatsd')
4
5
  const { ExternalLogger, NoopExternalLogger } = require('../../dd-trace/src/external-logger/src')
5
6
 
6
7
  const FLUSH_INTERVAL = 10 * 1000
@@ -14,7 +14,7 @@ const {
14
14
  TEST_CONFIGURATION_BROWSER_NAME,
15
15
  TEST_IS_NEW,
16
16
  TEST_IS_RETRY,
17
- TEST_EARLY_FLAKE_IS_ENABLED
17
+ TEST_EARLY_FLAKE_ENABLED
18
18
  } = require('../../dd-trace/src/plugins/util/test')
19
19
  const { RESOURCE_NAME } = require('../../../ext/tags')
20
20
  const { COMPONENT } = require('../../dd-trace/src/constants')
@@ -41,7 +41,7 @@ class PlaywrightPlugin extends CiPlugin {
41
41
  this.testSessionSpan.setTag(TEST_STATUS, status)
42
42
 
43
43
  if (isEarlyFlakeDetectionEnabled) {
44
- this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true')
44
+ this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
45
45
  }
46
46
 
47
47
  if (this.numFailedSuites > 0) {
@@ -0,0 +1,71 @@
1
+ const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
2
+ const { storage } = require('../../datadog-core')
3
+
4
+ const {
5
+ TEST_IS_RUM_ACTIVE,
6
+ TEST_BROWSER_DRIVER,
7
+ TEST_BROWSER_DRIVER_VERSION,
8
+ TEST_BROWSER_NAME,
9
+ TEST_BROWSER_VERSION,
10
+ TEST_TYPE
11
+ } = require('../../dd-trace/src/plugins/util/test')
12
+ const { SPAN_TYPE } = require('../../../ext/tags')
13
+
14
+ function isTestSpan (span) {
15
+ return span.context()._tags[SPAN_TYPE] === 'test'
16
+ }
17
+
18
+ function getTestSpanFromTrace (trace) {
19
+ for (const span of trace.started) {
20
+ if (isTestSpan(span)) {
21
+ return span
22
+ }
23
+ }
24
+ return null
25
+ }
26
+
27
+ class SeleniumPlugin extends CiPlugin {
28
+ static get id () {
29
+ return 'selenium'
30
+ }
31
+
32
+ constructor (...args) {
33
+ super(...args)
34
+
35
+ this.addSub('ci:selenium:driver:get', ({
36
+ setTraceId,
37
+ seleniumVersion,
38
+ browserName,
39
+ browserVersion,
40
+ isRumActive
41
+ }) => {
42
+ const store = storage.getStore()
43
+ const span = store?.span
44
+ if (!span) {
45
+ return
46
+ }
47
+ let testSpan
48
+ if (isTestSpan(span)) {
49
+ testSpan = span
50
+ } else {
51
+ testSpan = getTestSpanFromTrace(span.context()._trace)
52
+ }
53
+ if (!testSpan) {
54
+ return
55
+ }
56
+ if (setTraceId) {
57
+ setTraceId(testSpan.context().toTraceId())
58
+ }
59
+ if (isRumActive) {
60
+ testSpan.setTag(TEST_IS_RUM_ACTIVE, 'true')
61
+ }
62
+ testSpan.setTag(TEST_BROWSER_DRIVER, 'selenium')
63
+ testSpan.setTag(TEST_BROWSER_DRIVER_VERSION, seleniumVersion)
64
+ testSpan.setTag(TEST_BROWSER_NAME, browserName)
65
+ testSpan.setTag(TEST_BROWSER_VERSION, browserVersion)
66
+ testSpan.setTag(TEST_TYPE, 'browser')
67
+ })
68
+ }
69
+ }
70
+
71
+ module.exports = SeleniumPlugin
@@ -2,6 +2,7 @@
2
2
 
3
3
  module.exports = {
4
4
  COMMAND_INJECTION_ANALYZER: require('./command-injection-analyzer'),
5
+ HARCODED_PASSWORD_ANALYZER: require('./hardcoded-password-analyzer'),
5
6
  HARCODED_SECRET_ANALYZER: require('./hardcoded-secret-analyzer'),
6
7
  HEADER_INJECTION_ANALYZER: require('./header-injection-analyzer'),
7
8
  HSTS_HEADER_MISSING_ANALYZER: require('./hsts-header-missing-analyzer'),
@@ -0,0 +1,70 @@
1
+ 'use strict'
2
+
3
+ const Analyzer = require('./vulnerability-analyzer')
4
+ const { getRelativePath } = require('../path-line')
5
+
6
+ class HardcodedBaseAnalyzer extends Analyzer {
7
+ constructor (type, allRules = [], valueOnlyRules = []) {
8
+ super(type)
9
+
10
+ this.allRules = allRules
11
+ this.valueOnlyRules = valueOnlyRules
12
+ }
13
+
14
+ onConfigure () {
15
+ this.addSub('datadog:secrets:result', (secrets) => { this.analyze(secrets) })
16
+ }
17
+
18
+ analyze (secrets) {
19
+ if (!secrets?.file || !secrets.literals) return
20
+
21
+ const { allRules, valueOnlyRules } = this
22
+
23
+ const matches = []
24
+ for (const literal of secrets.literals) {
25
+ const { value, locations } = literal
26
+ if (!value || !locations) continue
27
+
28
+ for (const location of locations) {
29
+ let match
30
+ if (location.ident) {
31
+ const fullValue = `${location.ident}=${value}`
32
+ match = allRules.find(rule => fullValue.match(rule.regex))
33
+ } else {
34
+ match = valueOnlyRules.find(rule => value.match(rule.regex))
35
+ }
36
+
37
+ if (match) {
38
+ matches.push({ location, ruleId: match.id })
39
+ }
40
+ }
41
+ }
42
+
43
+ if (matches.length) {
44
+ const file = getRelativePath(secrets.file)
45
+
46
+ matches
47
+ .forEach(match => this._report({
48
+ file,
49
+ line: match.location.line,
50
+ column: match.location.column,
51
+ data: match.ruleId
52
+ }))
53
+ }
54
+ }
55
+
56
+ _getEvidence (value) {
57
+ return { value: `${value.data}` }
58
+ }
59
+
60
+ _getLocation (value) {
61
+ return {
62
+ path: value.file,
63
+ line: value.line,
64
+ column: value.column,
65
+ isInternal: false
66
+ }
67
+ }
68
+ }
69
+
70
+ module.exports = HardcodedBaseAnalyzer
@@ -0,0 +1,14 @@
1
+ 'use strict'
2
+
3
+ const { HARDCODED_PASSWORD } = require('../vulnerabilities')
4
+ const HardcodedBaseAnalyzer = require('./hardcoded-base-analyzer')
5
+
6
+ const allRules = require('./hardcoded-password-rules')
7
+
8
+ class HardcodedPasswordAnalyzer extends HardcodedBaseAnalyzer {
9
+ constructor () {
10
+ super(HARDCODED_PASSWORD, allRules)
11
+ }
12
+ }
13
+
14
+ module.exports = new HardcodedPasswordAnalyzer()
@@ -0,0 +1,12 @@
1
+ /* eslint-disable max-len */
2
+ 'use strict'
3
+
4
+ const { NameAndValue } = require('./hardcoded-rule-type')
5
+
6
+ module.exports = [
7
+ {
8
+ id: 'hardcoded-password',
9
+ regex: /(?:pwd|pswd|pass|secret)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9a-z\-_.=]{10,150})(?:['"\s\x60;]|$)/i,
10
+ type: NameAndValue
11
+ }
12
+ ]
@@ -0,0 +1,6 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ ValueOnly: 'ValueOnly',
5
+ NameAndValue: 'NameAndValue'
6
+ }
@@ -1,59 +1,14 @@
1
1
  'use strict'
2
2
 
3
- const Analyzer = require('./vulnerability-analyzer')
4
3
  const { HARDCODED_SECRET } = require('../vulnerabilities')
5
- const { getRelativePath } = require('../path-line')
4
+ const HardcodedBaseAnalyzer = require('./hardcoded-base-analyzer')
5
+ const { ValueOnly } = require('./hardcoded-rule-type')
6
6
 
7
- const secretRules = require('./hardcoded-secrets-rules')
7
+ const allRules = require('./hardcoded-secret-rules')
8
8
 
9
- class HardcodedSecretAnalyzer extends Analyzer {
9
+ class HardcodedSecretAnalyzer extends HardcodedBaseAnalyzer {
10
10
  constructor () {
11
- super(HARDCODED_SECRET)
12
- }
13
-
14
- onConfigure () {
15
- this.addSub('datadog:secrets:result', (secrets) => { this.analyze(secrets) })
16
- }
17
-
18
- analyze (secrets) {
19
- if (!secrets?.file || !secrets.literals) return
20
-
21
- const matches = secrets.literals
22
- .filter(literal => literal.value && literal.locations?.length)
23
- .map(literal => {
24
- const match = secretRules.find(rule => literal.value.match(rule.regex))
25
-
26
- return match ? { locations: literal.locations, ruleId: match.id } : undefined
27
- })
28
- .filter(match => !!match)
29
-
30
- if (matches.length) {
31
- const file = getRelativePath(secrets.file)
32
-
33
- matches.forEach(match => {
34
- match.locations
35
- .filter(location => location.line)
36
- .forEach(location => this._report({
37
- file,
38
- line: location.line,
39
- column: location.column,
40
- data: match.ruleId
41
- }))
42
- })
43
- }
44
- }
45
-
46
- _getEvidence (value) {
47
- return { value: `${value.data}` }
48
- }
49
-
50
- _getLocation (value) {
51
- return {
52
- path: value.file,
53
- line: value.line,
54
- column: value.column,
55
- isInternal: false
56
- }
11
+ super(HARDCODED_SECRET, allRules, allRules.filter(rule => rule.type === ValueOnly))
57
12
  }
58
13
  }
59
14