dd-trace 3.37.0 → 3.38.1

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 (50) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/package.json +4 -3
  3. package/packages/datadog-instrumentations/src/body-parser.js +2 -1
  4. package/packages/datadog-instrumentations/src/cucumber.js +24 -4
  5. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +45 -0
  6. package/packages/datadog-instrumentations/src/express.js +2 -1
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
  8. package/packages/datadog-instrumentations/src/jest.js +20 -11
  9. package/packages/datadog-instrumentations/src/knex.js +62 -1
  10. package/packages/datadog-instrumentations/src/mocha.js +19 -4
  11. package/packages/datadog-instrumentations/src/mongodb.js +63 -0
  12. package/packages/datadog-instrumentations/src/mongoose.js +140 -1
  13. package/packages/datadog-instrumentations/src/next.js +40 -0
  14. package/packages/datadog-instrumentations/src/playwright.js +11 -2
  15. package/packages/datadog-plugin-cucumber/src/index.js +17 -5
  16. package/packages/datadog-plugin-cypress/src/plugin.js +38 -8
  17. package/packages/datadog-plugin-jest/src/index.js +19 -4
  18. package/packages/datadog-plugin-jest/src/util.js +45 -2
  19. package/packages/datadog-plugin-memcached/src/index.js +10 -5
  20. package/packages/datadog-plugin-mocha/src/index.js +19 -6
  21. package/packages/dd-trace/src/appsec/channels.js +3 -1
  22. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  23. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +166 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +21 -1
  25. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +3 -3
  26. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -2
  27. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +4 -0
  28. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +25 -12
  29. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +4 -4
  30. package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +13 -0
  31. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
  32. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +16 -0
  33. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
  34. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +9 -0
  35. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +13 -1
  36. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +169 -0
  37. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  38. package/packages/dd-trace/src/appsec/index.js +31 -13
  39. package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -3
  40. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +14 -1
  41. package/packages/dd-trace/src/config.js +8 -0
  42. package/packages/dd-trace/src/format.js +3 -0
  43. package/packages/dd-trace/src/plugin_manager.js +3 -1
  44. package/packages/dd-trace/src/plugins/util/ci.js +17 -0
  45. package/packages/dd-trace/src/plugins/util/git.js +26 -4
  46. package/packages/dd-trace/src/plugins/util/test.js +16 -1
  47. package/packages/dd-trace/src/profiling/config.js +36 -5
  48. package/packages/dd-trace/src/profiling/profilers/wall.js +7 -1
  49. package/packages/dd-trace/src/service-naming/extra-services.js +24 -0
  50. package/packages/dd-trace/src/telemetry/metrics.js +0 -5
@@ -602,6 +602,23 @@ module.exports = {
602
602
  tags[refKey] = ref
603
603
  }
604
604
 
605
+ if (env.CODEBUILD_INITIATOR?.startsWith('codepipeline/')) {
606
+ const {
607
+ CODEBUILD_BUILD_ARN,
608
+ DD_ACTION_EXECUTION_ID,
609
+ DD_PIPELINE_EXECUTION_ID
610
+ } = env
611
+ tags = {
612
+ [CI_PROVIDER_NAME]: 'awscodepipeline',
613
+ [CI_PIPELINE_ID]: DD_PIPELINE_EXECUTION_ID,
614
+ [CI_ENV_VARS]: JSON.stringify({
615
+ CODEBUILD_BUILD_ARN,
616
+ DD_PIPELINE_EXECUTION_ID,
617
+ DD_ACTION_EXECUTION_ID
618
+ })
619
+ }
620
+ }
621
+
605
622
  normalizeTag(tags, CI_WORKSPACE_PATH, resolveTilde)
606
623
  normalizeTag(tags, GIT_REPOSITORY_URL, filterSensitiveInfoFromRepository)
607
624
  normalizeTag(tags, GIT_BRANCH, normalizeRef)
@@ -61,15 +61,37 @@ function unshallowRepository () {
61
61
  }
62
62
  const defaultRemoteName = sanitizedExec('git', ['config', '--default', 'origin', '--get', 'clone.defaultRemoteName'])
63
63
  const revParseHead = sanitizedExec('git', ['rev-parse', 'HEAD'])
64
- sanitizedExec('git', [
64
+
65
+ const baseGitOptions = [
65
66
  'fetch',
66
67
  '--shallow-since="1 month ago"',
67
68
  '--update-shallow',
68
69
  '--filter=blob:none',
69
70
  '--recurse-submodules=no',
70
- defaultRemoteName,
71
- revParseHead
72
- ])
71
+ defaultRemoteName
72
+ ]
73
+
74
+ try {
75
+ execFileSync('git', [
76
+ ...baseGitOptions,
77
+ revParseHead
78
+ ], { stdio: 'pipe' })
79
+ } catch (e) {
80
+ // If the local HEAD is a commit that has not been pushed to the remote, the above command will fail.
81
+ log.error(e)
82
+ const upstreamRemote = sanitizedExec('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'])
83
+ try {
84
+ execFileSync('git', [
85
+ ...baseGitOptions,
86
+ upstreamRemote
87
+ ], { stdio: 'pipe' })
88
+ } catch (e) {
89
+ // If the CI is working on a detached HEAD or branch tracking hasn’t been set up, the above command will fail.
90
+ log.error(e)
91
+ // We use sanitizedExec here because if this last option fails, we'll give up.
92
+ sanitizedExec('git', baseGitOptions)
93
+ }
94
+ }
73
95
  }
74
96
 
75
97
  function getRepositoryUrl () {
@@ -58,6 +58,8 @@ const TEST_ITR_SKIPPING_ENABLED = 'test.itr.tests_skipping.enabled'
58
58
  const TEST_ITR_SKIPPING_TYPE = 'test.itr.tests_skipping.type'
59
59
  const TEST_ITR_SKIPPING_COUNT = 'test.itr.tests_skipping.count'
60
60
  const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
61
+ const TEST_ITR_UNSKIPPABLE = 'test.itr.unskippable'
62
+ const TEST_ITR_FORCED_RUN = 'test.itr.forced_run'
61
63
 
62
64
  const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
63
65
 
@@ -107,6 +109,8 @@ module.exports = {
107
109
  TEST_ITR_SKIPPING_COUNT,
108
110
  TEST_CODE_COVERAGE_ENABLED,
109
111
  TEST_CODE_COVERAGE_LINES_PCT,
112
+ TEST_ITR_UNSKIPPABLE,
113
+ TEST_ITR_FORCED_RUN,
110
114
  addIntelligentTestRunnerSpanTags,
111
115
  getCoveredFilenamesFromCoverage,
112
116
  resetCoverage,
@@ -366,7 +370,9 @@ function addIntelligentTestRunnerSpanTags (
366
370
  isCodeCoverageEnabled,
367
371
  testCodeCoverageLinesTotal,
368
372
  skippingCount,
369
- skippingType = 'suite'
373
+ skippingType = 'suite',
374
+ hasUnskippableSuites,
375
+ hasForcedToRunSuites
370
376
  }
371
377
  ) {
372
378
  testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false')
@@ -381,6 +387,15 @@ function addIntelligentTestRunnerSpanTags (
381
387
  testModuleSpan.setTag(TEST_ITR_SKIPPING_COUNT, skippingCount)
382
388
  testModuleSpan.setTag(TEST_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
383
389
 
390
+ if (hasUnskippableSuites) {
391
+ testSessionSpan.setTag(TEST_ITR_UNSKIPPABLE, 'true')
392
+ testModuleSpan.setTag(TEST_ITR_UNSKIPPABLE, 'true')
393
+ }
394
+ if (hasForcedToRunSuites) {
395
+ testSessionSpan.setTag(TEST_ITR_FORCED_RUN, 'true')
396
+ testModuleSpan.setTag(TEST_ITR_FORCED_RUN, 'true')
397
+ }
398
+
384
399
  // If suites have been skipped we don't want to report the total coverage, as it will be wrong
385
400
  if (testCodeCoverageLinesTotal !== undefined && !isSuitesSkipped) {
386
401
  testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
@@ -37,6 +37,8 @@ class Config {
37
37
  DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
38
38
  DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
39
39
  DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
40
+ DD_PROFILING_CODEHOTSPOTS_ENABLED,
41
+ DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
40
42
  DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED,
41
43
  DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED
42
44
  } = process.env
@@ -53,8 +55,6 @@ class Config {
53
55
  Number(DD_PROFILING_UPLOAD_TIMEOUT), 60 * 1000)
54
56
  const sourceMap = coalesce(options.sourceMap,
55
57
  DD_PROFILING_SOURCE_MAP, true)
56
- const endpointCollectionEnabled = coalesce(options.endpointCollection,
57
- DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED, false)
58
58
  const pprofPrefix = coalesce(options.pprofPrefix,
59
59
  DD_PROFILING_PPROF_PREFIX, '')
60
60
 
@@ -71,11 +71,25 @@ class Config {
71
71
  tagger.parse({ env, host, service, version, functionname })
72
72
  )
73
73
  this.logger = ensureLogger(options.logger)
74
+ const logger = this.logger
75
+ function logExperimentalVarDeprecation (shortVarName) {
76
+ const deprecatedEnvVarName = `DD_PROFILING_EXPERIMENTAL_${shortVarName}`
77
+ const v = process.env[deprecatedEnvVarName]
78
+ // not null, undefined, or NaN -- same logic as koalas.hasValue
79
+ // eslint-disable-next-line no-self-compare
80
+ if (v != null && v === v) {
81
+ logger.warn(`${deprecatedEnvVarName} is deprecated. Use DD_PROFILING_${shortVarName} instead.`)
82
+ }
83
+ }
74
84
  this.flushInterval = flushInterval
75
85
  this.uploadTimeout = uploadTimeout
76
86
  this.sourceMap = sourceMap
77
87
  this.debugSourceMaps = isTrue(coalesce(options.debugSourceMaps, DD_PROFILING_DEBUG_SOURCE_MAPS, false))
78
- this.endpointCollectionEnabled = endpointCollectionEnabled
88
+ this.endpointCollectionEnabled = isTrue(coalesce(options.endpointCollection,
89
+ DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
90
+ DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED, false))
91
+ logExperimentalVarDeprecation('ENDPOINT_COLLECTION_ENABLED')
92
+
79
93
  this.pprofPrefix = pprofPrefix
80
94
  this.v8ProfilerBugWorkaroundEnabled = isTrue(coalesce(options.v8ProfilerBugWorkaround,
81
95
  DD_PROFILING_V8_PROFILER_BUG_WORKAROUND, true))
@@ -113,8 +127,25 @@ class Config {
113
127
  const profilers = options.profilers
114
128
  ? options.profilers
115
129
  : getProfilers({ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS })
116
- this.codeHotspotsEnabled = isTrue(coalesce(options.codeHotspotsEnabled,
117
- DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, false))
130
+
131
+ function getCodeHotspotsOptionsOr (defvalue) {
132
+ return coalesce(options.codeHotspotsEnabled,
133
+ DD_PROFILING_CODEHOTSPOTS_ENABLED,
134
+ DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, defvalue)
135
+ }
136
+ this.codeHotspotsEnabled = isTrue(getCodeHotspotsOptionsOr(false))
137
+ logExperimentalVarDeprecation('CODEHOTSPOTS_ENABLED')
138
+ if (this.endpointCollectionEnabled && !this.codeHotspotsEnabled) {
139
+ if (getCodeHotspotsOptionsOr(undefined) !== undefined) {
140
+ this.logger.warn(
141
+ 'Endpoint collection is enabled, but Code Hotspots are disabled. ' +
142
+ 'Enable Code Hotspots too for endpoint collection to work.')
143
+ this.endpointCollectionEnabled = false
144
+ } else {
145
+ this.logger.info('Code Hotspots are implicitly enabled by endpoint collection.')
146
+ this.codeHotspotsEnabled = true
147
+ }
148
+ }
118
149
 
119
150
  this.profilers = ensureProfilers(profilers, this)
120
151
  }
@@ -23,7 +23,7 @@ function getStartedSpans (context) {
23
23
  return context._trace.started
24
24
  }
25
25
 
26
- function generateLabels ({ spanId, rootSpanId, webTags, endpoint }) {
26
+ function generateLabels ({ context: { spanId, rootSpanId, webTags, endpoint }, timestamp }) {
27
27
  const labels = {}
28
28
  if (spanId) {
29
29
  labels['span id'] = spanId
@@ -37,6 +37,8 @@ function generateLabels ({ spanId, rootSpanId, webTags, endpoint }) {
37
37
  // fallback to endpoint computed when sample was taken
38
38
  labels['trace endpoint'] = endpoint
39
39
  }
40
+ // Incoming timestamps are in microseconds, we emit nanos.
41
+ labels['end_timestamp_ns'] = timestamp * 1000n
40
42
 
41
43
  return labels
42
44
  }
@@ -100,6 +102,10 @@ class NativeWallProfiler {
100
102
  return this._codeHotspotsEnabled
101
103
  }
102
104
 
105
+ endpointCollectionEnabled () {
106
+ return this._endpointCollectionEnabled
107
+ }
108
+
103
109
  start ({ mapper } = {}) {
104
110
  if (this._started) return
105
111
 
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ const maxExtraServices = 64
4
+ const extraServices = new Set()
5
+
6
+ function getExtraServices () {
7
+ return [...extraServices]
8
+ }
9
+
10
+ function registerExtraService (serviceName) {
11
+ if (serviceName && extraServices.size < maxExtraServices) {
12
+ extraServices.add(serviceName)
13
+ }
14
+ }
15
+
16
+ function clear () {
17
+ extraServices.clear()
18
+ }
19
+
20
+ module.exports = {
21
+ registerExtraService,
22
+ getExtraServices,
23
+ clear
24
+ }
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const { version } = require('../../../../package.json')
4
-
5
3
  const { sendData } = require('./send-data')
6
4
 
7
5
  function getId (type, namespace, name, tags) {
@@ -35,10 +33,7 @@ class Metric {
35
33
  this.metric = common ? metric : `nodejs.${metric}`
36
34
  this.tags = tagArray(tags)
37
35
  if (common) {
38
- this.tags.push('lib_language:nodejs')
39
36
  this.tags.push(`version:${process.version}`)
40
- } else {
41
- this.tags.push(`lib_version:${version}`)
42
37
  }
43
38
  this.common = common
44
39