dd-trace 3.12.0 → 3.13.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/ci/init.js +1 -0
- package/index.d.ts +50 -0
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/fs.js +357 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +0 -2
- package/packages/datadog-instrumentations/src/jest.js +11 -1
- package/packages/datadog-instrumentations/src/mocha.js +3 -2
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/playwright.js +236 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-jest/src/index.js +45 -23
- package/packages/datadog-plugin-mocha/src/index.js +34 -6
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +171 -0
- 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/index.js +1 -1
- package/packages/dd-trace/src/appsec/recommended.json +247 -112
- package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
- package/packages/dd-trace/src/config.js +7 -0
- 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/lambda/runtime/patch.js +1 -1
- package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -11
- 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 +108 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +27 -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/proxy.js +2 -0
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
|
+
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
TEST_STATUS,
|
|
8
|
+
finishAllTraceSpans,
|
|
9
|
+
getTestParentSpan,
|
|
10
|
+
getTestSessionCommonTags,
|
|
11
|
+
getTestSuitePath,
|
|
12
|
+
TEST_SESSION_ID,
|
|
13
|
+
TEST_COMMAND,
|
|
14
|
+
TEST_SUITE_ID,
|
|
15
|
+
getTestSuiteCommonTags,
|
|
16
|
+
getTestModuleCommonTags,
|
|
17
|
+
TEST_MODULE_ID,
|
|
18
|
+
TEST_BUNDLE
|
|
19
|
+
} = require('../../dd-trace/src/plugins/util/test')
|
|
20
|
+
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
21
|
+
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
22
|
+
|
|
23
|
+
class PlaywrightPlugin extends CiPlugin {
|
|
24
|
+
static get name () {
|
|
25
|
+
return 'playwright'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
constructor (...args) {
|
|
29
|
+
super(...args)
|
|
30
|
+
|
|
31
|
+
this._testSuites = new Map()
|
|
32
|
+
|
|
33
|
+
this.addSub('ci:playwright:session:start', ({ command, frameworkVersion, rootDir }) => {
|
|
34
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
35
|
+
this.command = command
|
|
36
|
+
this.frameworkVersion = frameworkVersion
|
|
37
|
+
this.rootDir = rootDir
|
|
38
|
+
|
|
39
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
|
|
40
|
+
this.testSessionSpan = this.tracer.startSpan('playwright.test_session', {
|
|
41
|
+
childOf,
|
|
42
|
+
tags: {
|
|
43
|
+
[COMPONENT]: this.constructor.name,
|
|
44
|
+
...this.testEnvironmentMetadata,
|
|
45
|
+
...testSessionSpanMetadata
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
|
|
49
|
+
this.testModuleSpan = this.tracer.startSpan('playwright.test_module', {
|
|
50
|
+
childOf: this.testSessionSpan,
|
|
51
|
+
tags: {
|
|
52
|
+
[COMPONENT]: this.constructor.name,
|
|
53
|
+
...this.testEnvironmentMetadata,
|
|
54
|
+
...testModuleSpanMetadata
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
this.addSub('ci:playwright:session:finish', ({ status, onDone }) => {
|
|
60
|
+
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
61
|
+
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
62
|
+
|
|
63
|
+
this.testModuleSpan.finish()
|
|
64
|
+
this.testSessionSpan.finish()
|
|
65
|
+
finishAllTraceSpans(this.testSessionSpan)
|
|
66
|
+
this.tracer._exporter.flush(onDone)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
this.addSub('ci:playwright:test-suite:start', (testSuiteAbsolutePath) => {
|
|
70
|
+
const store = storage.getStore()
|
|
71
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.rootDir)
|
|
72
|
+
|
|
73
|
+
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
74
|
+
this.command,
|
|
75
|
+
this.frameworkVersion,
|
|
76
|
+
testSuite
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const testSuiteSpan = this.tracer.startSpan('playwright.test_suite', {
|
|
80
|
+
childOf: this.testModuleSpan,
|
|
81
|
+
tags: {
|
|
82
|
+
[COMPONENT]: this.constructor.name,
|
|
83
|
+
...this.testEnvironmentMetadata,
|
|
84
|
+
...testSuiteMetadata
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
this.enter(testSuiteSpan, store)
|
|
88
|
+
|
|
89
|
+
this._testSuites.set(testSuite, testSuiteSpan)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
this.addSub('ci:playwright:test-suite:finish', (status) => {
|
|
93
|
+
const store = storage.getStore()
|
|
94
|
+
const span = store && store.span
|
|
95
|
+
if (!span) return
|
|
96
|
+
span.setTag(TEST_STATUS, status)
|
|
97
|
+
span.finish()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
this.addSub('ci:playwright:test:start', ({ testName, testSuiteAbsolutePath }) => {
|
|
101
|
+
const store = storage.getStore()
|
|
102
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.rootDir)
|
|
103
|
+
const span = this.startTestSpan(testName, testSuite)
|
|
104
|
+
|
|
105
|
+
this.enter(span, store)
|
|
106
|
+
})
|
|
107
|
+
this.addSub('ci:playwright:test:finish', ({ testStatus, steps, error }) => {
|
|
108
|
+
const store = storage.getStore()
|
|
109
|
+
const span = store && store.span
|
|
110
|
+
if (!span) return
|
|
111
|
+
|
|
112
|
+
span.setTag(TEST_STATUS, testStatus)
|
|
113
|
+
|
|
114
|
+
if (error) {
|
|
115
|
+
span.setTag('error', error)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
steps.forEach(step => {
|
|
119
|
+
const stepStartTime = step.startTime.getTime()
|
|
120
|
+
const stepSpan = this.tracer.startSpan('playwright.step', {
|
|
121
|
+
childOf: span,
|
|
122
|
+
startTime: stepStartTime,
|
|
123
|
+
tags: {
|
|
124
|
+
[COMPONENT]: this.constructor.name,
|
|
125
|
+
'playwright.step': step.title,
|
|
126
|
+
[RESOURCE_NAME]: step.title
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
if (step.error) {
|
|
130
|
+
stepSpan.setTag('error', step.error)
|
|
131
|
+
}
|
|
132
|
+
stepSpan.finish(stepStartTime + step.duration)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
span.finish()
|
|
136
|
+
finishAllTraceSpans(span)
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
startTestSpan (testName, testSuite) {
|
|
141
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
142
|
+
// This is a hack to get good time resolution on test events, while keeping
|
|
143
|
+
// the test event as the root span of its trace.
|
|
144
|
+
childOf._trace.startTime = this.testSessionSpan.context()._trace.startTime
|
|
145
|
+
childOf._trace.ticks = this.testSessionSpan.context()._trace.ticks
|
|
146
|
+
|
|
147
|
+
const testSuiteTags = {}
|
|
148
|
+
const testSuiteSpan = this._testSuites.get(testSuite)
|
|
149
|
+
if (testSuiteSpan) {
|
|
150
|
+
const testSuiteId = testSuiteSpan.context().toSpanId()
|
|
151
|
+
testSuiteTags[TEST_SUITE_ID] = testSuiteId
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (this.testSessionSpan) {
|
|
155
|
+
const testSessionId = this.testSessionSpan.context().toTraceId()
|
|
156
|
+
testSuiteTags[TEST_SESSION_ID] = testSessionId
|
|
157
|
+
testSuiteTags[TEST_COMMAND] = this.command
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (this.testModuleSpan) {
|
|
161
|
+
const testModuleId = this.testModuleSpan.context().toSpanId()
|
|
162
|
+
testSuiteTags[TEST_MODULE_ID] = testModuleId
|
|
163
|
+
testSuiteTags[TEST_COMMAND] = this.command
|
|
164
|
+
testSuiteTags[TEST_BUNDLE] = this.command
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return super.startTestSpan(testName, testSuite, testSuiteTags, childOf)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = PlaywrightPlugin
|
|
@@ -37,7 +37,7 @@ class WAFCallback {
|
|
|
37
37
|
Reporter.metricsQueue.set('_dd.appsec.event_rules.error_count', failed)
|
|
38
38
|
if (failed) Reporter.metricsQueue.set('_dd.appsec.event_rules.errors', JSON.stringify(errors))
|
|
39
39
|
|
|
40
|
-
Reporter.metricsQueue.set('manual.keep', true)
|
|
40
|
+
Reporter.metricsQueue.set('manual.keep', 'true')
|
|
41
41
|
|
|
42
42
|
this.wafContextCache = new WeakMap()
|
|
43
43
|
|
|
@@ -2,6 +2,7 @@ module.exports = {
|
|
|
2
2
|
'WEAK_CIPHER_ANALYZER': require('./weak-cipher-analyzer'),
|
|
3
3
|
'WEAK_HASH_ANALYZER': require('./weak-hash-analyzer'),
|
|
4
4
|
'SQL_INJECTION_ANALYZER': require('./sql-injection-analyzer'),
|
|
5
|
+
'PATH_TRAVERSAL_ANALYZER': require('./path-traversal-analyzer'),
|
|
5
6
|
'COMMAND_INJECTION_ANALYZER': require('./command-injection-analyzer'),
|
|
6
7
|
'LDAP_ANALYZER': require('./ldap-injection-analyzer')
|
|
7
8
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const { getIastContext } = require('../iast-context')
|
|
3
|
+
const { storage } = require('../../../../../datadog-core')
|
|
4
|
+
const InjectionAnalyzer = require('./injection-analyzer')
|
|
5
|
+
|
|
6
|
+
class PathTraversalAnalyzer extends InjectionAnalyzer {
|
|
7
|
+
constructor () {
|
|
8
|
+
super('PATH_TRAVERSAL')
|
|
9
|
+
this.addSub('apm:fs:operation:start', obj => {
|
|
10
|
+
const pathArguments = []
|
|
11
|
+
if (obj.dest) {
|
|
12
|
+
pathArguments.push(obj.dest)
|
|
13
|
+
}
|
|
14
|
+
if (obj.existingPath) {
|
|
15
|
+
pathArguments.push(obj.existingPath)
|
|
16
|
+
}
|
|
17
|
+
if (obj.file) {
|
|
18
|
+
pathArguments.push(obj.file)
|
|
19
|
+
}
|
|
20
|
+
if (obj.newPath) {
|
|
21
|
+
pathArguments.push(obj.newPath)
|
|
22
|
+
}
|
|
23
|
+
if (obj.oldPath) {
|
|
24
|
+
pathArguments.push(obj.oldPath)
|
|
25
|
+
}
|
|
26
|
+
if (obj.path) {
|
|
27
|
+
pathArguments.push(obj.path)
|
|
28
|
+
}
|
|
29
|
+
if (obj.prefix) {
|
|
30
|
+
pathArguments.push(obj.prefix)
|
|
31
|
+
}
|
|
32
|
+
if (obj.src) {
|
|
33
|
+
pathArguments.push(obj.src)
|
|
34
|
+
}
|
|
35
|
+
if (obj.target) {
|
|
36
|
+
pathArguments.push(obj.target)
|
|
37
|
+
}
|
|
38
|
+
this.analyze(pathArguments)
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
analyze (value) {
|
|
43
|
+
const iastContext = getIastContext(storage.getStore())
|
|
44
|
+
if (!iastContext) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (value && value.constructor === Array) {
|
|
49
|
+
for (const val of value) {
|
|
50
|
+
if (this._isVulnerable(val, iastContext)) {
|
|
51
|
+
this._report(val, iastContext)
|
|
52
|
+
// no support several evidences in the same vulnerability, just report the 1st one
|
|
53
|
+
break
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = new PathTraversalAnalyzer()
|
|
@@ -10,7 +10,7 @@ const Gateway = require('./gateway/engine')
|
|
|
10
10
|
const addresses = require('./addresses')
|
|
11
11
|
const Reporter = require('./reporter')
|
|
12
12
|
const web = require('../plugins/util/web')
|
|
13
|
-
const { extractIp } = require('
|
|
13
|
+
const { extractIp } = require('../plugins/util/ip_extractor')
|
|
14
14
|
const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
|
|
15
15
|
const { block, loadTemplates, loadTemplatesAsync } = require('./blocking')
|
|
16
16
|
|