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.
- package/LICENSE-3rdparty.csv +1 -0
- package/README.md +5 -5
- package/ci/init.js +3 -1
- package/index.d.ts +100 -1
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
- package/packages/datadog-instrumentations/src/cucumber.js +74 -15
- package/packages/datadog-instrumentations/src/cypress.js +1 -1
- package/packages/datadog-instrumentations/src/fs.js +358 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +24 -23
- package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
- package/packages/datadog-instrumentations/src/mocha.js +10 -7
- package/packages/datadog-instrumentations/src/mongoose.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/next.js +2 -1
- package/packages/datadog-instrumentations/src/playwright.js +263 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
- package/packages/datadog-plugin-cucumber/src/index.js +42 -11
- package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
- package/packages/datadog-plugin-cypress/src/support.js +5 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-hapi/src/index.js +5 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +40 -70
- package/packages/datadog-plugin-mocha/src/index.js +44 -64
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +112 -0
- package/packages/datadog-shimmer/src/shimmer.js +28 -11
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +35 -9
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
- package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
- package/packages/dd-trace/src/appsec/iast/index.js +3 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -2
- package/packages/dd-trace/src/appsec/index.js +5 -5
- package/packages/dd-trace/src/appsec/recommended.json +320 -184
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
- package/packages/dd-trace/src/appsec/reporter.js +14 -14
- package/packages/dd-trace/src/appsec/sdk/index.js +41 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +17 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -11
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
- package/packages/dd-trace/src/config.js +63 -7
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/encode/0.5.js +1 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
- package/packages/dd-trace/src/encode/tags-processors.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +10 -3
- package/packages/dd-trace/src/lambda/handler.js +5 -6
- package/packages/dd-trace/src/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +124 -0
- package/packages/dd-trace/src/metrics.js +18 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
- package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
- package/packages/dd-trace/src/opentracing/span.js +2 -1
- package/packages/dd-trace/src/opentracing/span_context.js +6 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +72 -12
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/plugins/util/exec.js +2 -2
- package/packages/dd-trace/src/plugins/util/git.js +16 -1
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +53 -10
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/profiler.js +3 -0
- package/packages/dd-trace/src/profiling/config.js +8 -3
- package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
- package/packages/dd-trace/src/profiling/profiler.js +23 -6
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/proxy.js +2 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_sampler.js +68 -52
- package/packages/dd-trace/src/startup-log.js +3 -6
- package/packages/dd-trace/src/telemetry/index.js +23 -2
- package/packages/dd-trace/src/telemetry/send-data.js +4 -1
- package/packages/dd-trace/src/tracer.js +0 -16
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
- /package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
|
@@ -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
|
|
90
|
-
if (!
|
|
89
|
+
const rootSpan = web.root(req)
|
|
90
|
+
if (!rootSpan) return false
|
|
91
91
|
|
|
92
92
|
if (metrics.duration) {
|
|
93
|
-
|
|
93
|
+
rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
if (metrics.durationExt) {
|
|
97
|
-
|
|
97
|
+
rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
if (metrics.rulesVersion) {
|
|
101
|
-
|
|
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
|
|
108
|
-
if (!
|
|
107
|
+
const rootSpan = web.root(req)
|
|
108
|
+
if (!rootSpan) return false
|
|
109
109
|
|
|
110
|
-
const currentTags =
|
|
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
|
-
|
|
149
|
+
rootSpan.addTags(newTags)
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
function finishRequest (req, context) {
|
|
153
|
-
const
|
|
154
|
-
if (!
|
|
153
|
+
const rootSpan = web.root(req)
|
|
154
|
+
if (!rootSpan) return false
|
|
155
155
|
|
|
156
156
|
if (metricsQueue.size) {
|
|
157
|
-
|
|
157
|
+
rootSpan.addTags(Object.fromEntries(metricsQueue))
|
|
158
158
|
|
|
159
159
|
metricsQueue.clear()
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
if (!context || !
|
|
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
|
-
|
|
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
|
+
}
|
|
@@ -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
|
|
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
|
-
|
|
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 =
|
|
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 (
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
150
|
+
sendGitMetadata () {
|
|
151
|
+
if (!this._config.isGitUploadEnabled) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
this._canUseCiVisProtocolPromise.then((canUseCiVisProtocol) => {
|
|
155
|
+
if (!canUseCiVisProtocol) {
|
|
156
|
+
return
|
|
127
157
|
}
|
|
128
|
-
this.
|
|
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)
|
package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js
CHANGED
|
@@ -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:
|
|
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
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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)
|