dd-trace 3.3.1 → 3.12.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 (198) hide show
  1. package/LICENSE-3rdparty.csv +8 -0
  2. package/README.md +108 -43
  3. package/ci/init.js +6 -1
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +129 -36
  7. package/package.json +18 -9
  8. package/packages/datadog-instrumentations/src/body-parser.js +26 -0
  9. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  10. package/packages/datadog-instrumentations/src/child-process.js +30 -0
  11. package/packages/datadog-instrumentations/src/connect.js +15 -15
  12. package/packages/datadog-instrumentations/src/cucumber.js +1 -3
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +51 -47
  14. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +9 -0
  16. package/packages/datadog-instrumentations/src/helpers/register.js +5 -0
  17. package/packages/datadog-instrumentations/src/http/server.js +20 -12
  18. package/packages/datadog-instrumentations/src/http2/server.js +67 -1
  19. package/packages/datadog-instrumentations/src/jest.js +182 -25
  20. package/packages/datadog-instrumentations/src/koa.js +32 -32
  21. package/packages/datadog-instrumentations/src/ldapjs.js +91 -0
  22. package/packages/datadog-instrumentations/src/mariadb.js +63 -0
  23. package/packages/datadog-instrumentations/src/memcached.js +1 -4
  24. package/packages/datadog-instrumentations/src/mocha.js +135 -24
  25. package/packages/datadog-instrumentations/src/next.js +10 -2
  26. package/packages/datadog-instrumentations/src/opensearch.js +10 -0
  27. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  28. package/packages/datadog-instrumentations/src/pg.js +7 -3
  29. package/packages/datadog-instrumentations/src/qs.js +24 -0
  30. package/packages/datadog-instrumentations/src/redis.js +12 -3
  31. package/packages/datadog-instrumentations/src/restify.js +5 -1
  32. package/packages/datadog-instrumentations/src/rhea.js +29 -15
  33. package/packages/datadog-instrumentations/src/router.js +23 -23
  34. package/packages/datadog-plugin-amqp10/src/consumer.js +32 -0
  35. package/packages/datadog-plugin-amqp10/src/index.js +11 -101
  36. package/packages/datadog-plugin-amqp10/src/producer.js +34 -0
  37. package/packages/datadog-plugin-amqp10/src/util.js +15 -0
  38. package/packages/datadog-plugin-amqplib/src/client.js +38 -0
  39. package/packages/datadog-plugin-amqplib/src/consumer.js +40 -0
  40. package/packages/datadog-plugin-amqplib/src/index.js +14 -102
  41. package/packages/datadog-plugin-amqplib/src/producer.js +37 -0
  42. package/packages/datadog-plugin-amqplib/src/util.js +14 -0
  43. package/packages/datadog-plugin-cassandra-driver/src/index.js +22 -60
  44. package/packages/datadog-plugin-cucumber/src/index.js +14 -33
  45. package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
  46. package/packages/datadog-plugin-dns/src/index.js +16 -91
  47. package/packages/datadog-plugin-dns/src/lookup.js +40 -0
  48. package/packages/datadog-plugin-dns/src/lookup_service.js +24 -0
  49. package/packages/datadog-plugin-dns/src/resolve.js +24 -0
  50. package/packages/datadog-plugin-dns/src/reverse.js +21 -0
  51. package/packages/datadog-plugin-elasticsearch/src/index.js +24 -60
  52. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +24 -0
  53. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +41 -0
  54. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +14 -99
  55. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +33 -0
  56. package/packages/datadog-plugin-graphql/src/execute.js +73 -0
  57. package/packages/datadog-plugin-graphql/src/index.js +14 -176
  58. package/packages/datadog-plugin-graphql/src/parse.js +32 -0
  59. package/packages/datadog-plugin-graphql/src/resolve.js +70 -76
  60. package/packages/datadog-plugin-graphql/src/validate.js +28 -0
  61. package/packages/datadog-plugin-grpc/src/client.js +46 -55
  62. package/packages/datadog-plugin-grpc/src/index.js +7 -24
  63. package/packages/datadog-plugin-grpc/src/server.js +50 -52
  64. package/packages/datadog-plugin-grpc/src/util.js +15 -14
  65. package/packages/datadog-plugin-http/src/client.js +15 -5
  66. package/packages/datadog-plugin-http/src/index.js +7 -22
  67. package/packages/datadog-plugin-http/src/server.js +19 -3
  68. package/packages/datadog-plugin-http2/src/client.js +20 -1
  69. package/packages/datadog-plugin-http2/src/index.js +8 -26
  70. package/packages/datadog-plugin-http2/src/server.js +44 -0
  71. package/packages/datadog-plugin-jest/src/index.js +41 -65
  72. package/packages/datadog-plugin-kafkajs/src/consumer.js +42 -0
  73. package/packages/datadog-plugin-kafkajs/src/index.js +11 -87
  74. package/packages/datadog-plugin-kafkajs/src/producer.js +31 -0
  75. package/packages/datadog-plugin-mariadb/src/index.js +10 -0
  76. package/packages/datadog-plugin-memcached/src/index.js +17 -52
  77. package/packages/datadog-plugin-mocha/src/index.js +40 -60
  78. package/packages/datadog-plugin-moleculer/src/client.js +22 -36
  79. package/packages/datadog-plugin-moleculer/src/index.js +8 -26
  80. package/packages/datadog-plugin-moleculer/src/server.js +18 -30
  81. package/packages/datadog-plugin-mongodb-core/src/index.js +23 -51
  82. package/packages/datadog-plugin-mysql/src/index.js +23 -52
  83. package/packages/datadog-plugin-mysql2/src/index.js +1 -3
  84. package/packages/datadog-plugin-net/src/index.js +4 -0
  85. package/packages/datadog-plugin-net/src/ipc.js +21 -0
  86. package/packages/datadog-plugin-net/src/tcp.js +46 -0
  87. package/packages/datadog-plugin-next/src/index.js +3 -0
  88. package/packages/datadog-plugin-opensearch/src/index.js +11 -0
  89. package/packages/datadog-plugin-oracledb/src/index.js +29 -55
  90. package/packages/datadog-plugin-pg/src/index.js +27 -51
  91. package/packages/datadog-plugin-redis/src/index.js +29 -60
  92. package/packages/datadog-plugin-rhea/src/consumer.js +55 -0
  93. package/packages/datadog-plugin-rhea/src/index.js +11 -96
  94. package/packages/datadog-plugin-rhea/src/producer.js +45 -0
  95. package/packages/datadog-plugin-router/src/index.js +13 -2
  96. package/packages/datadog-plugin-sharedb/src/index.js +22 -39
  97. package/packages/datadog-plugin-tedious/src/index.js +20 -41
  98. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  99. package/packages/dd-trace/src/appsec/blocking.js +44 -0
  100. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +8 -6
  101. package/packages/dd-trace/src/appsec/gateway/engine/engine.js +1 -1
  102. package/packages/dd-trace/src/appsec/gateway/engine/index.js +7 -2
  103. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -1
  104. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +4 -1
  105. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
  106. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
  107. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +11 -0
  108. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
  109. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +43 -5
  110. package/packages/dd-trace/src/appsec/iast/iast-context.js +3 -1
  111. package/packages/dd-trace/src/appsec/iast/index.js +24 -8
  112. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
  113. package/packages/dd-trace/src/appsec/iast/path-line.js +17 -6
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +17 -0
  115. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
  116. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
  117. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +98 -0
  118. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
  119. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
  120. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +67 -0
  121. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +103 -0
  122. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +98 -30
  123. package/packages/dd-trace/src/appsec/index.js +79 -25
  124. package/packages/dd-trace/src/{plugins/util → appsec}/ip_blocklist.js +0 -0
  125. package/packages/dd-trace/src/appsec/ip_extractor.js +98 -0
  126. package/packages/dd-trace/src/appsec/recommended.json +134 -53
  127. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
  128. package/packages/dd-trace/src/appsec/remote_config/index.js +56 -0
  129. package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
  130. package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
  131. package/packages/dd-trace/src/appsec/rule_manager.js +61 -1
  132. package/packages/dd-trace/src/appsec/templates/blocked.html +99 -0
  133. package/packages/dd-trace/src/appsec/templates/blocked.json +8 -0
  134. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +66 -0
  135. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +9 -5
  136. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +19 -51
  137. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +10 -5
  138. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +202 -0
  139. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +51 -62
  140. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +89 -0
  141. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +82 -0
  142. package/packages/dd-trace/src/config.js +119 -35
  143. package/packages/dd-trace/src/constants.js +9 -1
  144. package/packages/dd-trace/src/dogstatsd.js +42 -10
  145. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +10 -2
  146. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  147. package/packages/dd-trace/src/exporter.js +3 -0
  148. package/packages/dd-trace/src/exporters/agent/index.js +10 -2
  149. package/packages/dd-trace/src/exporters/agent/writer.js +2 -9
  150. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +82 -0
  151. package/packages/dd-trace/src/exporters/common/request.js +51 -1
  152. package/packages/dd-trace/src/exporters/span-stats/index.js +6 -2
  153. package/packages/dd-trace/src/format.js +29 -10
  154. package/packages/dd-trace/src/lambda/handler.js +72 -0
  155. package/packages/dd-trace/src/lambda/index.js +5 -0
  156. package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
  157. package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
  158. package/packages/dd-trace/src/lambda/runtime/ritm.js +138 -0
  159. package/packages/dd-trace/src/metrics.js +15 -2
  160. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
  161. package/packages/dd-trace/src/opentracing/span.js +2 -1
  162. package/packages/dd-trace/src/opentracing/span_context.js +9 -0
  163. package/packages/dd-trace/src/plugin_manager.js +11 -17
  164. package/packages/dd-trace/src/plugins/cache.js +9 -0
  165. package/packages/dd-trace/src/plugins/ci_plugin.js +97 -0
  166. package/packages/dd-trace/src/plugins/client.js +9 -0
  167. package/packages/dd-trace/src/plugins/composite.js +26 -0
  168. package/packages/dd-trace/src/plugins/consumer.js +9 -0
  169. package/packages/dd-trace/src/plugins/database.js +55 -0
  170. package/packages/dd-trace/src/plugins/incoming.js +7 -0
  171. package/packages/dd-trace/src/plugins/index.js +3 -0
  172. package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
  173. package/packages/dd-trace/src/plugins/outgoing.js +31 -0
  174. package/packages/dd-trace/src/plugins/plugin.js +3 -0
  175. package/packages/dd-trace/src/plugins/producer.js +9 -0
  176. package/packages/dd-trace/src/plugins/server.js +9 -0
  177. package/packages/dd-trace/src/plugins/storage.js +21 -0
  178. package/packages/dd-trace/src/plugins/tracing.js +94 -0
  179. package/packages/dd-trace/src/plugins/util/ci.js +40 -4
  180. package/packages/dd-trace/src/plugins/util/git.js +58 -18
  181. package/packages/dd-trace/src/plugins/util/test.js +71 -8
  182. package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
  183. package/packages/dd-trace/src/plugins/util/web.js +11 -114
  184. package/packages/dd-trace/src/priority_sampler.js +6 -2
  185. package/packages/dd-trace/src/profiling/config.js +11 -6
  186. package/packages/dd-trace/src/profiling/exporters/agent.js +4 -0
  187. package/packages/dd-trace/src/profiling/index.js +2 -2
  188. package/packages/dd-trace/src/profiling/profiler.js +43 -7
  189. package/packages/dd-trace/src/proxy.js +8 -16
  190. package/packages/dd-trace/src/ritm.js +25 -14
  191. package/packages/dd-trace/src/span_processor.js +17 -0
  192. package/packages/dd-trace/src/span_sampler.js +77 -0
  193. package/packages/dd-trace/src/span_stats.js +2 -2
  194. package/packages/dd-trace/src/telemetry/dependencies.js +21 -7
  195. package/packages/dd-trace/src/telemetry/index.js +7 -1
  196. package/packages/dd-trace/src/telemetry/send-data.js +3 -1
  197. package/packages/dd-trace/src/tracer.js +10 -5
  198. package/packages/dd-trace/src/util.js +43 -1
@@ -0,0 +1,94 @@
1
+ 'use strict'
2
+
3
+ const Plugin = require('./plugin')
4
+ const { storage } = require('../../../datadog-core')
5
+ const analyticsSampler = require('../analytics_sampler')
6
+ const { COMPONENT } = require('../constants')
7
+
8
+ class TracingPlugin extends Plugin {
9
+ constructor (...args) {
10
+ super(...args)
11
+
12
+ this.component = this.constructor.component || this.constructor.name
13
+ this.operation = this.constructor.operation
14
+
15
+ this.addTraceSub('start', message => {
16
+ this.start(message)
17
+ })
18
+
19
+ this.addTraceSub('error', err => {
20
+ this.error(err)
21
+ })
22
+
23
+ this.addTraceSub('finish', message => {
24
+ this.finish(message)
25
+ })
26
+ }
27
+
28
+ get activeSpan () {
29
+ const store = storage.getStore()
30
+
31
+ return store && store.span
32
+ }
33
+
34
+ configure (config) {
35
+ return super.configure({
36
+ ...config,
37
+ hooks: {
38
+ [this.operation]: () => {},
39
+ ...config.hooks
40
+ }
41
+ })
42
+ }
43
+
44
+ start () {} // implemented by individual plugins
45
+
46
+ finish () {
47
+ this.activeSpan.finish()
48
+ }
49
+
50
+ error (error) {
51
+ this.addError(error)
52
+ }
53
+
54
+ addTraceSub (eventName, handler) {
55
+ this.addSub(`apm:${this.component}:${this.operation}:${eventName}`, handler)
56
+ }
57
+
58
+ addError (error) {
59
+ const span = this.activeSpan
60
+
61
+ if (!span._spanContext._tags['error']) {
62
+ span.setTag('error', error || 1)
63
+ }
64
+ }
65
+
66
+ startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}) {
67
+ const store = storage.getStore()
68
+
69
+ if (store && childOf === undefined) {
70
+ childOf = store.span
71
+ }
72
+
73
+ const span = this.tracer.startSpan(name, {
74
+ childOf,
75
+ tags: {
76
+ [COMPONENT]: this.component,
77
+ 'service.name': service || this.tracer._service,
78
+ 'resource.name': resource,
79
+ 'span.kind': kind,
80
+ 'span.type': type,
81
+ ...meta,
82
+ ...metrics
83
+ }
84
+ })
85
+
86
+ analyticsSampler.sample(span, this.config.measured)
87
+
88
+ storage.enterWith({ ...store, span })
89
+
90
+ return span
91
+ }
92
+ }
93
+
94
+ module.exports = TracingPlugin
@@ -18,7 +18,9 @@ const {
18
18
  CI_JOB_URL,
19
19
  CI_JOB_NAME,
20
20
  CI_STAGE_NAME,
21
- CI_ENV_VARS
21
+ CI_ENV_VARS,
22
+ GIT_COMMIT_COMMITTER_NAME,
23
+ GIT_COMMIT_COMMITTER_EMAIL
22
24
  } = require('./tags')
23
25
 
24
26
  // Receives a string with the form 'John Doe <john.doe@gmail.com>'
@@ -233,7 +235,8 @@ module.exports = {
233
235
  GITHUB_SHA,
234
236
  GITHUB_REPOSITORY,
235
237
  GITHUB_SERVER_URL,
236
- GITHUB_RUN_ATTEMPT
238
+ GITHUB_RUN_ATTEMPT,
239
+ GITHUB_JOB
237
240
  } = env
238
241
 
239
242
  const repositoryURL = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git`
@@ -257,6 +260,7 @@ module.exports = {
257
260
  [GIT_COMMIT_SHA]: GITHUB_SHA,
258
261
  [GIT_REPOSITORY_URL]: repositoryURL,
259
262
  [CI_JOB_URL]: jobUrl,
263
+ [CI_JOB_NAME]: GITHUB_JOB,
260
264
  [CI_WORKSPACE_PATH]: GITHUB_WORKSPACE,
261
265
  [refKey]: ref,
262
266
  [CI_ENV_VARS]: JSON.stringify({
@@ -281,6 +285,7 @@ module.exports = {
281
285
  APPVEYOR_REPO_TAG_NAME,
282
286
  APPVEYOR_REPO_COMMIT_AUTHOR,
283
287
  APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL,
288
+ APPVEYOR_REPO_COMMIT_MESSAGE,
284
289
  APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
285
290
  } = env
286
291
 
@@ -296,7 +301,7 @@ module.exports = {
296
301
  [CI_WORKSPACE_PATH]: APPVEYOR_BUILD_FOLDER,
297
302
  [GIT_COMMIT_AUTHOR_NAME]: APPVEYOR_REPO_COMMIT_AUTHOR,
298
303
  [GIT_COMMIT_AUTHOR_EMAIL]: APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL,
299
- [GIT_COMMIT_MESSAGE]: APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
304
+ [GIT_COMMIT_MESSAGE]: APPVEYOR_REPO_COMMIT_MESSAGE + '\n' + APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
300
305
  }
301
306
 
302
307
  if (APPVEYOR_REPO_PROVIDER === 'github') {
@@ -350,7 +355,8 @@ module.exports = {
350
355
  [GIT_COMMIT_AUTHOR_EMAIL]: BUILD_REQUESTEDFOREMAIL,
351
356
  [GIT_COMMIT_MESSAGE]: BUILD_SOURCEVERSIONMESSAGE,
352
357
  [CI_STAGE_NAME]: SYSTEM_STAGEDISPLAYNAME,
353
- [CI_JOB_NAME]: SYSTEM_JOBDISPLAYNAME
358
+ [CI_JOB_NAME]: SYSTEM_JOBDISPLAYNAME,
359
+ [CI_ENV_VARS]: JSON.stringify({ SYSTEM_TEAMPROJECTID, BUILD_BUILDID, SYSTEM_JOBID })
354
360
  }
355
361
 
356
362
  if (SYSTEM_TEAMFOUNDATIONSERVERURI && SYSTEM_TEAMPROJECTID && BUILD_BUILDID) {
@@ -506,6 +512,36 @@ module.exports = {
506
512
  }
507
513
  }
508
514
 
515
+ if (env.BUDDY) {
516
+ const {
517
+ BUDDY_EXECUTION_BRANCH,
518
+ BUDDY_EXECUTION_ID,
519
+ BUDDY_EXECUTION_REVISION,
520
+ BUDDY_EXECUTION_REVISION_COMMITTER_EMAIL,
521
+ BUDDY_EXECUTION_REVISION_COMMITTER_NAME,
522
+ BUDDY_EXECUTION_REVISION_MESSAGE,
523
+ BUDDY_EXECUTION_TAG,
524
+ BUDDY_EXECUTION_URL,
525
+ BUDDY_PIPELINE_ID,
526
+ BUDDY_PIPELINE_NAME,
527
+ BUDDY_SCM_URL
528
+ } = env
529
+ tags = {
530
+ [CI_PROVIDER_NAME]: 'buddy',
531
+ [CI_PIPELINE_ID]: `${BUDDY_PIPELINE_ID}/${BUDDY_EXECUTION_ID}`,
532
+ [CI_PIPELINE_NAME]: BUDDY_PIPELINE_NAME,
533
+ [CI_PIPELINE_NUMBER]: BUDDY_EXECUTION_ID,
534
+ [CI_PIPELINE_URL]: BUDDY_EXECUTION_URL,
535
+ [GIT_COMMIT_SHA]: BUDDY_EXECUTION_REVISION,
536
+ [GIT_REPOSITORY_URL]: BUDDY_SCM_URL,
537
+ [GIT_BRANCH]: BUDDY_EXECUTION_BRANCH,
538
+ [GIT_TAG]: BUDDY_EXECUTION_TAG,
539
+ [GIT_COMMIT_MESSAGE]: BUDDY_EXECUTION_REVISION_MESSAGE,
540
+ [GIT_COMMIT_COMMITTER_NAME]: BUDDY_EXECUTION_REVISION_COMMITTER_NAME,
541
+ [GIT_COMMIT_COMMITTER_EMAIL]: BUDDY_EXECUTION_REVISION_COMMITTER_EMAIL
542
+ }
543
+ }
544
+
509
545
  normalizeTag(tags, CI_WORKSPACE_PATH, resolveTilde)
510
546
  normalizeTag(tags, GIT_REPOSITORY_URL, filterSensitiveInfoFromRepository)
511
547
  normalizeTag(tags, GIT_BRANCH, normalizeRef)
@@ -1,6 +1,8 @@
1
1
  const { execSync } = require('child_process')
2
2
  const os = require('os')
3
+ const path = require('path')
3
4
 
5
+ const log = require('../../log')
4
6
  const { sanitizedExec } = require('./exec')
5
7
  const {
6
8
  GIT_COMMIT_SHA,
@@ -17,15 +19,22 @@ const {
17
19
  CI_WORKSPACE_PATH
18
20
  } = require('./tags')
19
21
 
22
+ const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB
23
+
20
24
  function getRepositoryUrl () {
21
25
  return sanitizedExec('git config --get remote.origin.url', { stdio: 'pipe' })
22
26
  }
23
27
 
24
28
  function getLatestCommits () {
25
- return execSync('git log --format=%H -n 1000 --since="1 month ago"', { stdio: 'pipe' })
26
- .toString()
27
- .split('\n')
28
- .filter(commit => !!commit)
29
+ try {
30
+ return execSync('git log --format=%H -n 1000 --since="1 month ago"', { stdio: 'pipe' })
31
+ .toString()
32
+ .split('\n')
33
+ .filter(commit => commit)
34
+ } catch (err) {
35
+ log.error(err)
36
+ return []
37
+ }
29
38
  }
30
39
 
31
40
  function getCommitsToUpload (commitsToExclude) {
@@ -36,27 +45,57 @@ function getCommitsToUpload (commitsToExclude) {
36
45
  gitCommandToGetCommitsToUpload = `${gitCommandToGetCommitsToUpload} ^${commit}`
37
46
  })
38
47
 
39
- return execSync(gitCommandToGetCommitsToUpload, { stdio: 'pipe' })
40
- .toString()
41
- .split('\n')
42
- .filter(commit => !!commit)
48
+ try {
49
+ return execSync(gitCommandToGetCommitsToUpload, { stdio: 'pipe', maxBuffer: GIT_REV_LIST_MAX_BUFFER })
50
+ .toString()
51
+ .split('\n')
52
+ .filter(commit => commit)
53
+ } catch (err) {
54
+ log.error(err)
55
+ return []
56
+ }
43
57
  }
44
58
 
45
- // Generates pack files to upload and
46
- // returns the ordered list of packfiles' paths
47
59
  function generatePackFilesForCommits (commitsToUpload) {
48
60
  const tmpFolder = os.tmpdir()
49
61
 
50
- const prefix = Math.floor(Math.random() * 10000)
51
- const path = `${tmpFolder}/${prefix}`
62
+ const randomPrefix = String(Math.floor(Math.random() * 10000))
63
+ const temporaryPath = path.join(tmpFolder, randomPrefix)
64
+ const cwdPath = path.join(process.cwd(), randomPrefix)
52
65
 
53
- const orderedCommits =
54
- execSync(
55
- `git pack-objects --compression=9 --max-pack-size=3m ${path}`,
66
+ // Generates pack files to upload and
67
+ // returns the ordered list of packfiles' paths
68
+ function execGitPackObjects (targetPath) {
69
+ return execSync(
70
+ `git pack-objects --compression=9 --max-pack-size=3m ${targetPath}`,
56
71
  { input: commitsToUpload.join('\n') }
57
- ).toString().split('\n').filter(commit => !!commit)
72
+ ).toString().split('\n').filter(commit => commit).map(commit => `${targetPath}-${commit}.pack`)
73
+ }
74
+
75
+ try {
76
+ return execGitPackObjects(temporaryPath, commitsToUpload)
77
+ } catch (err) {
78
+ log.error(err)
79
+ /**
80
+ * The generation of pack files in the temporary folder (from `os.tmpdir()`)
81
+ * sometimes fails in certain CI setups with the error message
82
+ * `unable to rename temporary pack file: Invalid cross-device link`.
83
+ * The reason why is unclear.
84
+ *
85
+ * A workaround is to attempt to generate the pack files in `process.cwd()`.
86
+ * While this works most of the times, it's not ideal since it affects the git status.
87
+ * This workaround is intended to be temporary.
88
+ *
89
+ * TODO: fix issue and remove workaround.
90
+ */
91
+ try {
92
+ return execGitPackObjects(cwdPath, commitsToUpload)
93
+ } catch (err) {
94
+ log.error(err)
95
+ }
58
96
 
59
- return orderedCommits.map(commit => `${path}-${commit}.pack`)
97
+ return []
98
+ }
60
99
  }
61
100
 
62
101
  // If there is ciMetadata, it takes precedence.
@@ -106,5 +145,6 @@ module.exports = {
106
145
  getLatestCommits,
107
146
  getRepositoryUrl,
108
147
  generatePackFilesForCommits,
109
- getCommitsToUpload
148
+ getCommitsToUpload,
149
+ GIT_REV_LIST_MAX_BUFFER
110
150
  }
@@ -1,6 +1,7 @@
1
1
  const path = require('path')
2
2
  const fs = require('fs')
3
3
 
4
+ const istanbul = require('istanbul-lib-coverage')
4
5
  const ignore = require('ignore')
5
6
 
6
7
  const { getGitMetadata } = require('./git')
@@ -40,14 +41,16 @@ const TEST_COMMAND = 'test.command'
40
41
  const TEST_SESSION_ID = 'test_session_id'
41
42
  const TEST_SUITE_ID = 'test_suite_id'
42
43
 
43
- const ERROR_TYPE = 'error.type'
44
- const ERROR_MESSAGE = 'error.msg'
45
- const ERROR_STACK = 'error.stack'
46
-
47
44
  const CI_APP_ORIGIN = 'ciapp-test'
48
45
 
49
46
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
50
47
 
48
+ const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
49
+ const TEST_SESSION_ITR_SKIPPING_ENABLED = 'test_session.itr.tests_skipping.enabled'
50
+ const TEST_SESSION_CODE_COVERAGE_ENABLED = 'test_session.code_coverage.enabled'
51
+
52
+ const TEST_CODE_COVERAGE_LINES_TOTAL = 'test.codecov_lines_total'
53
+
51
54
  module.exports = {
52
55
  TEST_CODE_OWNERS,
53
56
  TEST_FRAMEWORK,
@@ -61,9 +64,6 @@ module.exports = {
61
64
  TEST_SKIP_REASON,
62
65
  TEST_IS_RUM_ACTIVE,
63
66
  TEST_SOURCE_FILE,
64
- ERROR_TYPE,
65
- ERROR_MESSAGE,
66
- ERROR_STACK,
67
67
  CI_APP_ORIGIN,
68
68
  LIBRARY_VERSION,
69
69
  getTestEnvironmentMetadata,
@@ -78,7 +78,15 @@ module.exports = {
78
78
  getTestSuiteCommonTags,
79
79
  TEST_COMMAND,
80
80
  TEST_SESSION_ID,
81
- TEST_SUITE_ID
81
+ TEST_SUITE_ID,
82
+ TEST_ITR_TESTS_SKIPPED,
83
+ TEST_SESSION_ITR_SKIPPING_ENABLED,
84
+ TEST_SESSION_CODE_COVERAGE_ENABLED,
85
+ TEST_CODE_COVERAGE_LINES_TOTAL,
86
+ getCoveredFilenamesFromCoverage,
87
+ resetCoverage,
88
+ mergeCoverage,
89
+ fromCoverageMapToCoverage
82
90
  }
83
91
 
84
92
  function getTestEnvironmentMetadata (testFramework, config) {
@@ -256,3 +264,58 @@ function getTestSuiteCommonTags (command, version, testSuite) {
256
264
  [TEST_COMMAND]: command
257
265
  }
258
266
  }
267
+
268
+ function getCoveredFilenamesFromCoverage (coverage) {
269
+ const coverageMap = istanbul.createCoverageMap(coverage)
270
+
271
+ return coverageMap
272
+ .files()
273
+ .filter(filename => {
274
+ const fileCoverage = coverageMap.fileCoverageFor(filename)
275
+ const lineCoverage = fileCoverage.getLineCoverage()
276
+ const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
277
+
278
+ return isAnyLineExecuted
279
+ })
280
+ }
281
+
282
+ function resetCoverage (coverage) {
283
+ const coverageMap = istanbul.createCoverageMap(coverage)
284
+
285
+ return coverageMap
286
+ .files()
287
+ .forEach(filename => {
288
+ const fileCoverage = coverageMap.fileCoverageFor(filename)
289
+ fileCoverage.resetHits()
290
+ })
291
+ }
292
+
293
+ function mergeCoverage (coverage, targetCoverage) {
294
+ const coverageMap = istanbul.createCoverageMap(coverage)
295
+ return coverageMap
296
+ .files()
297
+ .forEach(filename => {
298
+ const fileCoverage = coverageMap.fileCoverageFor(filename)
299
+
300
+ // If the fileCoverage is not there for this filename,
301
+ // we create it to force a merge between the fileCoverages
302
+ // instead of a reference assignment (which would not work if the coverage is reset later on)
303
+ if (!targetCoverage.data[filename]) {
304
+ targetCoverage.addFileCoverage(istanbul.createFileCoverage(filename))
305
+ }
306
+ targetCoverage.addFileCoverage(fileCoverage)
307
+ const targetFileCoverage = targetCoverage.fileCoverageFor(filename)
308
+
309
+ // branches (.b) are copied by reference, so `resetHits` affects the copy, so we need to copy it manually
310
+ Object.entries(targetFileCoverage.data.b).forEach(([key, value]) => {
311
+ targetFileCoverage.data.b[key] = [...value]
312
+ })
313
+ })
314
+ }
315
+
316
+ function fromCoverageMapToCoverage (coverageMap) {
317
+ return Object.entries(coverageMap.data).reduce((acc, [filename, fileCoverage]) => {
318
+ acc[filename] = fileCoverage.data
319
+ return acc
320
+ }, {})
321
+ }
@@ -26,6 +26,19 @@ function removeEmptyValues (tags) {
26
26
  }, {})
27
27
  }
28
28
 
29
+ function filterSensitiveInfoFromRepository (repositoryUrl) {
30
+ try {
31
+ if (repositoryUrl.startsWith('git@')) {
32
+ return repositoryUrl
33
+ }
34
+ const { protocol, hostname, pathname } = new URL(repositoryUrl)
35
+
36
+ return `${protocol}//${hostname}${pathname}`
37
+ } catch (e) {
38
+ return repositoryUrl
39
+ }
40
+ }
41
+
29
42
  function getUserProviderGitMetadata () {
30
43
  const {
31
44
  DD_GIT_COMMIT_SHA,
@@ -57,7 +70,7 @@ function getUserProviderGitMetadata () {
57
70
  return removeEmptyValues({
58
71
  [GIT_COMMIT_SHA]: DD_GIT_COMMIT_SHA,
59
72
  [GIT_BRANCH]: branch,
60
- [GIT_REPOSITORY_URL]: DD_GIT_REPOSITORY_URL,
73
+ [GIT_REPOSITORY_URL]: filterSensitiveInfoFromRepository(DD_GIT_REPOSITORY_URL),
61
74
  [GIT_TAG]: tag,
62
75
  [GIT_COMMIT_MESSAGE]: DD_GIT_COMMIT_MESSAGE,
63
76
  [GIT_COMMIT_COMMITTER_NAME]: DD_GIT_COMMIT_COMMITTER_NAME,
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const net = require('net')
4
3
  const uniq = require('lodash.uniq')
5
4
  const analyticsSampler = require('../../analytics_sampler')
6
5
  const FORMAT_HTTP_HEADERS = 'http_headers'
@@ -9,8 +8,7 @@ const tags = require('../../../../../ext/tags')
9
8
  const types = require('../../../../../ext/types')
10
9
  const kinds = require('../../../../../ext/kinds')
11
10
  const urlFilter = require('./urlfilter')
12
- const BlockList = require('./ip_blocklist')
13
- const { incomingHttpRequestEnd } = require('../../appsec/gateway/channels')
11
+ const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../constants')
14
12
 
15
13
  const WEB = types.WEB
16
14
  const SERVER = kinds.SERVER
@@ -26,33 +24,18 @@ const HTTP_ROUTE = tags.HTTP_ROUTE
26
24
  const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
27
25
  const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS
28
26
  const HTTP_USERAGENT = tags.HTTP_USERAGENT
29
- const HTTP_CLIENT_IP = tags.HTTP_CLIENT_IP
30
27
  const MANUAL_DROP = tags.MANUAL_DROP
31
28
 
32
29
  const HTTP2_HEADER_AUTHORITY = ':authority'
33
30
  const HTTP2_HEADER_SCHEME = ':scheme'
34
31
  const HTTP2_HEADER_PATH = ':path'
35
32
 
36
- const ipHeaderList = [
37
- 'x-forwarded-for',
38
- 'x-real-ip',
39
- 'client-ip',
40
- 'x-forwarded',
41
- 'x-cluster-client-ip',
42
- 'forwarded-for',
43
- 'forwarded',
44
- 'via',
45
- 'true-client-ip'
46
- ]
47
-
48
33
  const contexts = new WeakMap()
49
34
  const ends = new WeakMap()
50
35
 
51
36
  const web = {
52
37
  // Ensure the configuration has the correct structure and defaults.
53
38
  normalizeConfig (config) {
54
- config = config.server || config
55
-
56
39
  const headers = getHeadersToRecord(config)
57
40
  const validateStatus = getStatusValidator(config)
58
41
  const hooks = getHooks(config)
@@ -60,14 +43,15 @@ const web = {
60
43
  const middleware = getMiddlewareSetting(config)
61
44
  const queryStringObfuscation = getQsObfuscator(config)
62
45
 
63
- return Object.assign({}, config, {
46
+ return {
47
+ ...config,
64
48
  headers,
65
49
  validateStatus,
66
50
  hooks,
67
51
  filter,
68
52
  middleware,
69
53
  queryStringObfuscation
70
- })
54
+ }
71
55
  },
72
56
 
73
57
  setFramework (req, name, config) {
@@ -77,6 +61,7 @@ const web = {
77
61
  if (!span) return
78
62
 
79
63
  span.context()._name = `${name}.request`
64
+ span.context()._tags['component'] = name
80
65
 
81
66
  web.setConfig(req, config)
82
67
  },
@@ -204,9 +189,9 @@ const web = {
204
189
  if (span) {
205
190
  if (error) {
206
191
  span.addTags({
207
- 'error.type': error.name,
208
- 'error.msg': error.message,
209
- 'error.stack': error.stack
192
+ [ERROR_TYPE]: error.name,
193
+ [ERROR_MESSAGE]: error.message,
194
+ [ERROR_STACK]: error.stack
210
195
  })
211
196
  }
212
197
 
@@ -264,8 +249,7 @@ const web = {
264
249
 
265
250
  // Extract the parent span from the headers and start a new span as its child
266
251
  startChildSpan (tracer, name, headers) {
267
- const childOf = tracer.scope().active() || tracer.extract(FORMAT_HTTP_HEADERS, headers)
268
-
252
+ const childOf = tracer.extract(FORMAT_HTTP_HEADERS, headers)
269
253
  const span = tracer.startSpan(name, { childOf })
270
254
 
271
255
  return span
@@ -276,7 +260,7 @@ const web = {
276
260
  const context = contexts.get(req)
277
261
  const span = context.span
278
262
  const error = context.error
279
- const hasExistingError = span.context()._tags['error'] || span.context()._tags['error.msg']
263
+ const hasExistingError = span.context()._tags['error'] || span.context()._tags[ERROR_MESSAGE]
280
264
 
281
265
  if (!hasExistingError && !context.config.validateStatus(statusCode)) {
282
266
  span.setTag(ERROR, error || true)
@@ -320,18 +304,12 @@ const web = {
320
304
  },
321
305
 
322
306
  finishAll (context) {
323
- const { req, res } = context
324
-
325
307
  for (const beforeEnd of context.beforeEnd) {
326
308
  beforeEnd()
327
309
  }
328
310
 
329
311
  web.finishMiddleware(context)
330
312
 
331
- if (incomingHttpRequestEnd.hasSubscribers) {
332
- incomingHttpRequestEnd.publish({ req, res })
333
- }
334
-
335
313
  web.finishSpan(context)
336
314
  },
337
315
 
@@ -353,41 +331,6 @@ const web = {
353
331
  return `${path}?${qs}`
354
332
  },
355
333
 
356
- extractIp (context) {
357
- const { req, config } = context
358
-
359
- if (config.clientIpHeaderDisabled) return
360
-
361
- const headers = req.headers
362
-
363
- if (config.clientIpHeader) {
364
- const header = headers[config.clientIpHeader]
365
- if (!header) return
366
-
367
- return findFirstIp(header)
368
- }
369
-
370
- const foundHeaders = []
371
-
372
- for (let i = 0; i < ipHeaderList.length; i++) {
373
- if (headers[ipHeaderList[i]]) {
374
- foundHeaders.push(ipHeaderList[i])
375
- }
376
- }
377
-
378
- if (foundHeaders.length === 1) {
379
- const header = headers[foundHeaders[0]]
380
- const firstIp = findFirstIp(header)
381
-
382
- if (firstIp) return firstIp
383
- } else if (foundHeaders.length > 1) {
384
- log.error(`Cannot find client IP: multiple IP headers detected ${foundHeaders}`)
385
- return
386
- }
387
-
388
- return req.socket && req.socket.remoteAddress
389
- },
390
-
391
334
  wrapWriteHead (context) {
392
335
  const { req, res } = context
393
336
  const writeHead = res.writeHead
@@ -486,8 +429,7 @@ function addRequestTags (context) {
486
429
  [HTTP_METHOD]: req.method,
487
430
  [SPAN_KIND]: SERVER,
488
431
  [SPAN_TYPE]: WEB,
489
- [HTTP_USERAGENT]: req.headers['user-agent'],
490
- [HTTP_CLIENT_IP]: web.extractIp(context)
432
+ [HTTP_USERAGENT]: req.headers['user-agent']
491
433
  })
492
434
 
493
435
  addHeaders(context)
@@ -555,51 +497,6 @@ function getProtocol (req) {
555
497
  return 'http'
556
498
  }
557
499
 
558
- const privateCIDRs = [
559
- '127.0.0.0/8',
560
- '10.0.0.0/8',
561
- '172.16.0.0/12',
562
- '192.168.0.0/16',
563
- '169.254.0.0/16',
564
- '::1/128',
565
- 'fec0::/10',
566
- 'fe80::/10',
567
- 'fc00::/7',
568
- 'fd00::/8'
569
- ]
570
-
571
- const privateIPMatcher = new BlockList()
572
-
573
- for (const cidr of privateCIDRs) {
574
- const [ address, prefix ] = cidr.split('/')
575
-
576
- privateIPMatcher.addSubnet(address, parseInt(prefix), net.isIPv6(address) ? 'ipv6' : 'ipv4')
577
- }
578
-
579
- function findFirstIp (str) {
580
- let firstPrivateIp
581
- const splitted = str.split(',')
582
-
583
- for (let i = 0; i < splitted.length; i++) {
584
- const chunk = splitted[i].trim()
585
-
586
- // TODO: strip port and interface data ?
587
-
588
- const type = net.isIP(chunk)
589
- if (!type) continue
590
-
591
- if (!privateIPMatcher.check(chunk, type === 6 ? 'ipv6' : 'ipv4')) {
592
- // it's public, return it immediately
593
- return chunk
594
- }
595
-
596
- // it's private, only save the first one found
597
- if (!firstPrivateIp) firstPrivateIp = chunk
598
- }
599
-
600
- return firstPrivateIp
601
- }
602
-
603
500
  function getHeadersToRecord (config) {
604
501
  if (Array.isArray(config.headers)) {
605
502
  try {
@@ -109,9 +109,9 @@ class PrioritySampler {
109
109
  }
110
110
 
111
111
  _getPriorityFromTags (tags) {
112
- if (tags.hasOwnProperty(MANUAL_KEEP) && tags[MANUAL_KEEP] !== false) {
112
+ if (hasOwn(tags, MANUAL_KEEP) && tags[MANUAL_KEEP] !== false) {
113
113
  return USER_KEEP
114
- } else if (tags.hasOwnProperty(MANUAL_DROP) && tags[MANUAL_DROP] !== false) {
114
+ } else if (hasOwn(tags, MANUAL_DROP) && tags[MANUAL_DROP] !== false) {
115
115
  return USER_REJECT
116
116
  } else {
117
117
  const priority = parseInt(tags[SAMPLING_PRIORITY], 10)
@@ -198,4 +198,8 @@ class PrioritySampler {
198
198
  }
199
199
  }
200
200
 
201
+ function hasOwn (object, prop) {
202
+ return Object.prototype.hasOwnProperty.call(object, prop)
203
+ }
204
+
201
205
  module.exports = PrioritySampler