dd-trace 4.18.0 → 4.23.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 (137) hide show
  1. package/LICENSE-3rdparty.csv +3 -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 +29 -0
  8. package/package.json +12 -11
  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/aerospike.js +47 -0
  12. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  13. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  14. package/packages/datadog-instrumentations/src/child-process.js +4 -5
  15. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  16. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  17. package/packages/datadog-instrumentations/src/dns.js +2 -1
  18. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  19. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  20. package/packages/datadog-instrumentations/src/helpers/hooks.js +10 -2
  21. package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
  22. package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
  23. package/packages/datadog-instrumentations/src/http/client.js +12 -2
  24. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  25. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  26. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  27. package/packages/datadog-instrumentations/src/jest.js +12 -6
  28. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  29. package/packages/datadog-instrumentations/src/net.js +10 -2
  30. package/packages/datadog-instrumentations/src/next.js +18 -6
  31. package/packages/datadog-instrumentations/src/restify.js +14 -1
  32. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  33. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  34. package/packages/datadog-plugin-cucumber/src/index.js +34 -2
  35. package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
  36. package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
  37. package/packages/datadog-plugin-http/src/client.js +19 -2
  38. package/packages/datadog-plugin-jest/src/index.js +38 -4
  39. package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
  40. package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
  41. package/packages/datadog-plugin-mocha/src/index.js +32 -1
  42. package/packages/datadog-plugin-next/src/index.js +40 -14
  43. package/packages/datadog-plugin-playwright/src/index.js +17 -1
  44. package/packages/dd-trace/src/appsec/activation.js +29 -0
  45. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  46. package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
  47. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  48. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  49. package/packages/dd-trace/src/appsec/channels.js +5 -2
  50. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  51. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  52. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  53. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  54. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  55. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  56. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
  57. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
  58. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  59. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  60. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  61. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  62. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  63. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  64. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  65. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  66. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  67. package/packages/dd-trace/src/appsec/index.js +33 -32
  68. package/packages/dd-trace/src/appsec/recommended.json +1737 -120
  69. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
  70. package/packages/dd-trace/src/appsec/remote_config/index.js +40 -15
  71. package/packages/dd-trace/src/appsec/reporter.js +50 -34
  72. package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
  73. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  74. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
  75. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  77. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  78. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
  79. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +110 -59
  80. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +40 -7
  81. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
  82. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  83. package/packages/dd-trace/src/config.js +145 -63
  84. package/packages/dd-trace/src/datastreams/processor.js +166 -26
  85. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
  86. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  87. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  88. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  89. package/packages/dd-trace/src/format.js +6 -1
  90. package/packages/dd-trace/src/id.js +12 -0
  91. package/packages/dd-trace/src/iitm.js +1 -1
  92. package/packages/dd-trace/src/log/channels.js +1 -1
  93. package/packages/dd-trace/src/noop/proxy.js +4 -0
  94. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  95. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  96. package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
  97. package/packages/dd-trace/src/opentracing/span.js +6 -0
  98. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  99. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  100. package/packages/dd-trace/src/plugin_manager.js +1 -1
  101. package/packages/dd-trace/src/plugins/ci_plugin.js +46 -9
  102. package/packages/dd-trace/src/plugins/database.js +1 -1
  103. package/packages/dd-trace/src/plugins/index.js +6 -0
  104. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  105. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  106. package/packages/dd-trace/src/plugins/util/exec.js +23 -2
  107. package/packages/dd-trace/src/plugins/util/git.js +98 -22
  108. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  109. package/packages/dd-trace/src/plugins/util/test.js +3 -2
  110. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  111. package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
  112. package/packages/dd-trace/src/priority_sampler.js +30 -38
  113. package/packages/dd-trace/src/profiler.js +5 -3
  114. package/packages/dd-trace/src/profiling/config.js +26 -2
  115. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
  116. package/packages/dd-trace/src/profiling/profiler.js +17 -10
  117. package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
  118. package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
  119. package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
  120. package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
  121. package/packages/dd-trace/src/proxy.js +25 -1
  122. package/packages/dd-trace/src/ritm.js +1 -1
  123. package/packages/dd-trace/src/sampling_rule.js +130 -0
  124. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  125. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  126. package/packages/dd-trace/src/span_processor.js +4 -0
  127. package/packages/dd-trace/src/span_sampler.js +6 -64
  128. package/packages/dd-trace/src/spanleak.js +98 -0
  129. package/packages/dd-trace/src/startup-log.js +7 -1
  130. package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
  131. package/packages/dd-trace/src/telemetry/index.js +171 -41
  132. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  133. package/packages/dd-trace/src/telemetry/send-data.js +47 -5
  134. package/packages/dd-trace/src/tracer.js +8 -2
  135. package/scripts/install_plugin_modules.js +11 -3
  136. package/packages/diagnostics_channel/index.js +0 -3
  137. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -9,5 +9,10 @@ module.exports = {
9
9
  ASM_USER_BLOCKING: 1n << 7n,
10
10
  ASM_CUSTOM_RULES: 1n << 8n,
11
11
  ASM_CUSTOM_BLOCKING_RESPONSE: 1n << 9n,
12
- ASM_TRUSTED_IPS: 1n << 10n
12
+ ASM_TRUSTED_IPS: 1n << 10n,
13
+ ASM_API_SECURITY_SAMPLE_RATE: 1n << 11n,
14
+ APM_TRACING_SAMPLE_RATE: 1n << 12n,
15
+ APM_TRACING_LOGS_INJECTION: 1n << 13n,
16
+ APM_TRACING_HTTP_HEADER_TAGS: 1n << 14n,
17
+ APM_TRACING_CUSTOM_TAGS: 1n << 15n
13
18
  }
@@ -1,38 +1,63 @@
1
1
  'use strict'
2
2
 
3
+ const Activation = require('../activation')
4
+
3
5
  const RemoteConfigManager = require('./manager')
4
6
  const RemoteConfigCapabilities = require('./capabilities')
7
+ const apiSecuritySampler = require('../api_security_sampler')
5
8
 
6
9
  let rc
7
10
 
8
11
  function enable (config) {
9
12
  rc = new RemoteConfigManager(config)
13
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_CUSTOM_TAGS, true)
14
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_HTTP_HEADER_TAGS, true)
15
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_LOGS_INJECTION, true)
16
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RATE, true)
17
+
18
+ const activation = Activation.fromConfig(config)
10
19
 
11
- if (config.appsec.enabled === undefined) { // only activate ASM_FEATURES when conf is not set locally
12
- rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
20
+ if (activation !== Activation.DISABLED) {
21
+ if (activation === Activation.ONECLICK) {
22
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
23
+ }
13
24
 
14
- rc.on('ASM_FEATURES', (action, conf) => {
15
- if (conf && conf.asm && typeof conf.asm.enabled === 'boolean') {
16
- let shouldEnable
25
+ if (config.appsec.apiSecurity?.enabled) {
26
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_API_SECURITY_SAMPLE_RATE, true)
27
+ }
17
28
 
18
- if (action === 'apply' || action === 'modify') {
19
- shouldEnable = conf.asm.enabled // take control
20
- } else {
21
- shouldEnable = config.appsec.enabled // give back control to local config
22
- }
29
+ rc.on('ASM_FEATURES', (action, rcConfig) => {
30
+ if (!rcConfig) return
23
31
 
24
- if (shouldEnable) {
25
- require('..').enable(config)
26
- } else {
27
- require('..').disable()
28
- }
32
+ if (activation === Activation.ONECLICK) {
33
+ enableOrDisableAppsec(action, rcConfig, config)
29
34
  }
35
+
36
+ apiSecuritySampler.setRequestSampling(rcConfig.api_security?.request_sample_rate)
30
37
  })
31
38
  }
32
39
 
33
40
  return rc
34
41
  }
35
42
 
43
+ function enableOrDisableAppsec (action, rcConfig, config) {
44
+ if (typeof rcConfig.asm?.enabled === 'boolean') {
45
+ let shouldEnable
46
+
47
+ if (action === 'apply' || action === 'modify') {
48
+ shouldEnable = rcConfig.asm.enabled // take control
49
+ } else {
50
+ shouldEnable = config.appsec.enabled // give back control to local config
51
+ }
52
+
53
+ if (shouldEnable) {
54
+ require('..').enable(config)
55
+ } else {
56
+ require('..').disable()
57
+ }
58
+ }
59
+ }
60
+
36
61
  function enableWafUpdate (appsecConfig) {
37
62
  if (rc && appsecConfig && !appsecConfig.customRulesProvided) {
38
63
  // dirty require to make startup faster for serverless
@@ -3,64 +3,61 @@
3
3
  const Limiter = require('../rate_limiter')
4
4
  const { storage } = require('../../../datadog-core')
5
5
  const web = require('../plugins/util/web')
6
+ const { ipHeaderList } = require('../plugins/util/ip_extractor')
6
7
  const {
7
8
  incrementWafInitMetric,
8
9
  updateWafRequestsMetricTags,
9
10
  incrementWafUpdatesMetric,
10
11
  incrementWafRequestsMetric
11
12
  } = require('./telemetry')
13
+ const zlib = require('zlib')
12
14
 
13
15
  // default limiter, configurable with setRateLimit()
14
16
  let limiter = new Limiter(100)
15
17
 
16
- // TODO: use precomputed maps instead
17
- const REQUEST_HEADERS_PASSLIST = [
18
- 'accept',
19
- 'accept-encoding',
20
- 'accept-language',
18
+ const metricsQueue = new Map()
19
+
20
+ const contentHeaderList = [
21
21
  'content-encoding',
22
22
  'content-language',
23
23
  'content-length',
24
- 'content-type',
25
- 'forwarded',
26
- 'forwarded-for',
24
+ 'content-type'
25
+ ]
26
+
27
+ const REQUEST_HEADERS_MAP = mapHeaderAndTags([
28
+ 'accept',
29
+ 'accept-encoding',
30
+ 'accept-language',
27
31
  'host',
28
- 'true-client-ip',
29
32
  'user-agent',
33
+ 'forwarded',
30
34
  'via',
31
- 'x-client-ip',
32
- 'x-cluster-client-ip',
33
- 'x-forwarded',
34
- 'x-forwarded-for',
35
- 'x-real-ip'
36
- ]
37
35
 
38
- const RESPONSE_HEADERS_PASSLIST = [
39
- 'content-encoding',
40
- 'content-language',
41
- 'content-length',
42
- 'content-type'
43
- ]
36
+ ...ipHeaderList,
37
+ ...contentHeaderList
38
+ ], 'http.request.headers.')
44
39
 
45
- const metricsQueue = new Map()
40
+ const RESPONSE_HEADERS_MAP = mapHeaderAndTags(contentHeaderList, 'http.response.headers.')
46
41
 
47
- function filterHeaders (headers, passlist, prefix) {
42
+ function mapHeaderAndTags (headerList, tagPrefix) {
43
+ return new Map(headerList.map(headerName => [headerName, `${tagPrefix}${formatHeaderName(headerName)}`]))
44
+ }
45
+
46
+ function filterHeaders (headers, map) {
48
47
  const result = {}
49
48
 
50
49
  if (!headers) return result
51
50
 
52
- for (let i = 0; i < passlist.length; ++i) {
53
- const headerName = passlist[i]
54
-
55
- if (headers[headerName]) {
56
- result[`${prefix}${formatHeaderName(headerName)}`] = '' + headers[headerName]
51
+ for (const [headerName, tagName] of map) {
52
+ const headerValue = headers[headerName]
53
+ if (headerValue) {
54
+ result[tagName] = '' + headerValue
57
55
  }
58
56
  }
59
57
 
60
58
  return result
61
59
  }
62
60
 
63
- // TODO: this can be precomputed at start time
64
61
  function formatHeaderName (name) {
65
62
  return name
66
63
  .trim()
@@ -86,7 +83,7 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
86
83
  function reportMetrics (metrics) {
87
84
  // TODO: metrics should be incremental, there already is an RFC to report metrics
88
85
  const store = storage.getStore()
89
- const rootSpan = store && store.req && web.root(store.req)
86
+ const rootSpan = store?.req && web.root(store.req)
90
87
  if (!rootSpan) return
91
88
 
92
89
  if (metrics.duration) {
@@ -106,13 +103,13 @@ function reportMetrics (metrics) {
106
103
 
107
104
  function reportAttack (attackData) {
108
105
  const store = storage.getStore()
109
- const req = store && store.req
106
+ const req = store?.req
110
107
  const rootSpan = web.root(req)
111
108
  if (!rootSpan) return
112
109
 
113
110
  const currentTags = rootSpan.context()._tags
114
111
 
115
- const newTags = filterHeaders(req.headers, REQUEST_HEADERS_PASSLIST, 'http.request.headers.')
112
+ const newTags = filterHeaders(req.headers, REQUEST_HEADERS_MAP)
116
113
 
117
114
  newTags['appsec.event'] = 'true'
118
115
 
@@ -144,6 +141,23 @@ function reportAttack (attackData) {
144
141
  rootSpan.addTags(newTags)
145
142
  }
146
143
 
144
+ function reportSchemas (derivatives) {
145
+ if (!derivatives) return
146
+
147
+ const req = storage.getStore()?.req
148
+ const rootSpan = web.root(req)
149
+
150
+ if (!rootSpan) return
151
+
152
+ const tags = {}
153
+ for (const [address, value] of Object.entries(derivatives)) {
154
+ const gzippedValue = zlib.gzipSync(JSON.stringify(value))
155
+ tags[address] = gzippedValue.toString('base64')
156
+ }
157
+
158
+ rootSpan.addTags(tags)
159
+ }
160
+
147
161
  function finishRequest (req, res) {
148
162
  const rootSpan = web.root(req)
149
163
  if (!rootSpan) return
@@ -158,7 +172,7 @@ function finishRequest (req, res) {
158
172
 
159
173
  if (!rootSpan.context()._tags['appsec.event']) return
160
174
 
161
- const newTags = filterHeaders(res.getHeaders(), RESPONSE_HEADERS_PASSLIST, 'http.response.headers.')
175
+ const newTags = filterHeaders(res.getHeaders(), RESPONSE_HEADERS_MAP)
162
176
 
163
177
  if (req.route && typeof req.route.path === 'string') {
164
178
  newTags['http.endpoint'] = req.route.path
@@ -179,6 +193,8 @@ module.exports = {
179
193
  reportMetrics,
180
194
  reportAttack,
181
195
  reportWafUpdate: incrementWafUpdatesMetric,
196
+ reportSchemas,
182
197
  finishRequest,
183
- setRateLimit
198
+ setRateLimit,
199
+ mapHeaderAndTags
184
200
  }
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const fs = require('fs')
3
4
  const waf = require('./waf')
4
5
  const { ACKNOWLEDGED, ERROR } = require('./remote_config/apply_states')
5
6
  const blocking = require('./blocking')
@@ -13,13 +14,15 @@ let appliedExclusions = new Map()
13
14
  let appliedCustomRules = new Map()
14
15
  let appliedActions = new Map()
15
16
 
16
- function applyRules (rules, config) {
17
- defaultRules = rules
17
+ function loadRules (config) {
18
+ defaultRules = config.rules
19
+ ? JSON.parse(fs.readFileSync(config.rules))
20
+ : require('./recommended.json')
18
21
 
19
- waf.init(rules, config)
22
+ waf.init(defaultRules, config)
20
23
 
21
- if (rules.actions) {
22
- blocking.updateBlockingConfiguration(rules.actions.find(action => action.id === 'block'))
24
+ if (defaultRules.actions) {
25
+ blocking.updateBlockingConfiguration(defaultRules.actions.find(action => action.id === 'block'))
23
26
  }
24
27
  }
25
28
 
@@ -252,7 +255,7 @@ function clearAllRules () {
252
255
  }
253
256
 
254
257
  module.exports = {
255
- applyRules,
258
+ loadRules,
256
259
  updateWafFromRC,
257
260
  clearAllRules
258
261
  }
@@ -9,7 +9,7 @@ const { setUserTags } = require('./set_user')
9
9
  const log = require('../../log')
10
10
 
11
11
  function isUserBlocked (user) {
12
- const actions = waf.run({ [USER_ID]: user.id })
12
+ const actions = waf.run({ persistent: { [USER_ID]: user.id } })
13
13
 
14
14
  if (!actions) return false
15
15
 
@@ -10,37 +10,50 @@ const preventDuplicateAddresses = new Set([
10
10
  ])
11
11
 
12
12
  class WAFContextWrapper {
13
- constructor (ddwafContext, requiredAddresses, wafTimeout, wafVersion, rulesVersion) {
13
+ constructor (ddwafContext, wafTimeout, wafVersion, rulesVersion) {
14
14
  this.ddwafContext = ddwafContext
15
- this.requiredAddresses = requiredAddresses
16
15
  this.wafTimeout = wafTimeout
17
16
  this.wafVersion = wafVersion
18
17
  this.rulesVersion = rulesVersion
19
18
  this.addressesToSkip = new Set()
20
19
  }
21
20
 
22
- run (params) {
21
+ run ({ persistent, ephemeral }) {
22
+ const payload = {}
23
+ let payloadHasData = false
23
24
  const inputs = {}
24
- let someInputAdded = false
25
25
  const newAddressesToSkip = new Set(this.addressesToSkip)
26
26
 
27
- // TODO: possible optimizaion: only send params that haven't already been sent with same value to this wafContext
28
- for (const key of Object.keys(params)) {
29
- if (this.requiredAddresses.has(key) && !this.addressesToSkip.has(key)) {
30
- inputs[key] = params[key]
31
- if (preventDuplicateAddresses.has(key)) {
32
- newAddressesToSkip.add(key)
27
+ if (persistent && typeof persistent === 'object') {
28
+ // TODO: possible optimization: only send params that haven't already been sent with same value to this wafContext
29
+ for (const key of Object.keys(persistent)) {
30
+ // TODO: requiredAddresses is no longer used due to processor addresses are not included in the list. Check on
31
+ // future versions when the actual addresses are included in the 'loaded' section inside diagnostics.
32
+ if (!this.addressesToSkip.has(key)) {
33
+ inputs[key] = persistent[key]
34
+ if (preventDuplicateAddresses.has(key)) {
35
+ newAddressesToSkip.add(key)
36
+ }
33
37
  }
34
- someInputAdded = true
35
38
  }
36
39
  }
37
40
 
38
- if (!someInputAdded) return
41
+ if (Object.keys(inputs).length) {
42
+ payload['persistent'] = inputs
43
+ payloadHasData = true
44
+ }
45
+
46
+ if (ephemeral && Object.keys(ephemeral).length) {
47
+ payload['ephemeral'] = ephemeral
48
+ payloadHasData = true
49
+ }
50
+
51
+ if (!payloadHasData) return
39
52
 
40
53
  try {
41
54
  const start = process.hrtime.bigint()
42
55
 
43
- const result = this.ddwafContext.run(inputs, this.wafTimeout)
56
+ const result = this.ddwafContext.run(payload, this.wafTimeout)
44
57
 
45
58
  const end = process.hrtime.bigint()
46
59
 
@@ -63,6 +76,8 @@ class WAFContextWrapper {
63
76
  Reporter.reportAttack(JSON.stringify(result.events))
64
77
  }
65
78
 
79
+ Reporter.reportSchemas(result.derivatives)
80
+
66
81
  return result.actions
67
82
  } catch (err) {
68
83
  log.error('Error while running the AppSec WAF')
@@ -37,7 +37,6 @@ class WAFManager {
37
37
  if (!wafContext) {
38
38
  wafContext = new WAFContextWrapper(
39
39
  this.ddwaf.createContext(),
40
- this.ddwaf.requiredAddresses,
41
40
  this.wafTimeout,
42
41
  this.ddwafVersion,
43
42
  this.rulesVersion
@@ -5,6 +5,16 @@ const { safeJSONStringify } = require('../../../exporters/common/util')
5
5
 
6
6
  const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
7
7
  const BaseWriter = require('../../../exporters/common/writer')
8
+ const {
9
+ incrementCountMetric,
10
+ distributionMetric,
11
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS,
12
+ TELEMETRY_ENDPOINT_PAYLOAD_BYTES,
13
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
14
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
15
+ TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
16
+ getErrorTypeFromStatusCode
17
+ } = require('../../../ci-visibility/telemetry')
8
18
 
9
19
  class Writer extends BaseWriter {
10
20
  constructor ({ url, evpProxyPrefix = '' }) {
@@ -34,8 +44,27 @@ class Writer extends BaseWriter {
34
44
 
35
45
  log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
36
46
 
37
- request(form, options, (err, res) => {
47
+ const startRequestTime = Date.now()
48
+
49
+ incrementCountMetric(TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS, { endpoint: 'code_coverage' })
50
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_BYTES, { endpoint: 'code_coverage' }, form.size())
51
+
52
+ request(form, options, (err, res, statusCode) => {
53
+ distributionMetric(
54
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
55
+ { endpoint: 'code_coverage' },
56
+ Date.now() - startRequestTime
57
+ )
38
58
  if (err) {
59
+ const errorType = getErrorTypeFromStatusCode(statusCode)
60
+ incrementCountMetric(
61
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
62
+ { endpoint: 'code_coverage', errorType }
63
+ )
64
+ incrementCountMetric(
65
+ TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
66
+ { endpoint: 'code_coverage' }
67
+ )
39
68
  log.error(err)
40
69
  done()
41
70
  return
@@ -5,6 +5,16 @@ const log = require('../../../log')
5
5
 
6
6
  const { AgentlessCiVisibilityEncoder } = require('../../../encode/agentless-ci-visibility')
7
7
  const BaseWriter = require('../../../exporters/common/writer')
8
+ const {
9
+ incrementCountMetric,
10
+ distributionMetric,
11
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS,
12
+ TELEMETRY_ENDPOINT_PAYLOAD_BYTES,
13
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
14
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
15
+ TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
16
+ getErrorTypeFromStatusCode
17
+ } = require('../../../ci-visibility/telemetry')
8
18
 
9
19
  class Writer extends BaseWriter {
10
20
  constructor ({ url, tags, evpProxyPrefix = '' }) {
@@ -35,8 +45,27 @@ class Writer extends BaseWriter {
35
45
 
36
46
  log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
37
47
 
38
- request(data, options, (err, res) => {
48
+ const startRequestTime = Date.now()
49
+
50
+ incrementCountMetric(TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS, { endpoint: 'test_cycle' })
51
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_BYTES, { endpoint: 'test_cycle' }, data.length)
52
+
53
+ request(data, options, (err, res, statusCode) => {
54
+ distributionMetric(
55
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
56
+ { endpoint: 'test_cycle' },
57
+ Date.now() - startRequestTime
58
+ )
39
59
  if (err) {
60
+ const errorType = getErrorTypeFromStatusCode(statusCode)
61
+ incrementCountMetric(
62
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
63
+ { endpoint: 'test_cycle', errorType }
64
+ )
65
+ incrementCountMetric(
66
+ TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
67
+ { endpoint: 'test_cycle' }
68
+ )
40
69
  log.error(err)
41
70
  done()
42
71
  return
@@ -143,7 +143,23 @@ class CiVisibilityExporter extends AgentInfoExporter {
143
143
  * where the tests run in a subprocess, because `getItrConfiguration` is called only once.
144
144
  */
145
145
  this._itrConfig = itrConfig
146
- callback(err, itrConfig)
146
+
147
+ if (err) {
148
+ callback(err, {})
149
+ } else if (itrConfig?.requireGit) {
150
+ // If the backend requires git, we'll wait for the upload to finish and request settings again
151
+ this._gitUploadPromise.then(gitUploadError => {
152
+ if (gitUploadError) {
153
+ return callback(gitUploadError, {})
154
+ }
155
+ getItrConfigurationRequest(configuration, (err, finalItrConfig) => {
156
+ this._itrConfig = finalItrConfig
157
+ callback(err, finalItrConfig)
158
+ })
159
+ })
160
+ } else {
161
+ callback(null, itrConfig)
162
+ }
147
163
  })
148
164
  })
149
165
  }