dd-trace 5.35.0 → 5.37.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 +2 -1
- package/index.d.ts +8 -7
- package/loader-hook.mjs +0 -4
- package/package.json +15 -14
- package/packages/datadog-core/index.js +1 -1
- package/packages/datadog-core/src/storage.js +76 -31
- package/packages/datadog-instrumentations/src/cucumber.js +54 -1
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +2 -2
- package/packages/datadog-instrumentations/src/jest.js +105 -11
- package/packages/datadog-instrumentations/src/mocha/main.js +46 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +35 -2
- package/packages/datadog-instrumentations/src/mocha/worker.js +7 -0
- package/packages/datadog-instrumentations/src/mysql2.js +3 -3
- package/packages/datadog-instrumentations/src/openai.js +8 -0
- package/packages/datadog-instrumentations/src/playwright.js +70 -22
- package/packages/datadog-instrumentations/src/vitest.js +60 -6
- package/packages/datadog-plugin-aerospike/src/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-couchbase/src/index.js +2 -2
- package/packages/datadog-plugin-cucumber/src/index.js +31 -14
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +72 -7
- package/packages/datadog-plugin-cypress/src/support.js +36 -29
- package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
- package/packages/datadog-plugin-graphql/src/utils.js +8 -1
- package/packages/datadog-plugin-grpc/src/client.js +1 -1
- package/packages/datadog-plugin-grpc/src/server.js +1 -1
- package/packages/datadog-plugin-hapi/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +3 -3
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +17 -12
- package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
- package/packages/datadog-plugin-mariadb/src/index.js +3 -3
- package/packages/datadog-plugin-mocha/src/index.js +35 -16
- package/packages/datadog-plugin-mongodb-core/src/index.js +28 -2
- package/packages/datadog-plugin-next/src/index.js +4 -4
- package/packages/datadog-plugin-openai/src/tracing.js +2 -3
- package/packages/datadog-plugin-playwright/src/index.js +35 -9
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +2 -2
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +36 -12
- package/packages/dd-trace/src/appsec/graphql.js +6 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +3 -7
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +15 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +17 -30
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/stored-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +2 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +24 -4
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/index.js +4 -2
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +187 -0
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +96 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks.js +28 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +5 -0
- package/packages/dd-trace/src/appsec/iast/utils.js +24 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +8 -13
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +4 -4
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/lfi.js +3 -3
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +4 -4
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +3 -3
- package/packages/dd-trace/src/appsec/reporter.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/index.js +1 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +31 -56
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +20 -2
- package/packages/dd-trace/src/ci-visibility/quarantined-tests/get-quarantined-tests.js +62 -0
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -2
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
- package/packages/dd-trace/src/config.js +18 -3
- package/packages/dd-trace/src/data_streams_context.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
- package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +50 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +38 -10
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -3
- package/packages/dd-trace/src/iitm.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +12 -2
- package/packages/dd-trace/src/log/writer.js +3 -3
- package/packages/dd-trace/src/noop/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
- package/packages/dd-trace/src/opentracing/span.js +3 -3
- package/packages/dd-trace/src/plugin_manager.js +3 -1
- package/packages/dd-trace/src/plugins/apollo.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +51 -4
- package/packages/dd-trace/src/plugins/database.js +14 -4
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +8 -8
- package/packages/dd-trace/src/plugins/tracing.js +3 -3
- package/packages/dd-trace/src/plugins/util/git.js +3 -3
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -3
- package/packages/dd-trace/src/plugins/util/test.js +10 -4
- package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/proxy.js +5 -1
- package/packages/dd-trace/src/ritm.js +2 -1
- package/packages/dd-trace/src/scope.js +5 -5
- package/packages/dd-trace/src/spanleak.js +0 -1
- package/packages/dd-trace/src/tracer.js +0 -14
- package/packages/memwatch/package.json +0 -9
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const Module = require('module')
|
|
4
|
+
const { pathToFileURL } = require('url')
|
|
5
|
+
const { MessageChannel } = require('worker_threads')
|
|
4
6
|
const shimmer = require('../../../../../datadog-shimmer')
|
|
5
7
|
const { isPrivateModule, isNotLibraryFile } = require('./filter')
|
|
6
8
|
const { csiMethods } = require('./csi-methods')
|
|
7
9
|
const { getName } = require('../telemetry/verbosity')
|
|
8
|
-
const { getRewriteFunction } = require('./rewriter-telemetry')
|
|
10
|
+
const { getRewriteFunction, incrementTelemetryIfNeeded } = require('./rewriter-telemetry')
|
|
9
11
|
const dc = require('dc-polyfill')
|
|
10
12
|
const log = require('../../../log')
|
|
13
|
+
const { isMainThread } = require('worker_threads')
|
|
14
|
+
const { LOG_MESSAGE, REWRITTEN_MESSAGE } = require('./constants')
|
|
11
15
|
|
|
12
16
|
const hardcodedSecretCh = dc.channel('datadog:secrets:result')
|
|
13
17
|
let rewriter
|
|
14
|
-
let getPrepareStackTrace
|
|
18
|
+
let getPrepareStackTrace, cacheRewrittenSourceMap
|
|
15
19
|
let kSymbolPrepareStackTrace
|
|
20
|
+
let esmRewriterEnabled = false
|
|
16
21
|
|
|
17
22
|
let getRewriterOriginalPathAndLineFromSourceMap = function (path, line, column) {
|
|
18
23
|
return { path, line, column }
|
|
@@ -46,6 +51,7 @@ function getRewriter (telemetryVerbosity) {
|
|
|
46
51
|
const Rewriter = iastRewriter.Rewriter
|
|
47
52
|
getPrepareStackTrace = iastRewriter.getPrepareStackTrace
|
|
48
53
|
kSymbolPrepareStackTrace = iastRewriter.kSymbolPrepareStackTrace
|
|
54
|
+
cacheRewrittenSourceMap = iastRewriter.cacheRewrittenSourceMap
|
|
49
55
|
|
|
50
56
|
const chainSourceMap = isFlagPresent('--enable-source-maps')
|
|
51
57
|
const getOriginalPathAndLineFromSourceMap = iastRewriter.getOriginalPathAndLineFromSourceMap
|
|
@@ -104,6 +110,24 @@ function getCompileMethodFn (compileMethod) {
|
|
|
104
110
|
}
|
|
105
111
|
}
|
|
106
112
|
|
|
113
|
+
function esmRewritePostProcess (rewritten, filename) {
|
|
114
|
+
const { literalsResult, metrics } = rewritten
|
|
115
|
+
|
|
116
|
+
if (metrics?.status === 'modified') {
|
|
117
|
+
if (filename.startsWith('file://')) {
|
|
118
|
+
filename = filename.substring(7)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
cacheRewrittenSourceMap(filename, rewritten.content)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
incrementTelemetryIfNeeded(metrics)
|
|
125
|
+
|
|
126
|
+
if (literalsResult && hardcodedSecretCh.hasSubscribers) {
|
|
127
|
+
hardcodedSecretCh.publish(literalsResult)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
107
131
|
function enableRewriter (telemetryVerbosity) {
|
|
108
132
|
try {
|
|
109
133
|
const rewriter = getRewriter(telemetryVerbosity)
|
|
@@ -114,11 +138,65 @@ function enableRewriter (telemetryVerbosity) {
|
|
|
114
138
|
}
|
|
115
139
|
shimmer.wrap(Module.prototype, '_compile', compileMethod => getCompileMethodFn(compileMethod))
|
|
116
140
|
}
|
|
141
|
+
|
|
142
|
+
enableEsmRewriter(telemetryVerbosity)
|
|
117
143
|
} catch (e) {
|
|
118
144
|
log.error('[ASM] Error enabling TaintTracking Rewriter', e)
|
|
119
145
|
}
|
|
120
146
|
}
|
|
121
147
|
|
|
148
|
+
function isEsmConfigured () {
|
|
149
|
+
const hasLoaderArg = isFlagPresent('--loader') || isFlagPresent('--experimental-loader')
|
|
150
|
+
if (hasLoaderArg) return true
|
|
151
|
+
|
|
152
|
+
const initializeLoaded = Object.keys(require.cache).find(file => file.includes('import-in-the-middle/hook.js'))
|
|
153
|
+
return !!initializeLoaded
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function enableEsmRewriter (telemetryVerbosity) {
|
|
157
|
+
if (isMainThread && Module.register && !esmRewriterEnabled && isEsmConfigured()) {
|
|
158
|
+
esmRewriterEnabled = true
|
|
159
|
+
|
|
160
|
+
const { port1, port2 } = new MessageChannel()
|
|
161
|
+
|
|
162
|
+
port1.on('message', (message) => {
|
|
163
|
+
const { type, data } = message
|
|
164
|
+
switch (type) {
|
|
165
|
+
case LOG_MESSAGE:
|
|
166
|
+
log[data.level]?.(...data.messages)
|
|
167
|
+
break
|
|
168
|
+
|
|
169
|
+
case REWRITTEN_MESSAGE:
|
|
170
|
+
esmRewritePostProcess(data.rewritten, data.url)
|
|
171
|
+
break
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
port1.unref()
|
|
176
|
+
port2.unref()
|
|
177
|
+
|
|
178
|
+
const chainSourceMap = isFlagPresent('--enable-source-maps')
|
|
179
|
+
const data = {
|
|
180
|
+
port: port2,
|
|
181
|
+
csiMethods,
|
|
182
|
+
telemetryVerbosity,
|
|
183
|
+
chainSourceMap
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
Module.register('./rewriter-esm.mjs', {
|
|
188
|
+
parentURL: pathToFileURL(__filename),
|
|
189
|
+
transferList: [port2],
|
|
190
|
+
data
|
|
191
|
+
})
|
|
192
|
+
} catch (e) {
|
|
193
|
+
log.error('[ASM] Error enabling ESM Rewriter', e)
|
|
194
|
+
port1.close()
|
|
195
|
+
port2.close()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
122
200
|
function disableRewriter () {
|
|
123
201
|
shimmer.unwrap(Module.prototype, '_compile')
|
|
124
202
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const vulnerabilities = require('../vulnerabilities')
|
|
4
|
+
const { getNextSecureMark } = require('./secure-marks-generator')
|
|
5
|
+
|
|
6
|
+
const marks = {}
|
|
7
|
+
Object.keys(vulnerabilities).forEach(vulnerability => {
|
|
8
|
+
marks[vulnerability + '_MARK'] = getNextSecureMark()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
let asterisk = 0x0
|
|
12
|
+
Object.values(marks).forEach(mark => { asterisk |= mark })
|
|
13
|
+
|
|
14
|
+
marks.ASTERISK_MARK = asterisk
|
|
15
|
+
marks.CUSTOM_SECURE_MARK = getNextSecureMark()
|
|
16
|
+
|
|
17
|
+
function getMarkFromVulnerabilityType (vulnerabilityType) {
|
|
18
|
+
vulnerabilityType = vulnerabilityType?.trim()
|
|
19
|
+
const mark = vulnerabilityType === '*' ? 'ASTERISK_MARK' : vulnerabilityType + '_MARK'
|
|
20
|
+
return marks[mark]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
...marks,
|
|
25
|
+
getMarkFromVulnerabilityType,
|
|
26
|
+
|
|
27
|
+
ALL: marks
|
|
28
|
+
}
|
|
@@ -83,6 +83,9 @@ const REQUEST_TAINTED = new NoTaggedIastMetric('request.tainted', Scope.REQUEST)
|
|
|
83
83
|
const EXECUTED_PROPAGATION = new NoTaggedIastMetric('executed.propagation', Scope.REQUEST)
|
|
84
84
|
const EXECUTED_TAINTED = new NoTaggedIastMetric('executed.tainted', Scope.REQUEST)
|
|
85
85
|
|
|
86
|
+
const SUPPRESSED_VULNERABILITIES = new IastMetric('suppressed.vulnerabilities', Scope.REQUEST,
|
|
87
|
+
TagKey.VULNERABILITY_TYPE)
|
|
88
|
+
|
|
86
89
|
module.exports = {
|
|
87
90
|
INSTRUMENTED_PROPAGATION,
|
|
88
91
|
INSTRUMENTED_SOURCE,
|
|
@@ -95,6 +98,8 @@ module.exports = {
|
|
|
95
98
|
|
|
96
99
|
REQUEST_TAINTED,
|
|
97
100
|
|
|
101
|
+
SUPPRESSED_VULNERABILITIES,
|
|
102
|
+
|
|
98
103
|
PropagationType,
|
|
99
104
|
TagKey,
|
|
100
105
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function iterateObjectStrings (target, fn, levelKeys = [], depth = 20, visited = new Set()) {
|
|
4
|
+
if (target !== null && typeof target === 'object') {
|
|
5
|
+
if (visited.has(target)) return
|
|
6
|
+
|
|
7
|
+
visited.add(target)
|
|
8
|
+
|
|
9
|
+
Object.keys(target).forEach((key) => {
|
|
10
|
+
const nextLevelKeys = [...levelKeys, key]
|
|
11
|
+
const val = target[key]
|
|
12
|
+
|
|
13
|
+
if (typeof val === 'string') {
|
|
14
|
+
fn(val, nextLevelKeys, target, key)
|
|
15
|
+
} else if (depth > 0) {
|
|
16
|
+
iterateObjectStrings(val, fn, nextLevelKeys, depth - 1, visited)
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
iterateObjectStrings
|
|
24
|
+
}
|
|
@@ -81,21 +81,16 @@ class VulnerabilityFormatter {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
formatVulnerability (vulnerability, sourcesIndexes, sources) {
|
|
84
|
+
const { type, hash, stackId, evidence, location } = vulnerability
|
|
85
|
+
|
|
84
86
|
const formattedVulnerability = {
|
|
85
|
-
type
|
|
86
|
-
hash
|
|
87
|
-
stackId
|
|
88
|
-
evidence: this.formatEvidence(
|
|
89
|
-
location
|
|
90
|
-
spanId: vulnerability.location.spanId
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (vulnerability.location.path) {
|
|
94
|
-
formattedVulnerability.location.path = vulnerability.location.path
|
|
95
|
-
}
|
|
96
|
-
if (vulnerability.location.line) {
|
|
97
|
-
formattedVulnerability.location.line = vulnerability.location.line
|
|
87
|
+
type,
|
|
88
|
+
hash,
|
|
89
|
+
stackId,
|
|
90
|
+
evidence: this.formatEvidence(type, evidence, sourcesIndexes, sources),
|
|
91
|
+
location
|
|
98
92
|
}
|
|
93
|
+
|
|
99
94
|
return formattedVulnerability
|
|
100
95
|
}
|
|
101
96
|
|
|
@@ -91,7 +91,7 @@ function onRequestBodyParsed ({ req, res, body, abortController }) {
|
|
|
91
91
|
if (body === undefined || body === null) return
|
|
92
92
|
|
|
93
93
|
if (!req) {
|
|
94
|
-
const store = storage.getStore()
|
|
94
|
+
const store = storage('legacy').getStore()
|
|
95
95
|
req = store?.req
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -186,7 +186,7 @@ function incomingHttpEndTranslator ({ req, res }) {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
function onPassportVerify ({ framework, login, user, success, abortController }) {
|
|
189
|
-
const store = storage.getStore()
|
|
189
|
+
const store = storage('legacy').getStore()
|
|
190
190
|
const rootSpan = store?.req && web.root(store.req)
|
|
191
191
|
|
|
192
192
|
if (!rootSpan) {
|
|
@@ -200,7 +200,7 @@ function onPassportVerify ({ framework, login, user, success, abortController })
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
function onPassportDeserializeUser ({ user, abortController }) {
|
|
203
|
-
const store = storage.getStore()
|
|
203
|
+
const store = storage('legacy').getStore()
|
|
204
204
|
const rootSpan = store?.req && web.root(store.req)
|
|
205
205
|
|
|
206
206
|
if (!rootSpan) {
|
|
@@ -217,7 +217,7 @@ function onRequestQueryParsed ({ req, res, query, abortController }) {
|
|
|
217
217
|
if (!query || typeof query !== 'object') return
|
|
218
218
|
|
|
219
219
|
if (!req) {
|
|
220
|
-
const store = storage.getStore()
|
|
220
|
+
const store = storage('legacy').getStore()
|
|
221
221
|
req = store?.req
|
|
222
222
|
}
|
|
223
223
|
|
|
@@ -27,24 +27,24 @@ function disable () {
|
|
|
27
27
|
function analyzeCommandInjection ({ file, fileArgs, shell, abortController }) {
|
|
28
28
|
if (!file) return
|
|
29
29
|
|
|
30
|
-
const store = storage.getStore()
|
|
30
|
+
const store = storage('legacy').getStore()
|
|
31
31
|
const req = store?.req
|
|
32
32
|
if (!req) return
|
|
33
33
|
|
|
34
|
-
const
|
|
34
|
+
const ephemeral = {}
|
|
35
35
|
const raspRule = { type: RULE_TYPES.COMMAND_INJECTION }
|
|
36
36
|
const params = fileArgs ? [file, ...fileArgs] : file
|
|
37
37
|
|
|
38
38
|
if (shell) {
|
|
39
|
-
|
|
39
|
+
ephemeral[addresses.SHELL_COMMAND] = params
|
|
40
40
|
raspRule.variant = 'shell'
|
|
41
41
|
} else {
|
|
42
42
|
const commandParams = Array.isArray(params) ? params : [params]
|
|
43
|
-
|
|
43
|
+
ephemeral[addresses.EXEC_COMMAND] = commandParams
|
|
44
44
|
raspRule.variant = 'exec'
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const result = waf.run({
|
|
47
|
+
const result = waf.run({ ephemeral }, req, raspRule)
|
|
48
48
|
|
|
49
49
|
const res = store?.res
|
|
50
50
|
handleResult(result, req, res, abortController, config)
|
|
@@ -14,9 +14,9 @@ const enabledFor = {
|
|
|
14
14
|
|
|
15
15
|
let fsPlugin
|
|
16
16
|
|
|
17
|
-
function enterWith (fsProps, store = storage.getStore()) {
|
|
17
|
+
function enterWith (fsProps, store = storage('legacy').getStore()) {
|
|
18
18
|
if (store && !store.fs?.opExcluded) {
|
|
19
|
-
storage.enterWith({
|
|
19
|
+
storage('legacy').enterWith({
|
|
20
20
|
...store,
|
|
21
21
|
fs: {
|
|
22
22
|
...store.fs,
|
|
@@ -42,7 +42,7 @@ class AppsecFsPlugin extends Plugin {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
_onFsOperationStart () {
|
|
45
|
-
const store = storage.getStore()
|
|
45
|
+
const store = storage('legacy').getStore()
|
|
46
46
|
if (store) {
|
|
47
47
|
enterWith({ root: store.fs?.root === undefined }, store)
|
|
48
48
|
}
|
|
@@ -53,9 +53,9 @@ class AppsecFsPlugin extends Plugin {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
_onFsOperationFinishOrRenderEnd () {
|
|
56
|
-
const store = storage.getStore()
|
|
56
|
+
const store = storage('legacy').getStore()
|
|
57
57
|
if (store?.fs?.parentStore) {
|
|
58
|
-
storage.enterWith(store.fs.parentStore)
|
|
58
|
+
storage('legacy').enterWith(store.fs.parentStore)
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -47,20 +47,20 @@ function onFirstReceivedRequest () {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function analyzeLfi (ctx) {
|
|
50
|
-
const store = storage.getStore()
|
|
50
|
+
const store = storage('legacy').getStore()
|
|
51
51
|
if (!store) return
|
|
52
52
|
|
|
53
53
|
const { req, fs, res } = store
|
|
54
54
|
if (!req || !fs) return
|
|
55
55
|
|
|
56
56
|
getPaths(ctx, fs).forEach(path => {
|
|
57
|
-
const
|
|
57
|
+
const ephemeral = {
|
|
58
58
|
[FS_OPERATION_PATH]: path
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const raspRule = { type: RULE_TYPES.LFI }
|
|
62
62
|
|
|
63
|
-
const result = waf.run({
|
|
63
|
+
const result = waf.run({ ephemeral }, req, raspRule)
|
|
64
64
|
handleResult(result, req, res, ctx.abortController, config)
|
|
65
65
|
})
|
|
66
66
|
}
|
|
@@ -49,7 +49,7 @@ function analyzePgSqlInjection (ctx) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function analyzeSqlInjection (query, dbSystem, abortController) {
|
|
52
|
-
const store = storage.getStore()
|
|
52
|
+
const store = storage('legacy').getStore()
|
|
53
53
|
if (!store) return
|
|
54
54
|
|
|
55
55
|
const { req, res } = store
|
|
@@ -67,14 +67,14 @@ function analyzeSqlInjection (query, dbSystem, abortController) {
|
|
|
67
67
|
}
|
|
68
68
|
executedQueries.add(query)
|
|
69
69
|
|
|
70
|
-
const
|
|
70
|
+
const ephemeral = {
|
|
71
71
|
[addresses.DB_STATEMENT]: query,
|
|
72
72
|
[addresses.DB_SYSTEM]: dbSystem
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
const raspRule = { type: RULE_TYPES.SQL_INJECTION }
|
|
76
76
|
|
|
77
|
-
const result = waf.run({
|
|
77
|
+
const result = waf.run({ ephemeral }, req, raspRule)
|
|
78
78
|
|
|
79
79
|
handleResult(result, req, res, abortController, config)
|
|
80
80
|
}
|
|
@@ -91,7 +91,7 @@ function hasAddressesObjectInputAddress (addressesObject) {
|
|
|
91
91
|
function clearQuerySet ({ payload }) {
|
|
92
92
|
if (!payload) return
|
|
93
93
|
|
|
94
|
-
const store = storage.getStore()
|
|
94
|
+
const store = storage('legacy').getStore()
|
|
95
95
|
if (!store) return
|
|
96
96
|
|
|
97
97
|
const { req } = store
|
|
@@ -19,19 +19,19 @@ function disable () {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function analyzeSsrf (ctx) {
|
|
22
|
-
const store = storage.getStore()
|
|
22
|
+
const store = storage('legacy').getStore()
|
|
23
23
|
const req = store?.req
|
|
24
24
|
const outgoingUrl = (ctx.args.options?.uri && format(ctx.args.options.uri)) ?? ctx.args.uri
|
|
25
25
|
|
|
26
26
|
if (!req || !outgoingUrl) return
|
|
27
27
|
|
|
28
|
-
const
|
|
28
|
+
const ephemeral = {
|
|
29
29
|
[addresses.HTTP_OUTGOING_URL]: outgoingUrl
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const raspRule = { type: RULE_TYPES.SSRF }
|
|
33
33
|
|
|
34
|
-
const result = waf.run({
|
|
34
|
+
const result = waf.run({ ephemeral }, req, raspRule)
|
|
35
35
|
|
|
36
36
|
const res = store?.res
|
|
37
37
|
handleResult(result, req, res, ctx.abortController, config)
|
|
@@ -102,7 +102,7 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
function reportMetrics (metrics, raspRule) {
|
|
105
|
-
const store = storage.getStore()
|
|
105
|
+
const store = storage('legacy').getStore()
|
|
106
106
|
const rootSpan = store?.req && web.root(store.req)
|
|
107
107
|
if (!rootSpan) return
|
|
108
108
|
|
|
@@ -117,7 +117,7 @@ function reportMetrics (metrics, raspRule) {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function reportAttack (attackData) {
|
|
120
|
-
const store = storage.getStore()
|
|
120
|
+
const store = storage('legacy').getStore()
|
|
121
121
|
const req = store?.req
|
|
122
122
|
const rootSpan = web.root(req)
|
|
123
123
|
if (!rootSpan) return
|
|
@@ -162,7 +162,7 @@ function isFingerprintDerivative (derivative) {
|
|
|
162
162
|
function reportDerivatives (derivatives) {
|
|
163
163
|
if (!derivatives) return
|
|
164
164
|
|
|
165
|
-
const req = storage.getStore()?.req
|
|
165
|
+
const req = storage('legacy').getStore()?.req
|
|
166
166
|
const rootSpan = web.root(req)
|
|
167
167
|
|
|
168
168
|
if (!rootSpan) return
|
|
@@ -34,7 +34,7 @@ function checkUserAndSetUser (tracer, user) {
|
|
|
34
34
|
|
|
35
35
|
function blockRequest (tracer, req, res) {
|
|
36
36
|
if (!req || !res) {
|
|
37
|
-
const store = storage.getStore()
|
|
37
|
+
const store = storage('legacy').getStore()
|
|
38
38
|
if (store) {
|
|
39
39
|
req = req || store.req
|
|
40
40
|
res = res || store.res
|
|
@@ -48,7 +48,7 @@ function update (newRules) {
|
|
|
48
48
|
|
|
49
49
|
function run (data, req, raspRule) {
|
|
50
50
|
if (!req) {
|
|
51
|
-
const store = storage.getStore()
|
|
51
|
+
const store = storage('legacy').getStore()
|
|
52
52
|
if (!store || !store.req) {
|
|
53
53
|
log.warn('[ASM] Request object not available in waf.run')
|
|
54
54
|
return
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
const {
|
|
4
4
|
workerData: {
|
|
5
5
|
breakpointSetChannel,
|
|
@@ -8,10 +8,11 @@ const {
|
|
|
8
8
|
}
|
|
9
9
|
} = require('worker_threads')
|
|
10
10
|
const { randomUUID } = require('crypto')
|
|
11
|
-
const sourceMap = require('source-map')
|
|
12
11
|
|
|
13
12
|
// TODO: move debugger/devtools_client/session to common place
|
|
14
13
|
const session = require('../../../debugger/devtools_client/session')
|
|
14
|
+
// TODO: move debugger/devtools_client/source-maps to common place
|
|
15
|
+
const { getGeneratedPosition } = require('../../../debugger/devtools_client/source-maps')
|
|
15
16
|
// TODO: move debugger/devtools_client/snapshot to common place
|
|
16
17
|
const { getLocalStateForCallFrame } = require('../../../debugger/devtools_client/snapshot')
|
|
17
18
|
// TODO: move debugger/devtools_client/state to common place
|
|
@@ -93,74 +94,48 @@ async function addBreakpoint (probe) {
|
|
|
93
94
|
probe.location = { file, lines: [String(line)] }
|
|
94
95
|
|
|
95
96
|
const script = findScriptFromPartialPath(file)
|
|
96
|
-
if (!script)
|
|
97
|
+
if (!script) {
|
|
98
|
+
log.error(`No loaded script found for ${file}`)
|
|
99
|
+
throw new Error(`No loaded script found for ${file}`)
|
|
100
|
+
}
|
|
97
101
|
|
|
98
|
-
const
|
|
102
|
+
const { url, scriptId, sourceMapURL, source } = script
|
|
99
103
|
|
|
100
|
-
log.
|
|
104
|
+
log.warn(`Adding breakpoint at ${url}:${line}`)
|
|
101
105
|
|
|
102
106
|
let lineNumber = line
|
|
107
|
+
let columnNumber = 0
|
|
103
108
|
|
|
104
|
-
if (sourceMapURL
|
|
109
|
+
if (sourceMapURL) {
|
|
105
110
|
try {
|
|
106
|
-
lineNumber = await
|
|
111
|
+
({ line: lineNumber, column: columnNumber } = await getGeneratedPosition(url, source, line, sourceMapURL))
|
|
107
112
|
} catch (err) {
|
|
108
|
-
log.error('Error processing script with
|
|
113
|
+
log.error('Error processing script with source map', err)
|
|
114
|
+
}
|
|
115
|
+
if (lineNumber === null) {
|
|
116
|
+
log.error('Could not find generated position for %s:%s', url, line)
|
|
117
|
+
lineNumber = line
|
|
118
|
+
columnNumber = 0
|
|
109
119
|
}
|
|
110
120
|
}
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
122
|
+
try {
|
|
123
|
+
const { breakpointId } = await session.post('Debugger.setBreakpoint', {
|
|
124
|
+
location: {
|
|
125
|
+
scriptId,
|
|
126
|
+
lineNumber: lineNumber - 1,
|
|
127
|
+
columnNumber
|
|
128
|
+
}
|
|
129
|
+
})
|
|
118
130
|
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
breakpointIdToProbe.set(breakpointId, probe)
|
|
132
|
+
probeIdToBreakpointId.set(probe.id, breakpointId)
|
|
133
|
+
} catch (e) {
|
|
134
|
+
log.error('Error setting breakpoint at %s:%s', url, line, e)
|
|
135
|
+
}
|
|
121
136
|
}
|
|
122
137
|
|
|
123
138
|
function start () {
|
|
124
139
|
sessionStarted = true
|
|
125
140
|
return session.post('Debugger.enable') // return instead of await to reduce number of promises created
|
|
126
141
|
}
|
|
127
|
-
|
|
128
|
-
async function processScriptWithInlineSourceMap (params) {
|
|
129
|
-
const { file, line, sourceMapURL } = params
|
|
130
|
-
|
|
131
|
-
// Extract the base64-encoded source map
|
|
132
|
-
const base64SourceMap = sourceMapURL.split('base64,')[1]
|
|
133
|
-
|
|
134
|
-
// Decode the base64 source map
|
|
135
|
-
const decodedSourceMap = Buffer.from(base64SourceMap, 'base64').toString('utf8')
|
|
136
|
-
|
|
137
|
-
// Parse the source map
|
|
138
|
-
const consumer = await new sourceMap.SourceMapConsumer(decodedSourceMap)
|
|
139
|
-
|
|
140
|
-
let generatedPosition
|
|
141
|
-
|
|
142
|
-
// Map to the generated position. We'll attempt with the full file path first, then with the basename.
|
|
143
|
-
// TODO: figure out why sometimes the full path doesn't work
|
|
144
|
-
generatedPosition = consumer.generatedPositionFor({
|
|
145
|
-
source: file,
|
|
146
|
-
line,
|
|
147
|
-
column: 0
|
|
148
|
-
})
|
|
149
|
-
if (generatedPosition.line === null) {
|
|
150
|
-
generatedPosition = consumer.generatedPositionFor({
|
|
151
|
-
source: path.basename(file),
|
|
152
|
-
line,
|
|
153
|
-
column: 0
|
|
154
|
-
})
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
consumer.destroy()
|
|
158
|
-
|
|
159
|
-
// If we can't find the line, just return the original line
|
|
160
|
-
if (generatedPosition.line === null) {
|
|
161
|
-
log.error(`Could not find generated position for ${file}:${line}`)
|
|
162
|
-
return line
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return generatedPosition.line
|
|
166
|
-
}
|
|
@@ -6,6 +6,7 @@ const { sendGitMetadata: sendGitMetadataRequest } = require('./git/git_metadata'
|
|
|
6
6
|
const { getLibraryConfiguration: getLibraryConfigurationRequest } = require('../requests/get-library-configuration')
|
|
7
7
|
const { getSkippableSuites: getSkippableSuitesRequest } = require('../intelligent-test-runner/get-skippable-suites')
|
|
8
8
|
const { getKnownTests: getKnownTestsRequest } = require('../early-flake-detection/get-known-tests')
|
|
9
|
+
const { getQuarantinedTests: getQuarantinedTestsRequest } = require('../quarantined-tests/get-quarantined-tests')
|
|
9
10
|
const log = require('../../log')
|
|
10
11
|
const AgentInfoExporter = require('../../exporters/common/agent-info-exporter')
|
|
11
12
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../../plugins/util/tags')
|
|
@@ -92,6 +93,14 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
92
93
|
)
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
shouldRequestQuarantinedTests () {
|
|
97
|
+
return !!(
|
|
98
|
+
this._canUseCiVisProtocol &&
|
|
99
|
+
this._config.isTestManagementEnabled &&
|
|
100
|
+
this._libraryConfig?.isQuarantinedTestsEnabled
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
95
104
|
shouldRequestLibraryConfiguration () {
|
|
96
105
|
return this._config.isIntelligentTestRunnerEnabled
|
|
97
106
|
}
|
|
@@ -138,6 +147,13 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
138
147
|
getKnownTestsRequest(this.getRequestConfiguration(testConfiguration), callback)
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
getQuarantinedTests (testConfiguration, callback) {
|
|
151
|
+
if (!this.shouldRequestQuarantinedTests()) {
|
|
152
|
+
return callback(null)
|
|
153
|
+
}
|
|
154
|
+
getQuarantinedTestsRequest(this.getRequestConfiguration(testConfiguration), callback)
|
|
155
|
+
}
|
|
156
|
+
|
|
141
157
|
/**
|
|
142
158
|
* We can't request library configuration until we know whether we can use the
|
|
143
159
|
* CI Visibility Protocol, hence the this._canUseCiVisProtocol promise.
|
|
@@ -197,7 +213,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
197
213
|
earlyFlakeDetectionFaultyThreshold,
|
|
198
214
|
isFlakyTestRetriesEnabled,
|
|
199
215
|
isDiEnabled,
|
|
200
|
-
isKnownTestsEnabled
|
|
216
|
+
isKnownTestsEnabled,
|
|
217
|
+
isQuarantinedTestsEnabled
|
|
201
218
|
} = remoteConfiguration
|
|
202
219
|
return {
|
|
203
220
|
isCodeCoverageEnabled,
|
|
@@ -210,7 +227,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
210
227
|
isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled,
|
|
211
228
|
flakyTestRetriesCount: this._config.flakyTestRetriesCount,
|
|
212
229
|
isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled,
|
|
213
|
-
isKnownTestsEnabled
|
|
230
|
+
isKnownTestsEnabled,
|
|
231
|
+
isQuarantinedTestsEnabled: isQuarantinedTestsEnabled && this._config.isTestManagementEnabled
|
|
214
232
|
}
|
|
215
233
|
}
|
|
216
234
|
|