dd-trace 3.38.1 → 3.40.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 (82) hide show
  1. package/LICENSE-3rdparty.csv +2 -2
  2. package/README.md +3 -3
  3. package/ext/kinds.d.ts +1 -0
  4. package/ext/kinds.js +2 -1
  5. package/ext/tags.d.ts +2 -1
  6. package/ext/tags.js +6 -1
  7. package/index.d.ts +9 -1
  8. package/package.json +8 -8
  9. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  10. package/packages/datadog-esbuild/index.js +1 -20
  11. package/packages/datadog-instrumentations/src/cucumber.js +5 -0
  12. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  13. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  14. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  15. package/packages/datadog-instrumentations/src/jest.js +39 -10
  16. package/packages/datadog-instrumentations/src/knex.js +24 -17
  17. package/packages/datadog-instrumentations/src/mocha.js +16 -1
  18. package/packages/datadog-instrumentations/src/next.js +58 -23
  19. package/packages/datadog-instrumentations/src/playwright.js +11 -6
  20. package/packages/datadog-instrumentations/src/restify.js +14 -1
  21. package/packages/datadog-plugin-http/src/client.js +2 -0
  22. package/packages/datadog-plugin-jest/src/index.js +11 -3
  23. package/packages/datadog-plugin-kafkajs/src/consumer.js +8 -6
  24. package/packages/datadog-plugin-kafkajs/src/producer.js +9 -6
  25. package/packages/datadog-plugin-mocha/src/index.js +7 -1
  26. package/packages/datadog-plugin-next/src/index.js +4 -3
  27. package/packages/datadog-plugin-playwright/src/index.js +4 -1
  28. package/packages/dd-trace/src/appsec/channels.js +1 -1
  29. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  30. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-analyzer.js +60 -0
  31. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +269 -0
  32. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +5 -2
  33. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +22 -4
  34. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +9 -2
  35. package/packages/dd-trace/src/appsec/iast/analyzers/xcontenttype-header-missing-analyzer.js +2 -2
  36. package/packages/dd-trace/src/appsec/iast/iast-log.js +9 -4
  37. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  38. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  39. package/packages/dd-trace/src/appsec/iast/path-line.js +7 -2
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +13 -2
  41. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +1 -14
  42. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +19 -0
  43. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +2 -1
  44. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  45. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +5 -1
  46. package/packages/dd-trace/src/appsec/recommended.json +272 -48
  47. package/packages/dd-trace/src/appsec/reporter.js +31 -34
  48. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +16 -4
  49. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -0
  50. package/packages/dd-trace/src/config.js +35 -17
  51. package/packages/dd-trace/src/datastreams/processor.js +60 -15
  52. package/packages/dd-trace/src/format.js +6 -1
  53. package/packages/dd-trace/src/git_properties.js +16 -15
  54. package/packages/dd-trace/src/iitm.js +1 -1
  55. package/packages/dd-trace/src/log/channels.js +1 -1
  56. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  57. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  58. package/packages/dd-trace/src/opentracing/span.js +4 -0
  59. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  60. package/packages/dd-trace/src/plugin_manager.js +1 -1
  61. package/packages/dd-trace/src/plugins/database.js +1 -1
  62. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  63. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  64. package/packages/dd-trace/src/plugins/util/git.js +2 -1
  65. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  66. package/packages/dd-trace/src/plugins/util/test.js +29 -1
  67. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  68. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -14
  69. package/packages/dd-trace/src/profiling/config.js +23 -20
  70. package/packages/dd-trace/src/profiling/profilers/events.js +161 -0
  71. package/packages/dd-trace/src/profiling/profilers/shared.js +9 -0
  72. package/packages/dd-trace/src/profiling/profilers/wall.js +84 -47
  73. package/packages/dd-trace/src/ritm.js +1 -1
  74. package/packages/dd-trace/src/span_processor.js +4 -0
  75. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  76. package/packages/dd-trace/src/telemetry/index.js +5 -1
  77. package/packages/dd-trace/src/telemetry/logs/index.js +65 -0
  78. package/packages/dd-trace/src/{appsec/iast/telemetry/log → telemetry/logs}/log-collector.js +9 -22
  79. package/packages/dd-trace/src/tracer.js +4 -2
  80. package/packages/dd-trace/src/appsec/iast/telemetry/log/index.js +0 -87
  81. package/packages/diagnostics_channel/index.js +0 -3
  82. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -7,6 +7,7 @@ const { getNodeModulesPaths } = require('../path-line')
7
7
  const { getNextSecureMark } = require('../taint-tracking/secure-marks-generator')
8
8
  const { storage } = require('../../../../../datadog-core')
9
9
  const { getIastContext } = require('../iast-context')
10
+ const { HTTP_REQUEST_PARAMETER, HTTP_REQUEST_BODY } = require('../taint-tracking/source-types')
10
11
 
11
12
  const EXCLUDED_PATHS_FROM_STACK = getNodeModulesPaths('mongodb', 'mongoose')
12
13
  const MONGODB_NOSQL_SECURE_MARK = getNextSecureMark()
@@ -113,6 +114,12 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
113
114
  })
114
115
  }
115
116
 
117
+ _isVulnerableRange (range) {
118
+ const rangeType = range?.iinfo?.type
119
+ const isVulnerableType = rangeType === HTTP_REQUEST_PARAMETER || rangeType === HTTP_REQUEST_BODY
120
+ return isVulnerableType && (range.secureMarks & MONGODB_NOSQL_SECURE_MARK) !== MONGODB_NOSQL_SECURE_MARK
121
+ }
122
+
116
123
  _isVulnerable (value, iastContext) {
117
124
  if (value?.filter && iastContext) {
118
125
  let isVulnerable = false
@@ -124,13 +131,13 @@ class NosqlInjectionMongodbAnalyzer extends InjectionAnalyzer {
124
131
  const rangesByKey = {}
125
132
  const allRanges = []
126
133
 
127
- iterateObjectStrings(value.filter, function (val, nextLevelKeys) {
134
+ iterateObjectStrings(value.filter, (val, nextLevelKeys) => {
128
135
  const ranges = getRanges(iastContext, val)
129
136
  if (ranges?.length) {
130
137
  const filteredRanges = []
131
138
 
132
139
  for (const range of ranges) {
133
- if ((range.secureMarks & MONGODB_NOSQL_SECURE_MARK) !== MONGODB_NOSQL_SECURE_MARK) {
140
+ if (this._isVulnerableRange(range)) {
134
141
  isVulnerable = true
135
142
  filteredRanges.push(range)
136
143
  }
@@ -11,8 +11,8 @@ class XcontenttypeHeaderMissingAnalyzer extends MissingHeaderAnalyzer {
11
11
  }
12
12
 
13
13
  _isVulnerableFromRequestAndResponse (req, res) {
14
- const headerToCheck = res.getHeader(XCONTENTTYPEOPTIONS_HEADER_NAME)
15
- return !headerToCheck || headerToCheck.trim().toLowerCase() !== 'nosniff'
14
+ const headerValues = this._getHeaderValues(res, XCONTENTTYPEOPTIONS_HEADER_NAME)
15
+ return headerValues.length === 0 || headerValues.some(headerValue => headerValue.trim().toLowerCase() !== 'nosniff')
16
16
  }
17
17
  }
18
18
 
@@ -1,9 +1,11 @@
1
1
  'use strict'
2
2
 
3
+ const dc = require('dc-polyfill')
3
4
  const log = require('../../log')
4
- const telemetryLogs = require('./telemetry/log')
5
5
  const { calculateDDBasePath } = require('../../util')
6
6
 
7
+ const telemetryLog = dc.channel('datadog:telemetry:log')
8
+
7
9
  const ddBasePath = calculateDDBasePath(__dirname)
8
10
  const EOL = '\n'
9
11
  const STACK_FRAME_LINE_REGEX = /^\s*at\s/gm
@@ -80,9 +82,8 @@ const iastLog = {
80
82
  },
81
83
 
82
84
  publish (data, level) {
83
- if (telemetryLogs.isLevelEnabled(level)) {
84
- const telemetryLog = getTelemetryLog(data, level)
85
- telemetryLogs.publish(telemetryLog)
85
+ if (telemetryLog.hasSubscribers) {
86
+ telemetryLog.publish(getTelemetryLog(data, level))
86
87
  }
87
88
  return this
88
89
  },
@@ -92,6 +93,10 @@ const iastLog = {
92
93
  return this.publish(data, 'DEBUG')
93
94
  },
94
95
 
96
+ /**
97
+ * forward 'INFO' log level to 'DEBUG' telemetry log level
98
+ * see also {@link ../../telemetry/logs#isLevelEnabled } method
99
+ */
95
100
  infoAndPublish (data) {
96
101
  this.info(data)
97
102
  return this.publish(data, 'DEBUG')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
 
5
5
  const iastLog = require('./iast-log')
6
6
  const Plugin = require('../../plugins/plugin')
@@ -3,7 +3,7 @@ const { enableAllAnalyzers, disableAllAnalyzers } = require('./analyzers')
3
3
  const web = require('../../plugins/util/web')
4
4
  const { storage } = require('../../../../datadog-core')
5
5
  const overheadController = require('./overhead-controller')
6
- const dc = require('../../../../diagnostics_channel')
6
+ const dc = require('dc-polyfill')
7
7
  const iastContextFunctions = require('./iast-context')
8
8
  const {
9
9
  enableTaintTracking,
@@ -6,13 +6,14 @@ const { calculateDDBasePath } = require('../../util')
6
6
  const pathLine = {
7
7
  getFirstNonDDPathAndLine,
8
8
  getNodeModulesPaths,
9
+ getRelativePath,
9
10
  getFirstNonDDPathAndLineFromCallsites, // Exported only for test purposes
10
11
  calculateDDBasePath, // Exported only for test purposes
11
12
  ddBasePath: calculateDDBasePath(__dirname) // Only for test purposes
12
13
  }
13
14
 
14
15
  const EXCLUDED_PATHS = [
15
- path.join(path.sep, 'node_modules', 'diagnostics_channel')
16
+ path.join(path.sep, 'node_modules', 'dc-polyfill')
16
17
  ]
17
18
  const EXCLUDED_PATH_PREFIXES = [
18
19
  'node:diagnostics_channel',
@@ -45,7 +46,7 @@ function getFirstNonDDPathAndLineFromCallsites (callsites, externallyExcludedPat
45
46
  const filepath = callsite.getFileName()
46
47
  if (!isExcluded(callsite, externallyExcludedPaths) && filepath.indexOf(pathLine.ddBasePath) === -1) {
47
48
  return {
48
- path: path.relative(process.cwd(), filepath),
49
+ path: getRelativePath(filepath),
49
50
  line: callsite.getLineNumber(),
50
51
  column: callsite.getColumnNumber(),
51
52
  isInternal: !path.isAbsolute(filepath)
@@ -56,6 +57,10 @@ function getFirstNonDDPathAndLineFromCallsites (callsites, externallyExcludedPat
56
57
  return null
57
58
  }
58
59
 
60
+ function getRelativePath (filepath) {
61
+ return path.relative(process.cwd(), filepath)
62
+ }
63
+
59
64
  function isExcluded (callsite, externallyExcludedPaths) {
60
65
  if (callsite.isNative()) return true
61
66
  const filename = callsite.getFileName()
@@ -7,7 +7,9 @@ const { isPrivateModule, isNotLibraryFile } = require('./filter')
7
7
  const { csiMethods } = require('./csi-methods')
8
8
  const { getName } = require('../telemetry/verbosity')
9
9
  const { getRewriteFunction } = require('./rewriter-telemetry')
10
+ const dc = require('dc-polyfill')
10
11
 
12
+ const hardcodedSecretCh = dc.channel('datadog:secrets:result')
11
13
  let rewriter
12
14
  let getPrepareStackTrace
13
15
 
@@ -50,7 +52,11 @@ function getRewriter (telemetryVerbosity) {
50
52
  getGetOriginalPathAndLineFromSourceMapFunction(chainSourceMap, getOriginalPathAndLineFromSourceMap)
51
53
  }
52
54
 
53
- rewriter = new Rewriter({ csiMethods, telemetryVerbosity: getName(telemetryVerbosity), chainSourceMap })
55
+ rewriter = new Rewriter({
56
+ csiMethods,
57
+ telemetryVerbosity: getName(telemetryVerbosity),
58
+ chainSourceMap
59
+ })
54
60
  } catch (e) {
55
61
  iastLog.error('Unable to initialize TaintTracking Rewriter')
56
62
  .errorAndPublish(e)
@@ -80,7 +86,12 @@ function getCompileMethodFn (compileMethod) {
80
86
  try {
81
87
  if (isPrivateModule(filename) && isNotLibraryFile(filename)) {
82
88
  const rewritten = rewriteFn(content, filename)
83
- if (rewritten && rewritten.content) {
89
+
90
+ if (rewritten?.literalsResult && hardcodedSecretCh.hasSubscribers) {
91
+ hardcodedSecretCh.publish(rewritten.literalsResult)
92
+ }
93
+
94
+ if (rewritten?.content) {
84
95
  return compileMethod.apply(this, [rewritten.content, filename])
85
96
  }
86
97
  }
@@ -1,21 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const telemetryMetrics = require('../../../telemetry/metrics')
4
- const telemetryLogs = require('./log')
5
4
  const { Verbosity, getVerbosity } = require('./verbosity')
6
5
  const { initRequestNamespace, finalizeRequestNamespace, globalNamespace } = require('./namespaces')
7
6
 
8
- function isIastMetricsEnabled (metrics) {
9
- // TODO: let DD_TELEMETRY_METRICS_ENABLED as undefined in config.js to avoid read here the env property
10
- return process.env.DD_TELEMETRY_METRICS_ENABLED !== undefined ? metrics : true
11
- }
12
-
13
7
  class Telemetry {
14
8
  configure (config, verbosity) {
15
- const telemetryAndMetricsEnabled = config &&
16
- config.telemetry &&
17
- config.telemetry.enabled &&
18
- isIastMetricsEnabled(config.telemetry.metrics)
9
+ const telemetryAndMetricsEnabled = config?.telemetry?.enabled && config.telemetry.metrics
19
10
 
20
11
  this.verbosity = telemetryAndMetricsEnabled ? getVerbosity(verbosity) : Verbosity.OFF
21
12
  this.enabled = this.verbosity !== Verbosity.OFF
@@ -23,15 +14,11 @@ class Telemetry {
23
14
  if (this.enabled) {
24
15
  telemetryMetrics.manager.set('iast', globalNamespace)
25
16
  }
26
-
27
- telemetryLogs.start()
28
17
  }
29
18
 
30
19
  stop () {
31
20
  this.enabled = false
32
21
  telemetryMetrics.manager.delete('iast')
33
-
34
- telemetryLogs.stop()
35
22
  }
36
23
 
37
24
  isEnabled () {
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const iastLog = require('../../iast-log')
3
4
  const vulnerabilities = require('../../vulnerabilities')
4
5
 
5
6
  const { contains, intersects, remove } = require('./range-utils')
@@ -263,6 +264,24 @@ class SensitiveHandler {
263
264
  valueParts.push({ redacted: true })
264
265
  }
265
266
  }
267
+
268
+ setRedactionPatterns (redactionNamePattern, redactionValuePattern) {
269
+ if (redactionNamePattern) {
270
+ try {
271
+ this._namePattern = new RegExp(redactionNamePattern, 'gmi')
272
+ } catch (e) {
273
+ iastLog.warn('Redaction name pattern is not valid')
274
+ }
275
+ }
276
+
277
+ if (redactionValuePattern) {
278
+ try {
279
+ this._valuePattern = new RegExp(redactionValuePattern, 'gmi')
280
+ } catch (e) {
281
+ iastLog.warn('Redaction value pattern is not valid')
282
+ }
283
+ }
284
+ }
266
285
  }
267
286
 
268
287
  module.exports = new SensitiveHandler()
@@ -8,8 +8,9 @@ class VulnerabilityFormatter {
8
8
  this._redactVulnearbilities = true
9
9
  }
10
10
 
11
- setRedactVulnerabilities (shouldRedactVulnerabilities) {
11
+ setRedactVulnerabilities (shouldRedactVulnerabilities, redactionNamePattern, redactionValuePattern) {
12
12
  this._redactVulnearbilities = shouldRedactVulnerabilities
13
+ sensitiveHandler.setRedactionPatterns(redactionNamePattern, redactionValuePattern)
13
14
  }
14
15
 
15
16
  extractSourcesFromVulnerability (vulnerability) {
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
2
  COMMAND_INJECTION: 'COMMAND_INJECTION',
3
+ HARDCODED_SECRET: 'HARDCODED_SECRET',
3
4
  HSTS_HEADER_MISSING: 'HSTS_HEADER_MISSING',
4
5
  INSECURE_COOKIE: 'INSECURE_COOKIE',
5
6
  LDAP_INJECTION: 'LDAP_INJECTION',
@@ -95,7 +95,11 @@ function deduplicateVulnerabilities (vulnerabilities) {
95
95
 
96
96
  function start (config, _tracer) {
97
97
  deduplicationEnabled = config.iast.deduplicationEnabled
98
- vulnerabilitiesFormatter.setRedactVulnerabilities(config.iast.redactionEnabled)
98
+ vulnerabilitiesFormatter.setRedactVulnerabilities(
99
+ config.iast.redactionEnabled,
100
+ config.iast.redactionNamePattern,
101
+ config.iast.redactionValuePattern
102
+ )
99
103
  if (deduplicationEnabled) {
100
104
  startClearCacheTimer()
101
105
  }