dd-trace 4.2.0 → 4.3.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 (49) hide show
  1. package/index.d.ts +7 -0
  2. package/package.json +5 -5
  3. package/packages/datadog-instrumentations/src/cookie.js +21 -0
  4. package/packages/datadog-instrumentations/src/fetch.js +48 -0
  5. package/packages/datadog-instrumentations/src/grpc/server.js +1 -1
  6. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  7. package/packages/datadog-instrumentations/src/helpers/register.js +10 -0
  8. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +18 -0
  9. package/packages/datadog-plugin-fetch/src/index.js +36 -0
  10. package/packages/datadog-plugin-http/src/client.js +24 -8
  11. package/packages/datadog-plugin-mysql/src/index.js +2 -11
  12. package/packages/datadog-plugin-tedious/src/index.js +2 -2
  13. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -0
  14. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +52 -0
  15. package/packages/dd-trace/src/appsec/iast/analyzers/insecure-cookie-analyzer.js +3 -22
  16. package/packages/dd-trace/src/appsec/iast/analyzers/no-httponly-cookie-analyzer.js +12 -0
  17. package/packages/dd-trace/src/appsec/iast/analyzers/no-samesite-cookie-analyzer.js +12 -0
  18. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +7 -3
  19. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +3 -3
  20. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +48 -0
  21. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +3 -3
  22. package/packages/dd-trace/src/appsec/iast/index.js +9 -2
  23. package/packages/dd-trace/src/appsec/iast/path-line.js +13 -0
  24. package/packages/dd-trace/src/appsec/iast/tags.js +6 -0
  25. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +2 -1
  26. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +13 -4
  27. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +5 -1
  28. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +24 -4
  29. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -1
  30. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +3 -0
  31. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -1
  32. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -3
  33. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -2
  34. package/packages/dd-trace/src/config.js +13 -0
  35. package/packages/dd-trace/src/external-logger/src/index.js +126 -0
  36. package/packages/dd-trace/src/external-logger/test/index.spec.js +147 -0
  37. package/packages/dd-trace/src/lambda/handler.js +3 -15
  38. package/packages/dd-trace/src/noop/proxy.js +4 -0
  39. package/packages/dd-trace/src/opentelemetry/context_manager.js +1 -1
  40. package/packages/dd-trace/src/plugin_manager.js +10 -7
  41. package/packages/dd-trace/src/plugins/database.js +7 -3
  42. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  43. package/packages/dd-trace/src/plugins/util/exec.js +2 -2
  44. package/packages/dd-trace/src/plugins/util/git.js +51 -24
  45. package/packages/dd-trace/src/profiling/config.js +2 -0
  46. package/packages/dd-trace/src/profiling/profiler.js +13 -4
  47. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +24 -1
  48. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +18 -1
  49. package/packages/dd-trace/src/util.js +1 -1
@@ -1,6 +1,7 @@
1
- const { execSync } = require('child_process')
1
+ const { execFileSync } = require('child_process')
2
2
  const os = require('os')
3
3
  const path = require('path')
4
+ const fs = require('fs')
4
5
 
5
6
  const log = require('../../log')
6
7
  const { sanitizedExec } = require('./exec')
@@ -21,26 +22,35 @@ const {
21
22
 
22
23
  const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB
23
24
 
25
+ function isDirectory (path) {
26
+ try {
27
+ const stats = fs.statSync(path)
28
+ return stats.isDirectory()
29
+ } catch (e) {
30
+ return false
31
+ }
32
+ }
33
+
24
34
  function isShallowRepository () {
25
- return sanitizedExec('git rev-parse --is-shallow-repository', { stdio: 'pipe' }) === 'true'
35
+ return sanitizedExec('git', ['rev-parse', '--is-shallow-repository']) === 'true'
26
36
  }
27
37
 
28
38
  function unshallowRepository () {
29
39
  try {
30
- execSync('git config remote.origin.partialclonefilter "blob:none"', { stdio: 'pipe' })
31
- execSync('git fetch --shallow-since="1 month ago" --update-shallow --refetch', { stdio: 'pipe' })
40
+ sanitizedExec('git', ['config', 'remote.origin.partialclonefilter', '"blob:none"'])
41
+ sanitizedExec('git', ['fetch', '--shallow-since="1 month ago"', '--update-shallow', '--refetch'])
32
42
  } catch (err) {
33
43
  log.error(err)
34
44
  }
35
45
  }
36
46
 
37
47
  function getRepositoryUrl () {
38
- return sanitizedExec('git config --get remote.origin.url', { stdio: 'pipe' })
48
+ return sanitizedExec('git', ['config', '--get', 'remote.origin.url'])
39
49
  }
40
50
 
41
51
  function getLatestCommits () {
42
52
  try {
43
- return execSync('git log --format=%H -n 1000 --since="1 month ago"', { stdio: 'pipe' })
53
+ return execFileSync('git', ['log', '--format=%H', '-n 1000', '--since="1 month ago"'], { stdio: 'pipe' })
44
54
  .toString()
45
55
  .split('\n')
46
56
  .filter(commit => commit)
@@ -51,15 +61,21 @@ function getLatestCommits () {
51
61
  }
52
62
 
53
63
  function getCommitsToUpload (commitsToExclude) {
54
- let gitCommandToGetCommitsToUpload =
55
- 'git rev-list --objects --no-object-names --filter=blob:none --since="1 month ago" HEAD'
56
-
57
- commitsToExclude.forEach(commit => {
58
- gitCommandToGetCommitsToUpload = `${gitCommandToGetCommitsToUpload} ^${commit}`
59
- })
64
+ const commitsToExcludeString = commitsToExclude.map(commit => `^${commit}`)
60
65
 
61
66
  try {
62
- return execSync(gitCommandToGetCommitsToUpload, { stdio: 'pipe', maxBuffer: GIT_REV_LIST_MAX_BUFFER })
67
+ return execFileSync(
68
+ 'git',
69
+ [
70
+ 'rev-list',
71
+ '--objects',
72
+ '--no-object-names',
73
+ '--filter=blob:none',
74
+ '--since="1 month ago"',
75
+ 'HEAD',
76
+ ...commitsToExcludeString
77
+ ],
78
+ { stdio: 'pipe', maxBuffer: GIT_REV_LIST_MAX_BUFFER })
63
79
  .toString()
64
80
  .split('\n')
65
81
  .filter(commit => commit)
@@ -72,6 +88,11 @@ function getCommitsToUpload (commitsToExclude) {
72
88
  function generatePackFilesForCommits (commitsToUpload) {
73
89
  const tmpFolder = os.tmpdir()
74
90
 
91
+ if (!isDirectory(tmpFolder)) {
92
+ log.error(new Error('Provided path to generate packfiles is not a directory'))
93
+ return []
94
+ }
95
+
75
96
  const randomPrefix = String(Math.floor(Math.random() * 10000))
76
97
  const temporaryPath = path.join(tmpFolder, randomPrefix)
77
98
  const cwdPath = path.join(process.cwd(), randomPrefix)
@@ -79,14 +100,20 @@ function generatePackFilesForCommits (commitsToUpload) {
79
100
  // Generates pack files to upload and
80
101
  // returns the ordered list of packfiles' paths
81
102
  function execGitPackObjects (targetPath) {
82
- return execSync(
83
- `git pack-objects --compression=9 --max-pack-size=3m ${targetPath}`,
84
- { input: commitsToUpload.join('\n') }
103
+ return execFileSync(
104
+ 'git',
105
+ [
106
+ 'pack-objects',
107
+ '--compression=9',
108
+ '--max-pack-size=3m',
109
+ targetPath
110
+ ],
111
+ { stdio: 'pipe', input: commitsToUpload.join('\n') }
85
112
  ).toString().split('\n').filter(commit => commit).map(commit => `${targetPath}-${commit}.pack`)
86
113
  }
87
114
 
88
115
  try {
89
- return execGitPackObjects(temporaryPath, commitsToUpload)
116
+ return execGitPackObjects(temporaryPath)
90
117
  } catch (err) {
91
118
  log.error(err)
92
119
  /**
@@ -102,7 +129,7 @@ function generatePackFilesForCommits (commitsToUpload) {
102
129
  * TODO: fix issue and remove workaround.
103
130
  */
104
131
  try {
105
- return execGitPackObjects(cwdPath, commitsToUpload)
132
+ return execGitPackObjects(cwdPath)
106
133
  } catch (err) {
107
134
  log.error(err)
108
135
  }
@@ -133,23 +160,23 @@ function getGitMetadata (ciMetadata) {
133
160
  committerName,
134
161
  committerEmail,
135
162
  committerDate
136
- ] = sanitizedExec('git show -s --format=%an,%ae,%aI,%cn,%ce,%cI', { stdio: 'pipe' }).split(',')
163
+ ] = sanitizedExec('git', ['show', '-s', '--format=%an,%ae,%aI,%cn,%ce,%cI']).split(',')
137
164
 
138
165
  return {
139
166
  [GIT_REPOSITORY_URL]:
140
- repositoryUrl || sanitizedExec('git ls-remote --get-url', { stdio: 'pipe' }),
167
+ repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url']),
141
168
  [GIT_COMMIT_MESSAGE]:
142
- commitMessage || sanitizedExec('git show -s --format=%s', { stdio: 'pipe' }),
169
+ commitMessage || sanitizedExec('git', ['show', '-s', '--format=%s']),
143
170
  [GIT_COMMIT_AUTHOR_DATE]: authorDate,
144
171
  [GIT_COMMIT_AUTHOR_NAME]: ciAuthorName || authorName,
145
172
  [GIT_COMMIT_AUTHOR_EMAIL]: ciAuthorEmail || authorEmail,
146
173
  [GIT_COMMIT_COMMITTER_DATE]: committerDate,
147
174
  [GIT_COMMIT_COMMITTER_NAME]: committerName,
148
175
  [GIT_COMMIT_COMMITTER_EMAIL]: committerEmail,
149
- [GIT_BRANCH]: branch || sanitizedExec('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' }),
150
- [GIT_COMMIT_SHA]: commitSHA || sanitizedExec('git rev-parse HEAD', { stdio: 'pipe' }),
176
+ [GIT_BRANCH]: branch || sanitizedExec('git', ['rev-parse', '--abbrev-ref', 'HEAD']),
177
+ [GIT_COMMIT_SHA]: commitSHA || sanitizedExec('git', ['rev-parse', 'HEAD']),
151
178
  [GIT_TAG]: tag,
152
- [CI_WORKSPACE_PATH]: ciWorkspacePath || sanitizedExec('git rev-parse --show-toplevel', { stdio: 'pipe' })
179
+ [CI_WORKSPACE_PATH]: ciWorkspacePath || sanitizedExec('git', ['rev-parse', '--show-toplevel'])
153
180
  }
154
181
  }
155
182
 
@@ -27,6 +27,7 @@ class Config {
27
27
  DD_TRACE_AGENT_URL,
28
28
  DD_AGENT_HOST,
29
29
  DD_TRACE_AGENT_PORT,
30
+ DD_PROFILING_DEBUG_SOURCE_MAPS,
30
31
  DD_PROFILING_UPLOAD_TIMEOUT,
31
32
  DD_PROFILING_SOURCE_MAP,
32
33
  DD_PROFILING_UPLOAD_PERIOD,
@@ -70,6 +71,7 @@ class Config {
70
71
  this.flushInterval = flushInterval
71
72
  this.uploadTimeout = uploadTimeout
72
73
  this.sourceMap = sourceMap
74
+ this.debugSourceMaps = isTrue(coalesce(options.debugSourceMaps, DD_PROFILING_DEBUG_SOURCE_MAPS, false))
73
75
  this.endpointCollection = endpointCollection
74
76
  this.pprofPrefix = pprofPrefix
75
77
 
@@ -4,12 +4,11 @@ const { EventEmitter } = require('events')
4
4
  const { Config } = require('./config')
5
5
  const { snapshotKinds } = require('./constants')
6
6
 
7
- function maybeSourceMap (sourceMap) {
7
+ function maybeSourceMap (sourceMap, SourceMapper, debug) {
8
8
  if (!sourceMap) return
9
- const { SourceMapper } = require('@datadog/pprof')
10
9
  return SourceMapper.create([
11
10
  process.cwd()
12
- ])
11
+ ], debug)
13
12
  }
14
13
 
15
14
  class Profiler extends EventEmitter {
@@ -42,7 +41,17 @@ class Profiler extends EventEmitter {
42
41
  // of the profiler from running without source maps.
43
42
  let mapper
44
43
  try {
45
- mapper = await maybeSourceMap(config.sourceMap)
44
+ const { setLogger, SourceMapper } = require('@datadog/pprof')
45
+ setLogger(config.logger)
46
+
47
+ mapper = await maybeSourceMap(config.sourceMap, SourceMapper, config.debugSourceMaps)
48
+ if (config.SourceMap && config.debugSourceMaps) {
49
+ this._logger.debug(() => {
50
+ return mapper.infoMap.size === 0
51
+ ? 'Found no source maps'
52
+ : `Found source maps for following files: [${Array.from(mapper.infoMap.keys()).join(', ')}]`
53
+ })
54
+ }
46
55
  } catch (err) {
47
56
  this._logger.error(err)
48
57
  }
@@ -12,6 +12,13 @@ function fromSystem (service, system) {
12
12
  return system ? `${service}-${system}` : undefined
13
13
  }
14
14
 
15
+ function mysqlServiceName (service, config, dbConfig, system) {
16
+ if (typeof config.service === 'function') {
17
+ return config.service(dbConfig)
18
+ }
19
+ return config.service ? config.service : fromSystem(service, system)
20
+ }
21
+
15
22
  const redisConfig = {
16
23
  opName: () => 'redis.command',
17
24
  serviceName: (service, config, system, connectionName) => {
@@ -22,11 +29,27 @@ const redisConfig = {
22
29
  const storage = {
23
30
  client: {
24
31
  ioredis: redisConfig,
32
+ mariadb: {
33
+ opName: () => 'mariadb.query',
34
+ serviceName: mysqlServiceName
35
+ },
25
36
  memcached: {
26
37
  opName: () => 'memcached.command',
27
38
  serviceName: (service, config, system) => config.service || fromSystem(service, system)
28
39
  },
29
- redis: redisConfig
40
+ mysql: {
41
+ opName: () => 'mysql.query',
42
+ serviceName: mysqlServiceName
43
+ },
44
+ mysql2: {
45
+ opName: () => 'mysql.query',
46
+ serviceName: mysqlServiceName
47
+ },
48
+ redis: redisConfig,
49
+ tedious: {
50
+ opName: () => 'tedious.request',
51
+ serviceName: (service, config, system) => config.service || fromSystem(service, system)
52
+ }
30
53
  }
31
54
  }
32
55
 
@@ -1,3 +1,5 @@
1
+ const { identityService } = require('../util')
2
+
1
3
  function configWithFallback (service, config) {
2
4
  return config.service || service
3
5
  }
@@ -7,14 +9,29 @@ const redisNaming = {
7
9
  serviceName: configWithFallback
8
10
  }
9
11
 
12
+ const mySQLNaming = {
13
+ opName: () => 'mysql.query',
14
+ serviceName: identityService
15
+ }
16
+
10
17
  const storage = {
11
18
  client: {
12
19
  ioredis: redisNaming,
20
+ mariadb: {
21
+ opName: () => 'mariadb.query',
22
+ serviceName: identityService
23
+ },
13
24
  memcached: {
14
25
  opName: () => 'memcached.command',
15
26
  serviceName: configWithFallback
16
27
  },
17
- redis: redisNaming
28
+ mysql: mySQLNaming,
29
+ mysql2: mySQLNaming,
30
+ redis: redisNaming,
31
+ tedious: {
32
+ opName: () => 'mssql.query',
33
+ serviceName: configWithFallback
34
+ }
18
35
  }
19
36
  }
20
37
 
@@ -16,7 +16,7 @@ function isError (value) {
16
16
  if (value instanceof Error) {
17
17
  return true
18
18
  }
19
- if (value && value.message && value.stack) {
19
+ if (value && value.message) {
20
20
  return true
21
21
  }
22
22
  return false