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
@@ -1,8 +1,10 @@
1
1
  'use strict'
2
2
 
3
3
  const callbacks = require('./callbacks')
4
+ const Gateway = require('./gateway/engine')
4
5
 
5
6
  const appliedCallbacks = new Map()
7
+ const appliedAsmData = new Map()
6
8
 
7
9
  function applyRules (rules, config) {
8
10
  if (appliedCallbacks.has(rules)) return
@@ -13,15 +15,73 @@ function applyRules (rules, config) {
13
15
  appliedCallbacks.set(rules, callback)
14
16
  }
15
17
 
18
+ function updateAsmData (action, asmData, asmDataId) {
19
+ if (action === 'unapply') {
20
+ appliedAsmData.delete(asmDataId)
21
+ } else {
22
+ appliedAsmData.set(asmDataId, asmData)
23
+ }
24
+
25
+ const mergedRuleData = mergeRuleData(appliedAsmData.values())
26
+ for (const callback of appliedCallbacks.values()) {
27
+ callback.updateRuleData(mergedRuleData)
28
+ }
29
+ }
30
+
31
+ function mergeRuleData (asmDataValues) {
32
+ const mergedRulesData = new Map()
33
+ for (const asmData of asmDataValues) {
34
+ if (!asmData.rules_data) continue
35
+ for (const rulesData of asmData.rules_data) {
36
+ const key = `${rulesData.id}+${rulesData.type}`
37
+ if (mergedRulesData.has(key)) {
38
+ const existingRulesData = mergedRulesData.get(key)
39
+ rulesData.data.reduce(rulesReducer, existingRulesData.data)
40
+ } else {
41
+ mergedRulesData.set(key, copyRulesData(rulesData))
42
+ }
43
+ }
44
+ }
45
+ return [...mergedRulesData.values()]
46
+ }
47
+
48
+ function rulesReducer (existingEntries, rulesDataEntry) {
49
+ const existingEntry = existingEntries.find((entry) => entry.value === rulesDataEntry.value)
50
+ if (existingEntry && !('expiration' in existingEntry)) return existingEntries
51
+ if (existingEntry && 'expiration' in rulesDataEntry && rulesDataEntry.expiration > existingEntry.expiration) {
52
+ existingEntry.expiration = rulesDataEntry.expiration
53
+ } else if (existingEntry && !('expiration' in rulesDataEntry)) {
54
+ delete existingEntry.expiration
55
+ } else if (!existingEntry) {
56
+ existingEntries.push({ ...rulesDataEntry })
57
+ }
58
+ return existingEntries
59
+ }
60
+
61
+ function copyRulesData (rulesData) {
62
+ const copy = { ...rulesData }
63
+ if (copy.data) {
64
+ const data = []
65
+ copy.data.forEach(item => {
66
+ data.push({ ...item })
67
+ })
68
+ copy.data = data
69
+ }
70
+ return copy
71
+ }
16
72
  function clearAllRules () {
73
+ Gateway.manager.clear()
74
+
17
75
  for (const [key, callback] of appliedCallbacks) {
18
76
  callback.clear()
19
77
 
20
78
  appliedCallbacks.delete(key)
21
79
  }
80
+ appliedAsmData.clear()
22
81
  }
23
82
 
24
83
  module.exports = {
25
84
  applyRules,
26
- clearAllRules
85
+ clearAllRules,
86
+ updateAsmData
27
87
  }
@@ -0,0 +1,99 @@
1
+ <!-- Sorry, you’ve been blocked -->
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <meta charset="UTF-8">
7
+ <meta name="viewport" content="width=device-width,initial-scale=1">
8
+ <title>You've been blocked</title>
9
+ <style>
10
+ a,
11
+ body,
12
+ div,
13
+ html,
14
+ span {
15
+ margin: 0;
16
+ padding: 0;
17
+ border: 0;
18
+ font-size: 100%;
19
+ font: inherit;
20
+ vertical-align: baseline
21
+ }
22
+
23
+ body {
24
+ background: -webkit-radial-gradient(26% 19%, circle, #fff, #f4f7f9);
25
+ background: radial-gradient(circle at 26% 19%, #fff, #f4f7f9);
26
+ display: -webkit-box;
27
+ display: -ms-flexbox;
28
+ display: flex;
29
+ -webkit-box-pack: center;
30
+ -ms-flex-pack: center;
31
+ justify-content: center;
32
+ -webkit-box-align: center;
33
+ -ms-flex-align: center;
34
+ align-items: center;
35
+ -ms-flex-line-pack: center;
36
+ align-content: center;
37
+ width: 100%;
38
+ min-height: 100vh;
39
+ line-height: 1;
40
+ flex-direction: column
41
+ }
42
+
43
+ p {
44
+ display: block
45
+ }
46
+
47
+
48
+ main {
49
+ text-align: center;
50
+ flex: 1;
51
+ display: -webkit-box;
52
+ display: -ms-flexbox;
53
+ display: flex;
54
+ -webkit-box-pack: center;
55
+ -ms-flex-pack: center;
56
+ justify-content: center;
57
+ -webkit-box-align: center;
58
+ -ms-flex-align: center;
59
+ align-items: center;
60
+ -ms-flex-line-pack: center;
61
+ align-content: center;
62
+ flex-direction: column
63
+ }
64
+
65
+ p {
66
+ font-size: 18px;
67
+ line-height: normal;
68
+ color: #646464;
69
+ font-family: sans-serif;
70
+ font-weight: 400
71
+ }
72
+
73
+ a {
74
+ color: #4842b7
75
+ }
76
+
77
+ footer {
78
+ width: 100%;
79
+ text-align: center
80
+ }
81
+
82
+ footer p {
83
+ font-size: 16px
84
+ }
85
+ </style>
86
+ </head>
87
+
88
+ <body>
89
+ <main>
90
+ <p>Sorry, you cannot access this page. Please contact the customer service team.</p>
91
+ </main>
92
+ <footer>
93
+ <p>Security provided by <a
94
+ href="https://www.datadoghq.com/product/security-platform/application-security-monitoring/"
95
+ target="_blank">Datadog</a></p>
96
+ </footer>
97
+ </body>
98
+
99
+ </html>
@@ -0,0 +1,8 @@
1
+ {
2
+ "errors": [
3
+ {
4
+ "title": "You've been blocked",
5
+ "detail": "Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."
6
+ }
7
+ ]
8
+ }
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ const AgentWriter = require('../../../exporters/agent/writer')
4
+ const AgentlessWriter = require('../agentless/writer')
5
+ const CoverageWriter = require('../agentless/coverage-writer')
6
+ const CiVisibilityExporter = require('../ci-visibility-exporter')
7
+
8
+ const AGENT_EVP_PROXY_PATH = '/evp_proxy/v2'
9
+
10
+ function getIsEvpCompatible (err, agentInfo) {
11
+ return !err && agentInfo.endpoints.some(url => url.includes(AGENT_EVP_PROXY_PATH))
12
+ }
13
+
14
+ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
15
+ constructor (config) {
16
+ super(config)
17
+
18
+ const {
19
+ tags,
20
+ prioritySampler,
21
+ lookup,
22
+ protocolVersion,
23
+ headers,
24
+ isGitUploadEnabled
25
+ } = config
26
+
27
+ this.getAgentInfo((err, agentInfo) => {
28
+ this._isInitialized = true
29
+ const isEvpCompatible = getIsEvpCompatible(err, agentInfo)
30
+ if (isEvpCompatible) {
31
+ this._isUsingEvpProxy = true
32
+ this._writer = new AgentlessWriter({
33
+ url: this._url,
34
+ tags,
35
+ evpProxyPrefix: AGENT_EVP_PROXY_PATH
36
+ })
37
+ this._coverageWriter = new CoverageWriter({
38
+ url: this._url,
39
+ evpProxyPrefix: AGENT_EVP_PROXY_PATH
40
+ })
41
+ if (isGitUploadEnabled) {
42
+ this.sendGitMetadata({ url: this._url, isEvpProxy: true })
43
+ }
44
+ } else {
45
+ this._writer = new AgentWriter({
46
+ url: this._url,
47
+ prioritySampler,
48
+ lookup,
49
+ protocolVersion,
50
+ headers
51
+ })
52
+ // coverages will never be used, so we discard them
53
+ this._coverageBuffer = []
54
+ }
55
+ this._resolveCanUseCiVisProtocol(isEvpCompatible)
56
+ this.exportUncodedTraces()
57
+ this.exportUncodedCoverages()
58
+ })
59
+ }
60
+
61
+ setUrl (url, coverageUrl) {
62
+ this._setUrl(url, coverageUrl)
63
+ }
64
+ }
65
+
66
+ module.exports = AgentProxyCiVisibilityExporter
@@ -12,10 +12,11 @@ function safeJSONStringify (value) {
12
12
  }
13
13
 
14
14
  class Writer extends BaseWriter {
15
- constructor ({ url }) {
15
+ constructor ({ url, evpProxyPrefix = '' }) {
16
16
  super(...arguments)
17
17
  this._url = url
18
18
  this._encoder = new CoverageCIVisibilityEncoder(this)
19
+ this._evpProxyPrefix = evpProxyPrefix
19
20
  }
20
21
 
21
22
  _sendPayload (form, _, done) {
@@ -26,12 +27,15 @@ class Writer extends BaseWriter {
26
27
  'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
27
28
  ...form.getHeaders()
28
29
  },
29
- timeout: 15000
30
+ timeout: 15000,
31
+ url: this._url
30
32
  }
31
33
 
32
- options.protocol = this._url.protocol
33
- options.hostname = this._url.hostname
34
- options.port = this._url.port
34
+ if (this._evpProxyPrefix) {
35
+ options.path = `${this._evpProxyPrefix}/api/v2/citestcov`
36
+ delete options.headers['dd-api-key']
37
+ options.headers['X-Datadog-EVP-Subdomain'] = 'event-platform-intake'
38
+ }
35
39
 
36
40
  log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
37
41
 
@@ -3,75 +3,43 @@
3
3
  const URL = require('url').URL
4
4
  const Writer = require('./writer')
5
5
  const CoverageWriter = require('./coverage-writer')
6
-
6
+ const CiVisibilityExporter = require('../ci-visibility-exporter')
7
7
  const log = require('../../../log')
8
8
 
9
- class AgentlessCiVisibilityExporter {
9
+ class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
10
10
  constructor (config) {
11
- this._config = config
12
- const { tags, site, url, isIntelligentTestRunnerEnabled } = config
13
- this._isIntelligentTestRunnerEnabled = isIntelligentTestRunnerEnabled
11
+ super(config)
12
+ const { tags, site, url, isGitUploadEnabled } = config
13
+ // we don't need to request /info because we are using agentless by configuration
14
+ this._isInitialized = true
15
+ this._resolveCanUseCiVisProtocol(true)
16
+
14
17
  this._url = url || new URL(`https://citestcycle-intake.${site}`)
15
18
  this._writer = new Writer({ url: this._url, tags })
16
- this._timer = undefined
17
- this._coverageTimer = undefined
18
19
 
19
20
  this._coverageUrl = url || new URL(`https://event-platform-intake.${site}`)
20
21
  this._coverageWriter = new CoverageWriter({ url: this._coverageUrl })
21
22
 
22
- process.once('beforeExit', () => {
23
- this._writer.flush()
24
- this._coverageWriter.flush()
25
- })
26
- }
23
+ this._apiUrl = url || new URL(`https://api.${site}`)
27
24
 
28
- exportCoverage ({ span, coverageFiles }) {
29
- const formattedCoverage = {
30
- traceId: span.context()._traceId,
31
- spanId: span.context()._spanId,
32
- files: coverageFiles
33
- }
34
- this._coverageWriter.append(formattedCoverage)
35
-
36
- const { flushInterval } = this._config
37
-
38
- if (flushInterval === 0) {
39
- this._coverageWriter.flush()
40
- } else if (flushInterval > 0 && !this._coverageTimer) {
41
- this._coverageTimer = setTimeout(() => {
42
- this._coverageWriter.flush()
43
- this._coverageTimer = clearTimeout(this._coverageTimer)
44
- }, flushInterval).unref()
25
+ if (isGitUploadEnabled) {
26
+ this.sendGitMetadata({ url: this._getApiUrl() })
45
27
  }
46
28
  }
47
29
 
48
- export (trace) {
49
- this._writer.append(trace)
50
-
51
- const { flushInterval } = this._config
52
-
53
- if (flushInterval === 0) {
54
- this._writer.flush()
55
- } else if (flushInterval > 0 && !this._timer) {
56
- this._timer = setTimeout(() => {
57
- this._writer.flush()
58
- this._timer = clearTimeout(this._timer)
59
- }, flushInterval).unref()
60
- }
61
- }
62
-
63
- setUrl (url, coverageUrl = url) {
30
+ setUrl (url, coverageUrl = url, apiUrl = url) {
31
+ this._setUrl(url, coverageUrl)
64
32
  try {
65
- url = new URL(url)
66
- coverageUrl = new URL(coverageUrl)
67
- this._url = url
68
- this._coverageUrl = coverageUrl
69
- this._writer.setUrl(url)
70
- this._coverageWriter.setUrl(coverageUrl)
33
+ apiUrl = new URL(apiUrl)
34
+ this._apiUrl = apiUrl
71
35
  } catch (e) {
72
36
  log.error(e)
73
37
  }
74
38
  }
39
+
40
+ _getApiUrl () {
41
+ return this._apiUrl
42
+ }
75
43
  }
76
44
 
77
45
  module.exports = AgentlessCiVisibilityExporter
@@ -12,11 +12,12 @@ function safeJSONStringify (value) {
12
12
  }
13
13
 
14
14
  class Writer extends BaseWriter {
15
- constructor ({ url, tags }) {
15
+ constructor ({ url, tags, evpProxyPrefix = '' }) {
16
16
  super(...arguments)
17
17
  const { 'runtime-id': runtimeId, env, service } = tags
18
18
  this._url = url
19
19
  this._encoder = new AgentlessCiVisibilityEncoder(this, { runtimeId, env, service })
20
+ this._evpProxyPrefix = evpProxyPrefix
20
21
  }
21
22
 
22
23
  _sendPayload (data, _, done) {
@@ -27,14 +28,18 @@ class Writer extends BaseWriter {
27
28
  'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
28
29
  'Content-Type': 'application/msgpack'
29
30
  },
30
- timeout: 15000
31
+ timeout: 15000,
32
+ url: this._url
31
33
  }
32
34
 
33
- options.protocol = this._url.protocol
34
- options.hostname = this._url.hostname
35
- options.port = this._url.port
35
+ if (this._evpProxyPrefix) {
36
+ options.path = `${this._evpProxyPrefix}/api/v2/citestcycle`
37
+ delete options.headers['dd-api-key']
38
+ options.headers['X-Datadog-EVP-Subdomain'] = 'citestcycle-intake'
39
+ }
36
40
 
37
41
  log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
42
+
38
43
  request(data, options, (err, res) => {
39
44
  if (err) {
40
45
  log.error(err)
@@ -0,0 +1,202 @@
1
+ 'use strict'
2
+
3
+ const URL = require('url').URL
4
+
5
+ const { sendGitMetadata: sendGitMetadataRequest } = require('./git/git_metadata')
6
+ const { getItrConfiguration: getItrConfigurationRequest } = require('../intelligent-test-runner/get-itr-configuration')
7
+ const { getSkippableSuites: getSkippableSuitesRequest } = require('../intelligent-test-runner/get-skippable-suites')
8
+ const log = require('../../log')
9
+ const AgentInfoExporter = require('../../exporters/common/agent-info-exporter')
10
+
11
+ function getIsTestSessionTrace (trace) {
12
+ return trace.some(span =>
13
+ span.type === 'test_session_end' || span.type === 'test_suite_end'
14
+ )
15
+ }
16
+
17
+ class CiVisibilityExporter extends AgentInfoExporter {
18
+ constructor (config) {
19
+ super(config)
20
+ this._timer = undefined
21
+ this._coverageTimer = undefined
22
+ this._coverageBuffer = []
23
+ // The library can use new features like ITR and test suite level visibility
24
+ // AKA CI Vis Protocol
25
+ this._canUseCiVisProtocol = false
26
+
27
+ // TODO: add timeout to reject this promise
28
+ this._gitUploadPromise = new Promise(resolve => {
29
+ this._resolveGit = resolve
30
+ })
31
+
32
+ // TODO: add timeout to reject this promise
33
+ this._canUseCiVisProtocolPromise = new Promise(resolve => {
34
+ this._resolveCanUseCiVisProtocol = (canUseCiVisProtocol) => {
35
+ this._canUseCiVisProtocol = canUseCiVisProtocol
36
+ resolve(canUseCiVisProtocol)
37
+ }
38
+ })
39
+
40
+ process.once('beforeExit', () => {
41
+ if (this._writer) {
42
+ this._writer.flush()
43
+ }
44
+ if (this._coverageWriter) {
45
+ this._coverageWriter.flush()
46
+ }
47
+ })
48
+ }
49
+
50
+ shouldRequestSkippableSuites () {
51
+ return !!(this._config.isIntelligentTestRunnerEnabled &&
52
+ this._canUseCiVisProtocol &&
53
+ this._itrConfig &&
54
+ this._itrConfig.isSuitesSkippingEnabled)
55
+ }
56
+
57
+ shouldRequestItrConfiguration () {
58
+ return this._config.isIntelligentTestRunnerEnabled
59
+ }
60
+
61
+ canReportSessionTraces () {
62
+ return this._canUseCiVisProtocol
63
+ }
64
+
65
+ canReportCodeCoverage () {
66
+ return this._canUseCiVisProtocol
67
+ }
68
+
69
+ // We can't call the skippable endpoint until git upload has finished,
70
+ // hence the this._gitUploadPromise.then
71
+ getSkippableSuites (testConfiguration, callback) {
72
+ if (!this.shouldRequestSkippableSuites()) {
73
+ return callback(null, [])
74
+ }
75
+ this._gitUploadPromise.then(gitUploadError => {
76
+ if (gitUploadError) {
77
+ return callback(gitUploadError, [])
78
+ }
79
+ const configuration = {
80
+ url: this._getApiUrl(),
81
+ site: this._config.site,
82
+ env: this._config.env,
83
+ service: this._config.service,
84
+ isEvpProxy: !!this._isUsingEvpProxy,
85
+ ...testConfiguration
86
+ }
87
+ getSkippableSuitesRequest(configuration, callback)
88
+ })
89
+ }
90
+
91
+ /**
92
+ * We can't request ITR configuration until we know whether we can use the
93
+ * CI Visibility Protocol, hence the this._canUseCiVisProtocol promise.
94
+ */
95
+ getItrConfiguration (testConfiguration, callback) {
96
+ if (!this.shouldRequestItrConfiguration()) {
97
+ return callback(null, {})
98
+ }
99
+ this._canUseCiVisProtocolPromise.then((canUseCiVisProtocol) => {
100
+ if (!canUseCiVisProtocol) {
101
+ return callback(null, {})
102
+ }
103
+ const configuration = {
104
+ url: this._getApiUrl(),
105
+ env: this._config.env,
106
+ service: this._config.service,
107
+ isEvpProxy: !!this._isUsingEvpProxy,
108
+ ...testConfiguration
109
+ }
110
+ getItrConfigurationRequest(configuration, (err, itrConfig) => {
111
+ /**
112
+ * **Important**: this._itrConfig remains empty in testing frameworks
113
+ * where the tests run in a subprocess, because `getItrConfiguration` is called only once.
114
+ */
115
+ this._itrConfig = itrConfig
116
+ callback(err, itrConfig)
117
+ })
118
+ })
119
+ }
120
+
121
+ sendGitMetadata ({ url, isEvpProxy }) {
122
+ sendGitMetadataRequest(url, isEvpProxy, (err) => {
123
+ if (err) {
124
+ log.error(`Error uploading git metadata: ${err.message}`)
125
+ } else {
126
+ log.debug('Successfully uploaded git metadata')
127
+ }
128
+ this._resolveGit(err)
129
+ })
130
+ }
131
+
132
+ export (trace) {
133
+ // Until it's initialized, we just store the traces as is
134
+ if (!this._isInitialized) {
135
+ this._traceBuffer.push(trace)
136
+ return
137
+ }
138
+ if (!this.canReportSessionTraces() && getIsTestSessionTrace(trace)) {
139
+ return
140
+ }
141
+ this._export(trace)
142
+ }
143
+
144
+ exportCoverage (coveragePayload) {
145
+ // Until it's initialized, we just store the coverages as is
146
+ if (!this._isInitialized) {
147
+ this._coverageBuffer.push(coveragePayload)
148
+ return
149
+ }
150
+ if (!this.canReportCodeCoverage()) {
151
+ return
152
+ }
153
+
154
+ const { span, coverageFiles } = coveragePayload
155
+ const formattedCoverage = {
156
+ traceId: span.context()._traceId,
157
+ spanId: span.context()._spanId,
158
+ files: coverageFiles
159
+ }
160
+
161
+ this._export(formattedCoverage, this._coverageWriter, '_coverageTimer')
162
+ }
163
+
164
+ flush (done = () => {}) {
165
+ if (!this._isInitialized) {
166
+ return done()
167
+ }
168
+ this._writer.flush(() => {
169
+ if (this._coverageWriter) {
170
+ this._coverageWriter.flush(done)
171
+ } else {
172
+ done()
173
+ }
174
+ })
175
+ }
176
+
177
+ exportUncodedCoverages () {
178
+ this._coverageBuffer.forEach(oldCoveragePayload => {
179
+ this.exportCoverage(oldCoveragePayload)
180
+ })
181
+ this._coverageBuffer = []
182
+ }
183
+
184
+ _setUrl (url, coverageUrl = url) {
185
+ try {
186
+ url = new URL(url)
187
+ coverageUrl = new URL(coverageUrl)
188
+ this._url = url
189
+ this._coverageUrl = coverageUrl
190
+ this._writer.setUrl(url)
191
+ this._coverageWriter.setUrl(coverageUrl)
192
+ } catch (e) {
193
+ log.error(e)
194
+ }
195
+ }
196
+
197
+ _getApiUrl () {
198
+ return this._url
199
+ }
200
+ }
201
+
202
+ module.exports = CiVisibilityExporter