dd-trace 4.18.0 → 4.22.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 +3 -2
- package/README.md +3 -3
- package/ext/kinds.d.ts +1 -0
- package/ext/kinds.js +2 -1
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +6 -1
- package/index.d.ts +29 -0
- package/package.json +11 -10
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/http/client.js +10 -0
- package/packages/datadog-instrumentations/src/jest.js +11 -5
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/next.js +18 -6
- package/packages/datadog-instrumentations/src/restify.js +14 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- package/packages/datadog-plugin-aerospike/src/index.js +113 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
- package/packages/dd-trace/src/appsec/blocking.js +95 -43
- package/packages/dd-trace/src/appsec/channels.js +5 -2
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +33 -32
- package/packages/dd-trace/src/appsec/recommended.json +1737 -120
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +36 -15
- package/packages/dd-trace/src/appsec/reporter.js +50 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +75 -56
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +22 -6
- package/packages/dd-trace/src/config.js +48 -7
- package/packages/dd-trace/src/datastreams/processor.js +166 -26
- package/packages/dd-trace/src/format.js +6 -1
- package/packages/dd-trace/src/id.js +12 -0
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +1 -1
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/opentelemetry/span.js +95 -2
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -0
- package/packages/dd-trace/src/opentracing/span_context.js +5 -2
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -1
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +6 -19
- package/packages/dd-trace/src/plugins/util/git.js +4 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +3 -2
- package/packages/dd-trace/src/plugins/util/url.js +26 -0
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +26 -2
- package/packages/dd-trace/src/profiling/profiler.js +17 -10
- package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
- package/packages/dd-trace/src/proxy.js +25 -1
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/span_processor.js +4 -0
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/startup-log.js +7 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
- package/packages/dd-trace/src/telemetry/index.js +136 -44
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +47 -5
- package/packages/dd-trace/src/tracer.js +8 -2
- package/scripts/install_plugin_modules.js +11 -3
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -1,38 +1,59 @@
|
|
|
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)
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
const activation = Activation.fromConfig(config)
|
|
15
|
+
|
|
16
|
+
if (activation !== Activation.DISABLED) {
|
|
17
|
+
if (activation === Activation.ONECLICK) {
|
|
18
|
+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
|
|
19
|
+
}
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
if (config.appsec.apiSecurity?.enabled) {
|
|
22
|
+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_API_SECURITY_SAMPLE_RATE, true)
|
|
23
|
+
}
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} else {
|
|
21
|
-
shouldEnable = config.appsec.enabled // give back control to local config
|
|
22
|
-
}
|
|
25
|
+
rc.on('ASM_FEATURES', (action, rcConfig) => {
|
|
26
|
+
if (!rcConfig) return
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} else {
|
|
27
|
-
require('..').disable()
|
|
28
|
-
}
|
|
28
|
+
if (activation === Activation.ONECLICK) {
|
|
29
|
+
enableOrDisableAppsec(action, rcConfig, config)
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
apiSecuritySampler.setRequestSampling(rcConfig.api_security?.request_sample_rate)
|
|
30
33
|
})
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
return rc
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
function enableOrDisableAppsec (action, rcConfig, config) {
|
|
40
|
+
if (typeof rcConfig.asm?.enabled === 'boolean') {
|
|
41
|
+
let shouldEnable
|
|
42
|
+
|
|
43
|
+
if (action === 'apply' || action === 'modify') {
|
|
44
|
+
shouldEnable = rcConfig.asm.enabled // take control
|
|
45
|
+
} else {
|
|
46
|
+
shouldEnable = config.appsec.enabled // give back control to local config
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (shouldEnable) {
|
|
50
|
+
require('..').enable(config)
|
|
51
|
+
} else {
|
|
52
|
+
require('..').disable()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
36
57
|
function enableWafUpdate (appsecConfig) {
|
|
37
58
|
if (rc && appsecConfig && !appsecConfig.customRulesProvided) {
|
|
38
59
|
// 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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'content-length',
|
|
42
|
-
'content-type'
|
|
43
|
-
]
|
|
36
|
+
...ipHeaderList,
|
|
37
|
+
...contentHeaderList
|
|
38
|
+
], 'http.request.headers.')
|
|
44
39
|
|
|
45
|
-
const
|
|
40
|
+
const RESPONSE_HEADERS_MAP = mapHeaderAndTags(contentHeaderList, 'http.response.headers.')
|
|
46
41
|
|
|
47
|
-
function
|
|
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 (
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
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
|
|
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,
|
|
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(),
|
|
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
|
|
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(
|
|
22
|
+
waf.init(defaultRules, config)
|
|
20
23
|
|
|
21
|
-
if (
|
|
22
|
-
blocking.updateBlockingConfiguration(
|
|
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
|
-
|
|
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,
|
|
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 (
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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 (
|
|
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(
|
|
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')
|
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -10,7 +10,7 @@ const {
|
|
|
10
10
|
getLatestCommits,
|
|
11
11
|
getRepositoryUrl,
|
|
12
12
|
generatePackFilesForCommits,
|
|
13
|
-
|
|
13
|
+
getCommitsRevList,
|
|
14
14
|
isShallowRepository,
|
|
15
15
|
unshallowRepository
|
|
16
16
|
} = require('../../../plugins/util/git')
|
|
@@ -46,11 +46,7 @@ function getCommonRequestOptions (url) {
|
|
|
46
46
|
* The response are the commits for which the backend already has information
|
|
47
47
|
* This response is used to know which commits can be ignored from there on
|
|
48
48
|
*/
|
|
49
|
-
function
|
|
50
|
-
const latestCommits = getLatestCommits()
|
|
51
|
-
|
|
52
|
-
log.debug(`There were ${latestCommits.length} commits since last month.`)
|
|
53
|
-
|
|
49
|
+
function getCommitsToUpload ({ url, repositoryUrl, latestCommits, isEvpProxy }, callback) {
|
|
54
50
|
const commonOptions = getCommonRequestOptions(url)
|
|
55
51
|
|
|
56
52
|
const options = {
|
|
@@ -83,13 +79,23 @@ function getCommitsToExclude ({ url, isEvpProxy, repositoryUrl }, callback) {
|
|
|
83
79
|
const error = new Error(`Error fetching commits to exclude: ${err.message}`)
|
|
84
80
|
return callback(error)
|
|
85
81
|
}
|
|
86
|
-
let
|
|
82
|
+
let alreadySeenCommits
|
|
87
83
|
try {
|
|
88
|
-
|
|
84
|
+
alreadySeenCommits = validateCommits(JSON.parse(response).data)
|
|
89
85
|
} catch (e) {
|
|
90
86
|
return callback(new Error(`Can't parse commits to exclude response: ${e.message}`))
|
|
91
87
|
}
|
|
92
|
-
|
|
88
|
+
log.debug(`There are ${alreadySeenCommits.length} commits to exclude.`)
|
|
89
|
+
const commitsToInclude = latestCommits.filter((commit) => !alreadySeenCommits.includes(commit))
|
|
90
|
+
log.debug(`There are ${commitsToInclude.length} commits to include.`)
|
|
91
|
+
|
|
92
|
+
if (!commitsToInclude.length) {
|
|
93
|
+
return callback(null, [])
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const commitsToUpload = getCommitsRevList(alreadySeenCommits, commitsToInclude)
|
|
97
|
+
|
|
98
|
+
callback(null, commitsToUpload)
|
|
93
99
|
})
|
|
94
100
|
}
|
|
95
101
|
|
|
@@ -150,6 +156,53 @@ function uploadPackFile ({ url, isEvpProxy, packFileToUpload, repositoryUrl, hea
|
|
|
150
156
|
})
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
function generateAndUploadPackFiles ({
|
|
160
|
+
url,
|
|
161
|
+
isEvpProxy,
|
|
162
|
+
commitsToUpload,
|
|
163
|
+
repositoryUrl,
|
|
164
|
+
headCommit
|
|
165
|
+
}, callback) {
|
|
166
|
+
log.debug(`There are ${commitsToUpload.length} commits to upload`)
|
|
167
|
+
|
|
168
|
+
const packFilesToUpload = generatePackFilesForCommits(commitsToUpload)
|
|
169
|
+
|
|
170
|
+
log.debug(`Uploading ${packFilesToUpload.length} packfiles.`)
|
|
171
|
+
|
|
172
|
+
if (!packFilesToUpload.length) {
|
|
173
|
+
return callback(new Error('Failed to generate packfiles'))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let packFileIndex = 0
|
|
177
|
+
// This uploads packfiles sequentially
|
|
178
|
+
const uploadPackFileCallback = (err) => {
|
|
179
|
+
if (err || packFileIndex === packFilesToUpload.length) {
|
|
180
|
+
return callback(err)
|
|
181
|
+
}
|
|
182
|
+
return uploadPackFile(
|
|
183
|
+
{
|
|
184
|
+
packFileToUpload: packFilesToUpload[packFileIndex++],
|
|
185
|
+
url,
|
|
186
|
+
isEvpProxy,
|
|
187
|
+
repositoryUrl,
|
|
188
|
+
headCommit
|
|
189
|
+
},
|
|
190
|
+
uploadPackFileCallback
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
uploadPackFile(
|
|
195
|
+
{
|
|
196
|
+
packFileToUpload: packFilesToUpload[packFileIndex++],
|
|
197
|
+
url,
|
|
198
|
+
isEvpProxy,
|
|
199
|
+
repositoryUrl,
|
|
200
|
+
headCommit
|
|
201
|
+
},
|
|
202
|
+
uploadPackFileCallback
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
153
206
|
/**
|
|
154
207
|
* This function uploads git metadata to CI Visibility's backend.
|
|
155
208
|
*/
|
|
@@ -165,65 +218,31 @@ function sendGitMetadata (url, isEvpProxy, configRepositoryUrl, callback) {
|
|
|
165
218
|
return callback(new Error('Repository URL is empty'))
|
|
166
219
|
}
|
|
167
220
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
221
|
+
const latestCommits = getLatestCommits()
|
|
222
|
+
log.debug(`There were ${latestCommits.length} commits since last month.`)
|
|
223
|
+
const [headCommit] = latestCommits
|
|
172
224
|
|
|
173
|
-
|
|
225
|
+
const getOnFinishGetCommitsToUpload = (hasCheckedShallow) => (err, commitsToUpload) => {
|
|
174
226
|
if (err) {
|
|
175
227
|
return callback(err)
|
|
176
228
|
}
|
|
177
|
-
log.debug(`There are ${commitsToExclude.length} commits to exclude.`)
|
|
178
|
-
const [headCommit] = latestCommits
|
|
179
|
-
const commitsToInclude = latestCommits.filter((commit) => !commitsToExclude.includes(commit))
|
|
180
|
-
log.debug(`There are ${commitsToInclude.length} commits to include.`)
|
|
181
|
-
|
|
182
|
-
const commitsToUpload = getCommitsToUpload(commitsToExclude, commitsToInclude)
|
|
183
229
|
|
|
184
230
|
if (!commitsToUpload.length) {
|
|
185
231
|
log.debug('No commits to upload')
|
|
186
232
|
return callback(null)
|
|
187
233
|
}
|
|
188
|
-
log.debug(`There are ${commitsToUpload.length} commits to upload`)
|
|
189
|
-
|
|
190
|
-
const packFilesToUpload = generatePackFilesForCommits(commitsToUpload)
|
|
191
|
-
|
|
192
|
-
log.debug(`Uploading ${packFilesToUpload.length} packfiles.`)
|
|
193
|
-
|
|
194
|
-
if (!packFilesToUpload.length) {
|
|
195
|
-
return callback(new Error('Failed to generate packfiles'))
|
|
196
|
-
}
|
|
197
234
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (err || packFileIndex === packFilesToUpload.length) {
|
|
202
|
-
return callback(err)
|
|
203
|
-
}
|
|
204
|
-
return uploadPackFile(
|
|
205
|
-
{
|
|
206
|
-
packFileToUpload: packFilesToUpload[packFileIndex++],
|
|
207
|
-
url,
|
|
208
|
-
isEvpProxy,
|
|
209
|
-
repositoryUrl,
|
|
210
|
-
headCommit
|
|
211
|
-
},
|
|
212
|
-
uploadPackFileCallback
|
|
213
|
-
)
|
|
235
|
+
// If it has already unshallowed or the clone is not shallow, we move on
|
|
236
|
+
if (hasCheckedShallow || !isShallowRepository()) {
|
|
237
|
+
return generateAndUploadPackFiles({ url, isEvpProxy, commitsToUpload, repositoryUrl, headCommit }, callback)
|
|
214
238
|
}
|
|
239
|
+
// Otherwise we unshallow and get commits to upload again
|
|
240
|
+
log.debug('It is shallow clone, unshallowing...')
|
|
241
|
+
unshallowRepository()
|
|
242
|
+
getCommitsToUpload({ url, repositoryUrl, latestCommits, isEvpProxy }, getOnFinishGetCommitsToUpload(true))
|
|
243
|
+
}
|
|
215
244
|
|
|
216
|
-
|
|
217
|
-
{
|
|
218
|
-
packFileToUpload: packFilesToUpload[packFileIndex++],
|
|
219
|
-
url,
|
|
220
|
-
isEvpProxy,
|
|
221
|
-
repositoryUrl,
|
|
222
|
-
headCommit
|
|
223
|
-
},
|
|
224
|
-
uploadPackFileCallback
|
|
225
|
-
)
|
|
226
|
-
})
|
|
245
|
+
getCommitsToUpload({ url, repositoryUrl, latestCommits, isEvpProxy }, getOnFinishGetCommitsToUpload(false))
|
|
227
246
|
}
|
|
228
247
|
|
|
229
248
|
module.exports = {
|
package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js
CHANGED
|
@@ -15,6 +15,7 @@ function getItrConfiguration ({
|
|
|
15
15
|
runtimeName,
|
|
16
16
|
runtimeVersion,
|
|
17
17
|
branch,
|
|
18
|
+
testLevel = 'suite',
|
|
18
19
|
custom
|
|
19
20
|
}, done) {
|
|
20
21
|
const options = {
|
|
@@ -23,7 +24,8 @@ function getItrConfiguration ({
|
|
|
23
24
|
headers: {
|
|
24
25
|
'Content-Type': 'application/json'
|
|
25
26
|
},
|
|
26
|
-
url
|
|
27
|
+
url,
|
|
28
|
+
timeout: 20000
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
if (isEvpProxy) {
|
|
@@ -42,7 +44,7 @@ function getItrConfiguration ({
|
|
|
42
44
|
id: id().toString(10),
|
|
43
45
|
type: 'ci_app_test_service_libraries_settings',
|
|
44
46
|
attributes: {
|
|
45
|
-
test_level:
|
|
47
|
+
test_level: testLevel,
|
|
46
48
|
configurations: {
|
|
47
49
|
'os.platform': osPlatform,
|
|
48
50
|
'os.version': osVersion,
|
|
@@ -69,13 +71,27 @@ function getItrConfiguration ({
|
|
|
69
71
|
data: {
|
|
70
72
|
attributes: {
|
|
71
73
|
code_coverage: isCodeCoverageEnabled,
|
|
72
|
-
tests_skipping: isSuitesSkippingEnabled
|
|
74
|
+
tests_skipping: isSuitesSkippingEnabled,
|
|
75
|
+
itr_enabled: isItrEnabled,
|
|
76
|
+
require_git: requireGit
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
} = JSON.parse(res)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
|
|
81
|
+
const settings = { isCodeCoverageEnabled, isSuitesSkippingEnabled, isItrEnabled, requireGit }
|
|
82
|
+
|
|
83
|
+
log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
|
|
84
|
+
|
|
85
|
+
if (process.env.DD_CIVISIBILITY_DANGEROUSLY_FORCE_COVERAGE) {
|
|
86
|
+
settings.isCodeCoverageEnabled = true
|
|
87
|
+
log.debug(() => 'Dangerously set code coverage to true')
|
|
88
|
+
}
|
|
89
|
+
if (process.env.DD_CIVISIBILITY_DANGEROUSLY_FORCE_TEST_SKIPPING) {
|
|
90
|
+
settings.isSuitesSkippingEnabled = true
|
|
91
|
+
log.debug(() => 'Dangerously set test skipping to true')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
done(null, settings)
|
|
79
95
|
} catch (err) {
|
|
80
96
|
done(err)
|
|
81
97
|
}
|