dd-trace 3.12.1 → 3.15.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 (101) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/README.md +5 -5
  3. package/ci/init.js +3 -1
  4. package/index.d.ts +100 -1
  5. package/package.json +5 -4
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
  7. package/packages/datadog-instrumentations/src/cucumber.js +74 -15
  8. package/packages/datadog-instrumentations/src/cypress.js +1 -1
  9. package/packages/datadog-instrumentations/src/fs.js +358 -0
  10. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  11. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  12. package/packages/datadog-instrumentations/src/jest.js +24 -23
  13. package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
  14. package/packages/datadog-instrumentations/src/mocha.js +10 -7
  15. package/packages/datadog-instrumentations/src/mongoose.js +1 -1
  16. package/packages/datadog-instrumentations/src/mysql.js +7 -1
  17. package/packages/datadog-instrumentations/src/mysql2.js +7 -1
  18. package/packages/datadog-instrumentations/src/next.js +2 -1
  19. package/packages/datadog-instrumentations/src/playwright.js +263 -0
  20. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
  21. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
  22. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
  23. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
  24. package/packages/datadog-plugin-cucumber/src/index.js +42 -11
  25. package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
  26. package/packages/datadog-plugin-cypress/src/support.js +5 -0
  27. package/packages/datadog-plugin-fs/src/index.js +45 -0
  28. package/packages/datadog-plugin-hapi/src/index.js +5 -1
  29. package/packages/datadog-plugin-http/src/server.js +1 -1
  30. package/packages/datadog-plugin-http2/src/server.js +1 -1
  31. package/packages/datadog-plugin-jest/src/index.js +40 -70
  32. package/packages/datadog-plugin-mocha/src/index.js +44 -64
  33. package/packages/datadog-plugin-mysql/src/index.js +8 -7
  34. package/packages/datadog-plugin-playwright/src/index.js +112 -0
  35. package/packages/datadog-shimmer/src/shimmer.js +28 -11
  36. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  37. package/packages/dd-trace/src/appsec/blocking.js +35 -9
  38. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
  39. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  40. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
  41. package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
  42. package/packages/dd-trace/src/appsec/iast/index.js +3 -2
  43. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -2
  44. package/packages/dd-trace/src/appsec/index.js +5 -5
  45. package/packages/dd-trace/src/appsec/recommended.json +320 -184
  46. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  47. package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
  48. package/packages/dd-trace/src/appsec/reporter.js +14 -14
  49. package/packages/dd-trace/src/appsec/sdk/index.js +41 -0
  50. package/packages/dd-trace/src/appsec/sdk/noop.js +17 -0
  51. package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
  52. package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
  53. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
  54. package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
  55. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
  56. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
  57. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -11
  58. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -1
  59. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
  60. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
  61. package/packages/dd-trace/src/config.js +63 -7
  62. package/packages/dd-trace/src/encode/0.4.js +1 -1
  63. package/packages/dd-trace/src/encode/0.5.js +1 -1
  64. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
  65. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
  66. package/packages/dd-trace/src/encode/tags-processors.js +3 -2
  67. package/packages/dd-trace/src/exporters/common/request.js +10 -3
  68. package/packages/dd-trace/src/lambda/handler.js +5 -6
  69. package/packages/dd-trace/src/log/channels.js +47 -0
  70. package/packages/dd-trace/src/log/index.js +79 -0
  71. package/packages/dd-trace/src/log/writer.js +124 -0
  72. package/packages/dd-trace/src/metrics.js +18 -0
  73. package/packages/dd-trace/src/noop/proxy.js +5 -2
  74. package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
  75. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
  76. package/packages/dd-trace/src/opentracing/span.js +2 -1
  77. package/packages/dd-trace/src/opentracing/span_context.js +6 -3
  78. package/packages/dd-trace/src/plugins/ci_plugin.js +72 -12
  79. package/packages/dd-trace/src/plugins/index.js +2 -0
  80. package/packages/dd-trace/src/plugins/util/ci.js +13 -21
  81. package/packages/dd-trace/src/plugins/util/exec.js +2 -2
  82. package/packages/dd-trace/src/plugins/util/git.js +16 -1
  83. package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
  84. package/packages/dd-trace/src/plugins/util/test.js +53 -10
  85. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
  86. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  87. package/packages/dd-trace/src/profiler.js +3 -0
  88. package/packages/dd-trace/src/profiling/config.js +8 -3
  89. package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
  90. package/packages/dd-trace/src/profiling/profiler.js +23 -6
  91. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
  92. package/packages/dd-trace/src/proxy.js +2 -0
  93. package/packages/dd-trace/src/span_processor.js +1 -1
  94. package/packages/dd-trace/src/span_sampler.js +68 -52
  95. package/packages/dd-trace/src/startup-log.js +3 -6
  96. package/packages/dd-trace/src/telemetry/index.js +23 -2
  97. package/packages/dd-trace/src/telemetry/send-data.js +4 -1
  98. package/packages/dd-trace/src/tracer.js +0 -16
  99. package/scripts/check-proposal-labels.js +71 -0
  100. package/packages/dd-trace/src/log.js +0 -143
  101. /package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
@@ -3,5 +3,6 @@
3
3
  module.exports = {
4
4
  ASM_ACTIVATION: 1n << 1n,
5
5
  ASM_IP_BLOCKING: 1n << 2n,
6
- ASM_DD_RULES: 1n << 3n
6
+ ASM_DD_RULES: 1n << 3n,
7
+ ASM_USER_BLOCKING: 1n << 7n
7
8
  }
@@ -35,12 +35,15 @@ function enable (config) {
35
35
  function enableAsmData (appsecConfig) {
36
36
  if (rc && appsecConfig && appsecConfig.rules === undefined) {
37
37
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, true)
38
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, true)
38
39
  rc.on('ASM_DATA', _asmDataListener)
39
40
  }
40
41
  }
41
42
 
42
43
  function disableAsmData () {
43
44
  if (rc) {
45
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, false)
46
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, false)
44
47
  rc.off('ASM_DATA', _asmDataListener)
45
48
  }
46
49
  }
@@ -86,28 +86,28 @@ function formatHeaderName (name) {
86
86
 
87
87
  function reportMetrics (metrics, store) {
88
88
  const req = store && store.get('req')
89
- const topSpan = web.root(req)
90
- if (!topSpan) return false
89
+ const rootSpan = web.root(req)
90
+ if (!rootSpan) return false
91
91
 
92
92
  if (metrics.duration) {
93
- topSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
93
+ rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
94
94
  }
95
95
 
96
96
  if (metrics.durationExt) {
97
- topSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
97
+ rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
98
98
  }
99
99
 
100
100
  if (metrics.rulesVersion) {
101
- topSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
101
+ rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
102
102
  }
103
103
  }
104
104
 
105
105
  function reportAttack (attackData, store) {
106
106
  const req = store && store.get('req')
107
- const topSpan = web.root(req)
108
- if (!topSpan) return false
107
+ const rootSpan = web.root(req)
108
+ if (!rootSpan) return false
109
109
 
110
- const currentTags = topSpan.context()._tags
110
+ const currentTags = rootSpan.context()._tags
111
111
 
112
112
  const newTags = {
113
113
  'appsec.event': 'true'
@@ -146,20 +146,20 @@ function reportAttack (attackData, store) {
146
146
  newTags['network.client.ip'] = resolvedRequest.remote_ip
147
147
  }
148
148
 
149
- topSpan.addTags(newTags)
149
+ rootSpan.addTags(newTags)
150
150
  }
151
151
 
152
152
  function finishRequest (req, context) {
153
- const topSpan = web.root(req)
154
- if (!topSpan) return false
153
+ const rootSpan = web.root(req)
154
+ if (!rootSpan) return false
155
155
 
156
156
  if (metricsQueue.size) {
157
- topSpan.addTags(Object.fromEntries(metricsQueue))
157
+ rootSpan.addTags(Object.fromEntries(metricsQueue))
158
158
 
159
159
  metricsQueue.clear()
160
160
  }
161
161
 
162
- if (!context || !topSpan.context()._tags['appsec.event']) return false
162
+ if (!context || !rootSpan.context()._tags['appsec.event']) return false
163
163
 
164
164
  const resolvedResponse = resolveHTTPResponse(context)
165
165
 
@@ -169,7 +169,7 @@ function finishRequest (req, context) {
169
169
  newTags['http.endpoint'] = resolvedResponse.endpoint
170
170
  }
171
171
 
172
- topSpan.addTags(newTags)
172
+ rootSpan.addTags(newTags)
173
173
  }
174
174
 
175
175
  function setRateLimit (rateLimit) {
@@ -0,0 +1,41 @@
1
+ 'use strict'
2
+
3
+ const { trackUserLoginSuccessEvent, trackUserLoginFailureEvent, trackCustomEvent } = require('./track_event')
4
+ const { checkUserAndSetUser, blockRequest } = require('./user_blocking')
5
+ const { loadTemplates } = require('../blocking')
6
+ const { setUser } = require('./set_user')
7
+
8
+ class AppsecSdk {
9
+ constructor (tracer, config) {
10
+ this._tracer = tracer
11
+ if (config) {
12
+ loadTemplates(config)
13
+ }
14
+ }
15
+
16
+ trackUserLoginSuccessEvent (user, metadata) {
17
+ return trackUserLoginSuccessEvent(this._tracer, user, metadata)
18
+ }
19
+
20
+ trackUserLoginFailureEvent (userId, exists, metadata) {
21
+ return trackUserLoginFailureEvent(this._tracer, userId, exists, metadata)
22
+ }
23
+
24
+ trackCustomEvent (eventName, metadata) {
25
+ return trackCustomEvent(this._tracer, eventName, metadata)
26
+ }
27
+
28
+ isUserBlocked (user) {
29
+ return checkUserAndSetUser(this._tracer, user)
30
+ }
31
+
32
+ blockRequest (req, res) {
33
+ return blockRequest(this._tracer, req, res)
34
+ }
35
+
36
+ setUser (user) {
37
+ return setUser(this._tracer, user)
38
+ }
39
+ }
40
+
41
+ module.exports = AppsecSdk
@@ -0,0 +1,17 @@
1
+ 'use strict'
2
+
3
+ class NoopAppsecSdk {
4
+ trackUserLoginSuccessEvent () {}
5
+
6
+ trackUserLoginFailureEvent () {}
7
+
8
+ trackCustomEvent () {}
9
+
10
+ isUserBlocked () {}
11
+
12
+ blockRequest () {}
13
+
14
+ setUser () {}
15
+ }
16
+
17
+ module.exports = NoopAppsecSdk
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ const { getRootSpan } = require('./utils')
4
+ const log = require('../../log')
5
+
6
+ function setUserTags (user, rootSpan) {
7
+ for (const k of Object.keys(user)) {
8
+ rootSpan.setTag(`usr.${k}`, '' + user[k])
9
+ }
10
+ }
11
+
12
+ function setUser (tracer, user) {
13
+ if (!user || !user.id) {
14
+ log.warn('Invalid user provided to setUser')
15
+ return
16
+ }
17
+
18
+ const rootSpan = getRootSpan(tracer)
19
+ if (!rootSpan) {
20
+ log.warn('Root span not available in setUser')
21
+ return
22
+ }
23
+
24
+ setUserTags(user, rootSpan)
25
+ }
26
+
27
+ module.exports = {
28
+ setUserTags,
29
+ setUser
30
+ }
@@ -0,0 +1,74 @@
1
+ 'use strict'
2
+
3
+ const log = require('../../log')
4
+ const { getRootSpan } = require('./utils')
5
+ const { MANUAL_KEEP } = require('../../../../../ext/tags')
6
+ const { setUserTags } = require('./set_user')
7
+
8
+ function trackUserLoginSuccessEvent (tracer, user, metadata) {
9
+ // TODO: better user check here and in _setUser() ?
10
+ if (!user || !user.id) {
11
+ log.warn('Invalid user provided to trackUserLoginSuccessEvent')
12
+ return
13
+ }
14
+
15
+ const rootSpan = getRootSpan(tracer)
16
+ if (!rootSpan) {
17
+ log.warn('Root span not available in trackUserLoginSuccessEvent')
18
+ return
19
+ }
20
+
21
+ setUserTags(user, rootSpan)
22
+
23
+ trackEvent(tracer, 'users.login.success', metadata, 'trackUserLoginSuccessEvent', rootSpan)
24
+ }
25
+
26
+ function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
27
+ if (!userId || typeof userId !== 'string') {
28
+ log.warn('Invalid userId provided to trackUserLoginFailureEvent')
29
+ return
30
+ }
31
+
32
+ const fields = {
33
+ 'usr.id': userId,
34
+ 'usr.exists': exists ? 'true' : 'false',
35
+ ...metadata
36
+ }
37
+
38
+ trackEvent(tracer, 'users.login.failure', fields, 'trackUserLoginFailureEvent')
39
+ }
40
+
41
+ function trackCustomEvent (tracer, eventName, metadata) {
42
+ if (!eventName || typeof eventName !== 'string') {
43
+ log.warn('Invalid eventName provided to trackCustomEvent')
44
+ return
45
+ }
46
+
47
+ trackEvent(tracer, eventName, metadata, 'trackCustomEvent')
48
+ }
49
+
50
+ function trackEvent (tracer, eventName, fields, sdkMethodName, rootSpan = getRootSpan(tracer)) {
51
+ if (!rootSpan) {
52
+ log.warn(`Root span not available in ${sdkMethodName}`)
53
+ return
54
+ }
55
+
56
+ const tags = {
57
+ [`appsec.events.${eventName}.track`]: 'true',
58
+ [MANUAL_KEEP]: 'true'
59
+ }
60
+
61
+ if (fields) {
62
+ for (const metadataKey of Object.keys(fields)) {
63
+ tags[`appsec.events.${eventName}.${metadataKey}`] = '' + fields[metadataKey]
64
+ }
65
+ }
66
+
67
+ rootSpan.addTags(tags)
68
+ }
69
+
70
+ module.exports = {
71
+ trackUserLoginSuccessEvent,
72
+ trackUserLoginFailureEvent,
73
+ trackCustomEvent
74
+ }
@@ -0,0 +1,73 @@
1
+ 'use strict'
2
+
3
+ const { USER_ID } = require('../addresses')
4
+ const Gateway = require('../gateway/engine')
5
+ const { getRootSpan } = require('./utils')
6
+ const { block } = require('../blocking')
7
+ const { storage } = require('../../../../datadog-core')
8
+ const { setUserTags } = require('./set_user')
9
+ const log = require('../../log')
10
+
11
+ function isUserBlocked (user) {
12
+ const results = Gateway.propagate({ [USER_ID]: user.id })
13
+
14
+ if (!results) {
15
+ return false
16
+ }
17
+
18
+ for (const entry of results) {
19
+ if (entry && entry.includes('block')) {
20
+ return true
21
+ }
22
+ }
23
+
24
+ return false
25
+ }
26
+
27
+ function checkUserAndSetUser (tracer, user) {
28
+ if (!user || !user.id) {
29
+ log.warn('Invalid user provided to isUserBlocked')
30
+ return false
31
+ }
32
+
33
+ const rootSpan = getRootSpan(tracer)
34
+ if (rootSpan) {
35
+ if (!rootSpan.context()._tags['usr.id']) {
36
+ setUserTags(user, rootSpan)
37
+ }
38
+ } else {
39
+ log.warn('Root span not available in isUserBlocked')
40
+ }
41
+
42
+ return isUserBlocked(user)
43
+ }
44
+
45
+ function blockRequest (tracer, req, res) {
46
+ if (!req || !res) {
47
+ const store = storage.getStore()
48
+ if (store) {
49
+ req = req || store.req
50
+ res = res || store.res
51
+ }
52
+ }
53
+
54
+ if (!req || !res) {
55
+ log.warn('Requests or response object not available in blockRequest')
56
+ return false
57
+ }
58
+
59
+ const rootSpan = getRootSpan(tracer)
60
+ if (!rootSpan) {
61
+ log.warn('Root span not available in blockRequest')
62
+ return false
63
+ }
64
+
65
+ block(req, res, rootSpan)
66
+
67
+ return true
68
+ }
69
+
70
+ module.exports = {
71
+ checkUserAndSetUser,
72
+ blockRequest
73
+ }
@@ -0,0 +1,10 @@
1
+ 'use strict'
2
+
3
+ function getRootSpan (tracer) {
4
+ const span = tracer.scope().active()
5
+ return span && span.context()._trace.started[0]
6
+ }
7
+
8
+ module.exports = {
9
+ getRootSpan
10
+ }
@@ -20,8 +20,7 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
20
20
  prioritySampler,
21
21
  lookup,
22
22
  protocolVersion,
23
- headers,
24
- isGitUploadEnabled
23
+ headers
25
24
  } = config
26
25
 
27
26
  this.getAgentInfo((err, agentInfo) => {
@@ -38,9 +37,6 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
38
37
  url: this._url,
39
38
  evpProxyPrefix: AGENT_EVP_PROXY_PATH
40
39
  })
41
- if (isGitUploadEnabled) {
42
- this.sendGitMetadata({ url: this._url, isEvpProxy: true })
43
- }
44
40
  } else {
45
41
  this._writer = new AgentWriter({
46
42
  url: this._url,
@@ -9,7 +9,7 @@ const log = require('../../../log')
9
9
  class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
10
10
  constructor (config) {
11
11
  super(config)
12
- const { tags, site, url, isGitUploadEnabled } = config
12
+ const { tags, site, url } = config
13
13
  // we don't need to request /info because we are using agentless by configuration
14
14
  this._isInitialized = true
15
15
  this._resolveCanUseCiVisProtocol(true)
@@ -21,10 +21,6 @@ class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
21
21
  this._coverageWriter = new CoverageWriter({ url: this._coverageUrl })
22
22
 
23
23
  this._apiUrl = url || new URL(`https://api.${site}`)
24
-
25
- if (isGitUploadEnabled) {
26
- this.sendGitMetadata({ url: this._getApiUrl() })
27
- }
28
24
  }
29
25
 
30
26
  setUrl (url, coverageUrl = url, apiUrl = url) {
@@ -8,12 +8,28 @@ const { getSkippableSuites: getSkippableSuitesRequest } = require('../intelligen
8
8
  const log = require('../../log')
9
9
  const AgentInfoExporter = require('../../exporters/common/agent-info-exporter')
10
10
 
11
+ function getTestConfigurationTags (tags) {
12
+ if (!tags) {
13
+ return {}
14
+ }
15
+ return Object.keys(tags).reduce((acc, key) => {
16
+ if (key.startsWith('test.configuration.')) {
17
+ const [, configKey] = key.split('test.configuration.')
18
+ acc[configKey] = tags[key]
19
+ }
20
+ return acc
21
+ }, {})
22
+ }
23
+
11
24
  function getIsTestSessionTrace (trace) {
12
25
  return trace.some(span =>
13
- span.type === 'test_session_end' || span.type === 'test_suite_end'
26
+ span.type === 'test_session_end' || span.type === 'test_suite_end' || span.type === 'test_module_end'
14
27
  )
15
28
  }
16
29
 
30
+ const GIT_UPLOAD_TIMEOUT = 60000 // 60 seconds
31
+ const CAN_USE_CI_VIS_PROTOCOL_TIMEOUT = GIT_UPLOAD_TIMEOUT
32
+
17
33
  class CiVisibilityExporter extends AgentInfoExporter {
18
34
  constructor (config) {
19
35
  super(config)
@@ -24,14 +40,24 @@ class CiVisibilityExporter extends AgentInfoExporter {
24
40
  // AKA CI Vis Protocol
25
41
  this._canUseCiVisProtocol = false
26
42
 
27
- // TODO: add timeout to reject this promise
43
+ const gitUploadTimeoutId = setTimeout(() => {
44
+ this._resolveGit(new Error('Timeout while uploading git metadata'))
45
+ }, GIT_UPLOAD_TIMEOUT).unref()
46
+
47
+ const canUseCiVisProtocolTimeoutId = setTimeout(() => {
48
+ this._resolveCanUseCiVisProtocol(false)
49
+ }, CAN_USE_CI_VIS_PROTOCOL_TIMEOUT).unref()
50
+
28
51
  this._gitUploadPromise = new Promise(resolve => {
29
- this._resolveGit = resolve
52
+ this._resolveGit = (err) => {
53
+ clearTimeout(gitUploadTimeoutId)
54
+ resolve(err)
55
+ }
30
56
  })
31
57
 
32
- // TODO: add timeout to reject this promise
33
58
  this._canUseCiVisProtocolPromise = new Promise(resolve => {
34
59
  this._resolveCanUseCiVisProtocol = (canUseCiVisProtocol) => {
60
+ clearTimeout(canUseCiVisProtocolTimeoutId)
35
61
  this._canUseCiVisProtocol = canUseCiVisProtocol
36
62
  resolve(canUseCiVisProtocol)
37
63
  }
@@ -82,6 +108,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
82
108
  env: this._config.env,
83
109
  service: this._config.service,
84
110
  isEvpProxy: !!this._isUsingEvpProxy,
111
+ custom: getTestConfigurationTags(this._config.tags),
85
112
  ...testConfiguration
86
113
  }
87
114
  getSkippableSuitesRequest(configuration, callback)
@@ -93,6 +120,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
93
120
  * CI Visibility Protocol, hence the this._canUseCiVisProtocol promise.
94
121
  */
95
122
  getItrConfiguration (testConfiguration, callback) {
123
+ this.sendGitMetadata()
96
124
  if (!this.shouldRequestItrConfiguration()) {
97
125
  return callback(null, {})
98
126
  }
@@ -105,6 +133,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
105
133
  env: this._config.env,
106
134
  service: this._config.service,
107
135
  isEvpProxy: !!this._isUsingEvpProxy,
136
+ custom: getTestConfigurationTags(this._config.tags),
108
137
  ...testConfiguration
109
138
  }
110
139
  getItrConfigurationRequest(configuration, (err, itrConfig) => {
@@ -118,14 +147,22 @@ class CiVisibilityExporter extends AgentInfoExporter {
118
147
  })
119
148
  }
120
149
 
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')
150
+ sendGitMetadata () {
151
+ if (!this._config.isGitUploadEnabled) {
152
+ return
153
+ }
154
+ this._canUseCiVisProtocolPromise.then((canUseCiVisProtocol) => {
155
+ if (!canUseCiVisProtocol) {
156
+ return
127
157
  }
128
- this._resolveGit(err)
158
+ sendGitMetadataRequest(this._getApiUrl(), !!this._isUsingEvpProxy, (err) => {
159
+ if (err) {
160
+ log.error(`Error uploading git metadata: ${err.message}`)
161
+ } else {
162
+ log.debug('Successfully uploaded git metadata')
163
+ }
164
+ this._resolveGit(err)
165
+ })
129
166
  })
130
167
  }
131
168
 
@@ -10,7 +10,9 @@ const {
10
10
  getLatestCommits,
11
11
  getRepositoryUrl,
12
12
  generatePackFilesForCommits,
13
- getCommitsToUpload
13
+ getCommitsToUpload,
14
+ isShallowRepository,
15
+ unshallowRepository
14
16
  } = require('../../../plugins/util/git')
15
17
 
16
18
  const isValidSha = (sha) => /[0-9a-f]{40}/.test(sha)
@@ -157,6 +159,10 @@ function sendGitMetadata (url, isEvpProxy, callback) {
157
159
  return callback(new Error('Repository URL is empty'))
158
160
  }
159
161
 
162
+ if (isShallowRepository()) {
163
+ unshallowRepository()
164
+ }
165
+
160
166
  getCommitsToExclude({ url, repositoryUrl, isEvpProxy }, (err, commitsToExclude, headCommit) => {
161
167
  if (err) {
162
168
  return callback(err)
@@ -13,7 +13,8 @@ function getItrConfiguration ({
13
13
  osArchitecture,
14
14
  runtimeName,
15
15
  runtimeVersion,
16
- branch
16
+ branch,
17
+ custom
17
18
  }, done) {
18
19
  const options = {
19
20
  path: '/api/v2/libraries/tests/services/setting',
@@ -53,7 +54,8 @@ function getItrConfiguration ({
53
54
  'os.version': osVersion,
54
55
  'os.architecture': osArchitecture,
55
56
  'runtime.name': runtimeName,
56
- 'runtime.version': runtimeVersion
57
+ 'runtime.version': runtimeVersion,
58
+ custom
57
59
  },
58
60
  service,
59
61
  env,
@@ -11,7 +11,8 @@ function getSkippableSuites ({
11
11
  osPlatform,
12
12
  osArchitecture,
13
13
  runtimeName,
14
- runtimeVersion
14
+ runtimeVersion,
15
+ custom
15
16
  }, done) {
16
17
  const options = {
17
18
  path: '/api/v2/ci/tests/skippable',
@@ -19,7 +20,7 @@ function getSkippableSuites ({
19
20
  headers: {
20
21
  'Content-Type': 'application/json'
21
22
  },
22
- timeout: 15000,
23
+ timeout: 20000,
23
24
  url
24
25
  }
25
26
 
@@ -51,7 +52,8 @@ function getSkippableSuites ({
51
52
  'os.version': osVersion,
52
53
  'os.architecture': osArchitecture,
53
54
  'runtime.name': runtimeName,
54
- 'runtime.version': runtimeVersion
55
+ 'runtime.version': runtimeVersion,
56
+ custom
55
57
  },
56
58
  service,
57
59
  env,
@@ -54,6 +54,32 @@ function remapify (input, mappings) {
54
54
  return output
55
55
  }
56
56
 
57
+ function propagationStyle (key, option, defaultValue) {
58
+ // Extract by key if in object-form value
59
+ if (typeof option === 'object' && !Array.isArray(option)) {
60
+ option = option[key]
61
+ }
62
+
63
+ // Should be an array at this point
64
+ if (Array.isArray(option)) return option.map(v => v.toLowerCase())
65
+
66
+ // If it's not an array but not undefined there's something wrong with the input
67
+ if (typeof option !== 'undefined') {
68
+ log.warn('Unexpected input for config.tracePropagationStyle')
69
+ }
70
+
71
+ // Otherwise, fallback to env var parsing
72
+ const envKey = `DD_TRACE_PROPAGATION_STYLE_${key.toUpperCase()}`
73
+ const envVar = coalesce(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE)
74
+ if (typeof envVar !== 'undefined') {
75
+ return envVar.split(',')
76
+ .filter(v => v !== '')
77
+ .map(v => v.trim().toLowerCase())
78
+ }
79
+
80
+ return defaultValue
81
+ }
82
+
57
83
  class Config {
58
84
  constructor (options) {
59
85
  options = options || {}
@@ -185,19 +211,46 @@ class Config {
185
211
  process.env.DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
186
212
  qsRegex
187
213
  )
214
+ const DD_TRACE_CLIENT_IP_ENABLED = coalesce(
215
+ options.clientIpEnabled,
216
+ process.env.DD_TRACE_CLIENT_IP_ENABLED && isTrue(process.env.DD_TRACE_CLIENT_IP_ENABLED),
217
+ false
218
+ )
188
219
  const DD_TRACE_CLIENT_IP_HEADER = coalesce(
220
+ options.clientIpHeader,
189
221
  process.env.DD_TRACE_CLIENT_IP_HEADER,
190
222
  null
191
223
  )
224
+ // TODO: Remove the experimental env vars as a major?
192
225
  const DD_TRACE_B3_ENABLED = coalesce(
193
226
  options.experimental && options.experimental.b3,
194
227
  process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
195
228
  false
196
229
  )
197
- const DD_TRACE_TRACEPARENT_ENABLED = coalesce(
198
- options.experimental && options.experimental.traceparent,
199
- process.env.DD_TRACE_EXPERIMENTAL_TRACEPARENT_ENABLED,
200
- false
230
+ const defaultPropagationStyle = ['tracecontext', 'datadog']
231
+ if (isTrue(DD_TRACE_B3_ENABLED)) {
232
+ defaultPropagationStyle.push('b3')
233
+ defaultPropagationStyle.push('b3 single header')
234
+ }
235
+ if (process.env.DD_TRACE_PROPAGATION_STYLE && (
236
+ process.env.DD_TRACE_PROPAGATION_STYLE_INJECT ||
237
+ process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT
238
+ )) {
239
+ log.warn(
240
+ 'Use either the DD_TRACE_PROPAGATION_STYLE environment variable or separate ' +
241
+ 'DD_TRACE_PROPAGATION_STYLE_INJECT and DD_TRACE_PROPAGATION_STYLE_EXTRACT ' +
242
+ 'environment variables'
243
+ )
244
+ }
245
+ const DD_TRACE_PROPAGATION_STYLE_INJECT = propagationStyle(
246
+ 'inject',
247
+ options.tracePropagationStyle,
248
+ defaultPropagationStyle
249
+ )
250
+ const DD_TRACE_PROPAGATION_STYLE_EXTRACT = propagationStyle(
251
+ 'extract',
252
+ options.tracePropagationStyle,
253
+ defaultPropagationStyle
201
254
  )
202
255
  const DD_TRACE_RUNTIME_ID_ENABLED = coalesce(
203
256
  options.experimental && options.experimental.runtimeId,
@@ -323,7 +376,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
323
376
 
324
377
  const DD_CIVISIBILITY_GIT_UPLOAD_ENABLED = coalesce(
325
378
  process.env.DD_CIVISIBILITY_GIT_UPLOAD_ENABLED,
326
- false
379
+ true
327
380
  )
328
381
 
329
382
  const ingestion = options.ingestion || {}
@@ -372,6 +425,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
372
425
  this.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
373
426
  this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
374
427
  this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
428
+ this.clientIpEnabled = DD_TRACE_CLIENT_IP_ENABLED
375
429
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
376
430
  this.plugins = !!coalesce(options.plugins, true)
377
431
  this.service = DD_SERVICE
@@ -382,9 +436,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
382
436
  port: String(coalesce(dogstatsd.port, process.env.DD_DOGSTATSD_PORT, 8125))
383
437
  }
384
438
  this.runtimeMetrics = isTrue(DD_RUNTIME_METRICS_ENABLED)
439
+ this.tracePropagationStyle = {
440
+ inject: DD_TRACE_PROPAGATION_STYLE_INJECT,
441
+ extract: DD_TRACE_PROPAGATION_STYLE_EXTRACT
442
+ }
385
443
  this.experimental = {
386
- b3: isTrue(DD_TRACE_B3_ENABLED),
387
- traceparent: isTrue(DD_TRACE_TRACEPARENT_ENABLED),
388
444
  runtimeId: isTrue(DD_TRACE_RUNTIME_ID_ENABLED),
389
445
  exporter: DD_TRACE_EXPORTER,
390
446
  enableGetRumData: isTrue(DD_TRACE_GET_RUM_DATA_ENABLED)