dd-trace 4.51.1 → 4.53.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 +8 -2
- package/ci/init.js +16 -0
- package/index.d.ts +31 -13
- package/init.js +4 -66
- package/initialize.mjs +13 -10
- package/loader-hook.mjs +4 -0
- package/package.json +16 -11
- package/packages/datadog-core/src/storage.js +39 -2
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +29 -3
- package/packages/datadog-instrumentations/src/express.js +38 -4
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +3 -4
- package/packages/datadog-instrumentations/src/http/client.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +27 -8
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mysql2.js +13 -8
- package/packages/datadog-instrumentations/src/next.js +7 -4
- package/packages/datadog-instrumentations/src/passport-http.js +2 -14
- package/packages/datadog-instrumentations/src/passport-local.js +2 -14
- package/packages/datadog-instrumentations/src/passport-utils.js +43 -19
- package/packages/datadog-instrumentations/src/pg.js +6 -6
- package/packages/datadog-instrumentations/src/playwright.js +17 -4
- package/packages/datadog-instrumentations/src/router.js +97 -1
- package/packages/datadog-instrumentations/src/sequelize.js +9 -4
- package/packages/datadog-instrumentations/src/url.js +4 -0
- package/packages/datadog-instrumentations/src/vitest.js +27 -2
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +8 -3
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +154 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +92 -0
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +39 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +3 -3
- package/packages/datadog-plugin-grpc/src/client.js +2 -2
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +39 -4
- package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +1 -1
- package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +36 -2
- package/packages/datadog-plugin-oracledb/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +34 -2
- package/packages/datadog-shimmer/src/shimmer.js +8 -4
- package/packages/dd-trace/src/appsec/addresses.js +3 -0
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/blocked_templates.js +1 -1
- package/packages/dd-trace/src/appsec/blocking.js +1 -1
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +10 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +8 -21
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +2 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +64 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -8
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +7 -11
- package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +2 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +32 -37
- package/packages/dd-trace/src/appsec/index.js +18 -13
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +25 -1
- package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
- package/packages/dd-trace/src/appsec/reporter.js +3 -1
- package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/track_event.js +37 -24
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -4
- package/packages/dd-trace/src/appsec/telemetry.js +10 -0
- package/packages/dd-trace/src/appsec/user_tracking.js +168 -0
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -3
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/azure_metadata.js +4 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +39 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -9
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/config.js +24 -32
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +3 -2
- package/packages/dd-trace/src/datastreams/processor.js +4 -6
- package/packages/dd-trace/src/datastreams/writer.js +6 -5
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +80 -0
- package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/defaults.js +6 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +63 -8
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +10 -67
- package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/status.js +4 -4
- package/packages/dd-trace/src/debugger/index.js +14 -10
- package/packages/dd-trace/src/dogstatsd.js +2 -2
- package/packages/dd-trace/src/encode/0.4.js +23 -78
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +0 -32
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -2
- package/packages/dd-trace/src/encode/span-stats.js +0 -30
- package/packages/dd-trace/src/exporters/agent/writer.js +3 -3
- package/packages/dd-trace/src/exporters/common/request.js +1 -1
- package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -1
- package/packages/dd-trace/src/flare/index.js +1 -1
- package/packages/dd-trace/src/guardrails/index.js +64 -0
- package/packages/dd-trace/src/guardrails/log.js +32 -0
- package/packages/dd-trace/src/guardrails/telemetry.js +78 -0
- package/packages/dd-trace/src/guardrails/util.js +10 -0
- package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
- package/packages/dd-trace/src/llmobs/storage.js +2 -3
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
- package/packages/dd-trace/src/{encode → msgpack}/chunk.js +8 -5
- package/packages/dd-trace/src/msgpack/encoder.js +309 -0
- package/packages/dd-trace/src/msgpack/index.js +6 -0
- package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -9
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugin_manager.js +4 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +47 -4
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/git.js +7 -7
- package/packages/dd-trace/src/plugins/util/test.js +36 -3
- package/packages/dd-trace/src/plugins/util/web.js +2 -2
- package/packages/dd-trace/src/profiling/config.js +3 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +9 -68
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +76 -0
- package/packages/dd-trace/src/profiling/exporters/file.js +8 -4
- package/packages/dd-trace/src/profiling/profiler.js +62 -10
- package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +22 -12
- package/packages/dd-trace/src/profiling/profilers/events.js +47 -8
- package/packages/dd-trace/src/profiling/profilers/wall.js +2 -17
- package/packages/dd-trace/src/profiling/webspan-utils.js +23 -0
- package/packages/dd-trace/src/proxy.js +7 -2
- package/packages/dd-trace/src/runtime_metrics.js +107 -4
- package/packages/dd-trace/src/serverless.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +1 -1
- package/packages/dd-trace/src/span_processor.js +10 -10
- package/packages/dd-trace/src/tagger.js +1 -1
- package/packages/dd-trace/src/telemetry/index.js +1 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +10 -2
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/packages/dd-trace/src/util.js +5 -16
- package/packages/datadog-instrumentations/src/qs.js +0 -24
- package/packages/dd-trace/src/appsec/iast/iast-log.js +0 -86
- package/packages/dd-trace/src/appsec/passport.js +0 -110
- package/packages/dd-trace/src/telemetry/init-telemetry.js +0 -75
|
@@ -37,7 +37,7 @@ class LangChainLLMHandler extends LangChainLanguageModelHandler {
|
|
|
37
37
|
|
|
38
38
|
this.extractTokenMetrics(ctx.currentStore?.span, result)
|
|
39
39
|
|
|
40
|
-
for (const completionIdx in result
|
|
40
|
+
for (const completionIdx in result?.generations) {
|
|
41
41
|
const completion = result.generations[completionIdx]
|
|
42
42
|
if (this.isPromptCompletionSampled()) {
|
|
43
43
|
tags[`langchain.response.completions.${completionIdx}.text`] = this.normalize(completion[0].text) || ''
|
|
@@ -30,7 +30,12 @@ const {
|
|
|
30
30
|
TEST_SUITE,
|
|
31
31
|
MOCHA_IS_PARALLEL,
|
|
32
32
|
TEST_IS_RUM_ACTIVE,
|
|
33
|
-
TEST_BROWSER_DRIVER
|
|
33
|
+
TEST_BROWSER_DRIVER,
|
|
34
|
+
TEST_NAME,
|
|
35
|
+
DI_ERROR_DEBUG_INFO_CAPTURED,
|
|
36
|
+
DI_DEBUG_ERROR_SNAPSHOT_ID,
|
|
37
|
+
DI_DEBUG_ERROR_FILE,
|
|
38
|
+
DI_DEBUG_ERROR_LINE
|
|
34
39
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
35
40
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
36
41
|
const {
|
|
@@ -47,6 +52,8 @@ const {
|
|
|
47
52
|
const id = require('../../dd-trace/src/id')
|
|
48
53
|
const log = require('../../dd-trace/src/log')
|
|
49
54
|
|
|
55
|
+
const debuggerParameterPerTest = new Map()
|
|
56
|
+
|
|
50
57
|
function getTestSuiteLevelVisibilityTags (testSuiteSpan) {
|
|
51
58
|
const testSuiteSpanContext = testSuiteSpan.context()
|
|
52
59
|
const suiteTags = {
|
|
@@ -185,6 +192,28 @@ class MochaPlugin extends CiPlugin {
|
|
|
185
192
|
const store = storage.getStore()
|
|
186
193
|
const span = this.startTestSpan(testInfo)
|
|
187
194
|
|
|
195
|
+
const { testName } = testInfo
|
|
196
|
+
|
|
197
|
+
const debuggerParameters = debuggerParameterPerTest.get(testName)
|
|
198
|
+
|
|
199
|
+
if (debuggerParameters) {
|
|
200
|
+
const spanContext = span.context()
|
|
201
|
+
|
|
202
|
+
// TODO: handle race conditions with this.retriedTestIds
|
|
203
|
+
this.retriedTestIds = {
|
|
204
|
+
spanId: spanContext.toSpanId(),
|
|
205
|
+
traceId: spanContext.toTraceId()
|
|
206
|
+
}
|
|
207
|
+
const { snapshotId, file, line } = debuggerParameters
|
|
208
|
+
|
|
209
|
+
// TODO: should these be added on test:end if and only if the probe is hit?
|
|
210
|
+
// Sync issues: `hitProbePromise` might be resolved after the test ends
|
|
211
|
+
span.setTag(DI_ERROR_DEBUG_INFO_CAPTURED, 'true')
|
|
212
|
+
span.setTag(DI_DEBUG_ERROR_SNAPSHOT_ID, snapshotId)
|
|
213
|
+
span.setTag(DI_DEBUG_ERROR_FILE, file)
|
|
214
|
+
span.setTag(DI_DEBUG_ERROR_LINE, line)
|
|
215
|
+
}
|
|
216
|
+
|
|
188
217
|
this.enter(span, store)
|
|
189
218
|
})
|
|
190
219
|
|
|
@@ -242,7 +271,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
242
271
|
}
|
|
243
272
|
})
|
|
244
273
|
|
|
245
|
-
this.addSub('ci:mocha:test:retry', ({ isFirstAttempt, err }) => {
|
|
274
|
+
this.addSub('ci:mocha:test:retry', ({ isFirstAttempt, willBeRetried, err }) => {
|
|
246
275
|
const store = storage.getStore()
|
|
247
276
|
const span = store?.span
|
|
248
277
|
if (span) {
|
|
@@ -265,6 +294,11 @@ class MochaPlugin extends CiPlugin {
|
|
|
265
294
|
browserDriver: spanTags[TEST_BROWSER_DRIVER]
|
|
266
295
|
}
|
|
267
296
|
)
|
|
297
|
+
if (willBeRetried && this.di && this.libraryConfig?.isDiEnabled) {
|
|
298
|
+
const testName = span.context()._tags[TEST_NAME]
|
|
299
|
+
const debuggerParameters = this.addDiProbe(err)
|
|
300
|
+
debuggerParameterPerTest.set(testName, debuggerParameters)
|
|
301
|
+
}
|
|
268
302
|
|
|
269
303
|
span.finish()
|
|
270
304
|
finishAllTraceSpans(span)
|
|
@@ -17,7 +17,12 @@ const {
|
|
|
17
17
|
TEST_SOURCE_START,
|
|
18
18
|
TEST_IS_NEW,
|
|
19
19
|
TEST_EARLY_FLAKE_ENABLED,
|
|
20
|
-
TEST_EARLY_FLAKE_ABORT_REASON
|
|
20
|
+
TEST_EARLY_FLAKE_ABORT_REASON,
|
|
21
|
+
TEST_NAME,
|
|
22
|
+
DI_ERROR_DEBUG_INFO_CAPTURED,
|
|
23
|
+
DI_DEBUG_ERROR_SNAPSHOT_ID,
|
|
24
|
+
DI_DEBUG_ERROR_FILE,
|
|
25
|
+
DI_DEBUG_ERROR_LINE
|
|
21
26
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
22
27
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
23
28
|
const {
|
|
@@ -31,6 +36,8 @@ const {
|
|
|
31
36
|
// This is because there's some loss of resolution.
|
|
32
37
|
const MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION = 5
|
|
33
38
|
|
|
39
|
+
const debuggerParameterPerTest = new Map()
|
|
40
|
+
|
|
34
41
|
class VitestPlugin extends CiPlugin {
|
|
35
42
|
static get id () {
|
|
36
43
|
return 'vitest'
|
|
@@ -81,6 +88,26 @@ class VitestPlugin extends CiPlugin {
|
|
|
81
88
|
extraTags
|
|
82
89
|
)
|
|
83
90
|
|
|
91
|
+
const debuggerParameters = debuggerParameterPerTest.get(testName)
|
|
92
|
+
|
|
93
|
+
if (debuggerParameters) {
|
|
94
|
+
const spanContext = span.context()
|
|
95
|
+
|
|
96
|
+
// TODO: handle race conditions with this.retriedTestIds
|
|
97
|
+
this.retriedTestIds = {
|
|
98
|
+
spanId: spanContext.toSpanId(),
|
|
99
|
+
traceId: spanContext.toTraceId()
|
|
100
|
+
}
|
|
101
|
+
const { snapshotId, file, line } = debuggerParameters
|
|
102
|
+
|
|
103
|
+
// TODO: should these be added on test:end if and only if the probe is hit?
|
|
104
|
+
// Sync issues: `hitProbePromise` might be resolved after the test ends
|
|
105
|
+
span.setTag(DI_ERROR_DEBUG_INFO_CAPTURED, 'true')
|
|
106
|
+
span.setTag(DI_DEBUG_ERROR_SNAPSHOT_ID, snapshotId)
|
|
107
|
+
span.setTag(DI_DEBUG_ERROR_FILE, file)
|
|
108
|
+
span.setTag(DI_DEBUG_ERROR_LINE, line)
|
|
109
|
+
}
|
|
110
|
+
|
|
84
111
|
this.enter(span, store)
|
|
85
112
|
})
|
|
86
113
|
|
|
@@ -110,11 +137,16 @@ class VitestPlugin extends CiPlugin {
|
|
|
110
137
|
}
|
|
111
138
|
})
|
|
112
139
|
|
|
113
|
-
this.addSub('ci:vitest:test:error', ({ duration, error }) => {
|
|
140
|
+
this.addSub('ci:vitest:test:error', ({ duration, error, willBeRetried, probe, isDiEnabled }) => {
|
|
114
141
|
const store = storage.getStore()
|
|
115
142
|
const span = store?.span
|
|
116
143
|
|
|
117
144
|
if (span) {
|
|
145
|
+
if (willBeRetried && this.di && isDiEnabled) {
|
|
146
|
+
const testName = span.context()._tags[TEST_NAME]
|
|
147
|
+
const debuggerParameters = this.addDiProbe(error, probe)
|
|
148
|
+
debuggerParameterPerTest.set(testName, debuggerParameters)
|
|
149
|
+
}
|
|
118
150
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', {
|
|
119
151
|
hasCodeowners: !!span.context()._tags[TEST_CODE_OWNERS]
|
|
120
152
|
})
|
|
@@ -6,8 +6,12 @@ const log = require('../../dd-trace/src/log')
|
|
|
6
6
|
const unwrappers = new WeakMap()
|
|
7
7
|
|
|
8
8
|
function copyProperties (original, wrapped) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// TODO getPrototypeOf is not fast. Should we instead do this in specific
|
|
10
|
+
// instrumentations where needed?
|
|
11
|
+
const proto = Object.getPrototypeOf(original)
|
|
12
|
+
if (proto !== Function.prototype) {
|
|
13
|
+
Object.setPrototypeOf(wrapped, proto)
|
|
14
|
+
}
|
|
11
15
|
const props = Object.getOwnPropertyDescriptors(original)
|
|
12
16
|
const keys = Reflect.ownKeys(props)
|
|
13
17
|
|
|
@@ -136,7 +140,7 @@ function wrapMethod (target, name, wrapper, noAssert) {
|
|
|
136
140
|
if (callState.completed) {
|
|
137
141
|
// error was thrown after original function returned/resolved, so
|
|
138
142
|
// it was us. log it.
|
|
139
|
-
log.error(e)
|
|
143
|
+
log.error('Shimmer error was thrown after original function returned/resolved', e)
|
|
140
144
|
// original ran and returned something. return it.
|
|
141
145
|
return callState.retVal
|
|
142
146
|
}
|
|
@@ -144,7 +148,7 @@ function wrapMethod (target, name, wrapper, noAssert) {
|
|
|
144
148
|
if (!callState.called) {
|
|
145
149
|
// error was thrown before original function was called, so
|
|
146
150
|
// it was us. log it.
|
|
147
|
-
log.error(e)
|
|
151
|
+
log.error('Shimmer error was thrown before original function was called', e)
|
|
148
152
|
// original never ran. call it unwrapped.
|
|
149
153
|
return original.apply(this, args)
|
|
150
154
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
// TODO: reorder all this, it's a mess
|
|
3
4
|
module.exports = {
|
|
4
5
|
HTTP_INCOMING_BODY: 'server.request.body',
|
|
5
6
|
HTTP_INCOMING_QUERY: 'server.request.query',
|
|
@@ -20,6 +21,8 @@ module.exports = {
|
|
|
20
21
|
HTTP_CLIENT_IP: 'http.client_ip',
|
|
21
22
|
|
|
22
23
|
USER_ID: 'usr.id',
|
|
24
|
+
USER_LOGIN: 'usr.login',
|
|
25
|
+
|
|
23
26
|
WAF_CONTEXT_PROCESSOR: 'waf.context.processor',
|
|
24
27
|
|
|
25
28
|
HTTP_OUTGOING_URL: 'server.io.net.url',
|
|
@@ -64,7 +64,7 @@ function computeKey (req, res) {
|
|
|
64
64
|
const status = res.statusCode
|
|
65
65
|
|
|
66
66
|
if (!method || !status) {
|
|
67
|
-
log.warn('Unsupported groupkey for API security')
|
|
67
|
+
log.warn('[ASM] Unsupported groupkey for API security')
|
|
68
68
|
return null
|
|
69
69
|
}
|
|
70
70
|
return method + route + status
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
1
|
+
/* eslint-disable @stylistic/js/max-len */
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
4
|
const html = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>You've been blocked</title><style>a,body,div,html,span{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background:-webkit-radial-gradient(26% 19%,circle,#fff,#f4f7f9);background:radial-gradient(circle at 26% 19%,#fff,#f4f7f9);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;width:100%;min-height:100vh;line-height:1;flex-direction:column}p{display:block}main{text-align:center;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;flex-direction:column}p{font-size:18px;line-height:normal;color:#646464;font-family:sans-serif;font-weight:400}a{color:#4842b7}footer{width:100%;text-align:center}footer p{font-size:16px}</style></head><body><main><p>Sorry, you cannot access this page. Please contact the customer service team.</p></main><footer><p>Security provided by <a href="https://www.datadoghq.com/product/security-platform/application-security-monitoring/" target="_blank">Datadog</a></p></footer></body></html>`
|
|
@@ -101,7 +101,7 @@ function getBlockingData (req, specificType, actionParameters) {
|
|
|
101
101
|
|
|
102
102
|
function block (req, res, rootSpan, abortController, actionParameters = defaultBlockingActionParameters) {
|
|
103
103
|
if (res.headersSent) {
|
|
104
|
-
log.warn('Cannot send blocking response when headers have already been sent')
|
|
104
|
+
log.warn('[ASM] Cannot send blocking response when headers have already been sent')
|
|
105
105
|
return
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -19,6 +19,7 @@ module.exports = {
|
|
|
19
19
|
nextBodyParsed: dc.channel('apm:next:body-parsed'),
|
|
20
20
|
nextQueryParsed: dc.channel('apm:next:query-parsed'),
|
|
21
21
|
expressProcessParams: dc.channel('datadog:express:process_params:start'),
|
|
22
|
+
routerParam: dc.channel('datadog:router:param:start'),
|
|
22
23
|
responseBody: dc.channel('datadog:express:response:json:start'),
|
|
23
24
|
responseWriteHead: dc.channel('apm:http:server:response:writeHead:start'),
|
|
24
25
|
httpClientRequestStart: dc.channel('apm:http:client:request:start'),
|
|
@@ -11,6 +11,10 @@ class CodeInjectionAnalyzer extends InjectionAnalyzer {
|
|
|
11
11
|
onConfigure () {
|
|
12
12
|
this.addSub('datadog:eval:call', ({ script }) => this.analyze(script))
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
_areRangesVulnerable () {
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
module.exports = new CodeInjectionAnalyzer()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const Analyzer = require('./vulnerability-analyzer')
|
|
4
4
|
const { getNodeModulesPaths } = require('../path-line')
|
|
5
|
-
const
|
|
5
|
+
const log = require('../../../log')
|
|
6
6
|
|
|
7
7
|
const EXCLUDED_PATHS = getNodeModulesPaths('express/lib/response.js')
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ class CookieAnalyzer extends Analyzer {
|
|
|
16
16
|
try {
|
|
17
17
|
this.cookieFilterRegExp = new RegExp(config.iast.cookieFilterPattern)
|
|
18
18
|
} catch {
|
|
19
|
-
|
|
19
|
+
log.error('[ASM] Invalid regex in cookieFilterPattern')
|
|
20
20
|
this.cookieFilterRegExp = /.{32,}/
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const Analyzer = require('./vulnerability-analyzer')
|
|
3
|
-
const {
|
|
3
|
+
const { getRanges } = require('../taint-tracking/operations')
|
|
4
|
+
const { SQL_ROW_VALUE } = require('../taint-tracking/source-types')
|
|
4
5
|
|
|
5
6
|
class InjectionAnalyzer extends Analyzer {
|
|
6
7
|
_isVulnerable (value, iastContext) {
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
const ranges = value && getRanges(iastContext, value)
|
|
9
|
+
if (ranges?.length > 0) {
|
|
10
|
+
return this._areRangesVulnerable(ranges)
|
|
9
11
|
}
|
|
12
|
+
|
|
10
13
|
return false
|
|
11
14
|
}
|
|
12
15
|
|
|
@@ -14,6 +17,10 @@ class InjectionAnalyzer extends Analyzer {
|
|
|
14
17
|
const ranges = getRanges(iastContext, value)
|
|
15
18
|
return { value, ranges }
|
|
16
19
|
}
|
|
20
|
+
|
|
21
|
+
_areRangesVulnerable (ranges) {
|
|
22
|
+
return ranges?.some(range => range.iinfo.type !== SQL_ROW_VALUE)
|
|
23
|
+
}
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
module.exports = InjectionAnalyzer
|
|
@@ -13,6 +13,10 @@ class TemplateInjectionAnalyzer extends InjectionAnalyzer {
|
|
|
13
13
|
this.addSub('datadog:handlebars:register-partial:start', ({ partial }) => this.analyze(partial))
|
|
14
14
|
this.addSub('datadog:pug:compile:start', ({ source }) => this.analyze(source))
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
_areRangesVulnerable () {
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
module.exports = new TemplateInjectionAnalyzer()
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
4
|
|
|
5
|
-
const iastLog = require('./iast-log')
|
|
6
5
|
const Plugin = require('../../plugins/plugin')
|
|
7
6
|
const iastTelemetry = require('./telemetry')
|
|
8
7
|
const { getInstrumentedMetric, getExecutedMetric, TagKey, EXECUTED_SOURCE, formatTags } =
|
|
@@ -10,6 +9,7 @@ const { getInstrumentedMetric, getExecutedMetric, TagKey, EXECUTED_SOURCE, forma
|
|
|
10
9
|
const { storage } = require('../../../../datadog-core')
|
|
11
10
|
const { getIastContext } = require('./iast-context')
|
|
12
11
|
const instrumentations = require('../../../../datadog-instrumentations/src/helpers/instrumentations')
|
|
12
|
+
const log = require('../../log')
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Used by vulnerability sources and sinks to subscribe diagnostic channel events
|
|
@@ -60,24 +60,10 @@ class IastPlugin extends Plugin {
|
|
|
60
60
|
this.pluginSubs = []
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
_wrapHandler (handler) {
|
|
64
|
-
return (message, name) => {
|
|
65
|
-
try {
|
|
66
|
-
handler(message, name)
|
|
67
|
-
} catch (e) {
|
|
68
|
-
iastLog.errorAndPublish(e)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
63
|
_getTelemetryHandler (iastSub) {
|
|
74
64
|
return () => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
iastSub.increaseExecuted(iastContext)
|
|
78
|
-
} catch (e) {
|
|
79
|
-
iastLog.errorAndPublish(e)
|
|
80
|
-
}
|
|
65
|
+
const iastContext = getIastContext(storage.getStore())
|
|
66
|
+
iastSub.increaseExecuted(iastContext)
|
|
81
67
|
}
|
|
82
68
|
}
|
|
83
69
|
|
|
@@ -93,17 +79,17 @@ class IastPlugin extends Plugin {
|
|
|
93
79
|
}
|
|
94
80
|
return result
|
|
95
81
|
} catch (e) {
|
|
96
|
-
|
|
82
|
+
log.error('[ASM] Error executing handler or increasing metrics', e)
|
|
97
83
|
}
|
|
98
84
|
}
|
|
99
85
|
|
|
100
86
|
addSub (iastSub, handler) {
|
|
101
87
|
if (typeof iastSub === 'string') {
|
|
102
|
-
super.addSub(iastSub,
|
|
88
|
+
super.addSub(iastSub, handler)
|
|
103
89
|
} else {
|
|
104
90
|
iastSub = this._getAndRegisterSubscription(iastSub)
|
|
105
91
|
if (iastSub) {
|
|
106
|
-
super.addSub(iastSub.channelName,
|
|
92
|
+
super.addSub(iastSub.channelName, handler)
|
|
107
93
|
|
|
108
94
|
if (iastTelemetry.isEnabled()) {
|
|
109
95
|
super.addSub(iastSub.channelName, this._getTelemetryHandler(iastSub))
|
|
@@ -112,7 +98,8 @@ class IastPlugin extends Plugin {
|
|
|
112
98
|
}
|
|
113
99
|
}
|
|
114
100
|
|
|
115
|
-
enable () {
|
|
101
|
+
enable (iastConfig) {
|
|
102
|
+
this.iastConfig = iastConfig
|
|
116
103
|
this.configure(true)
|
|
117
104
|
}
|
|
118
105
|
|
|
@@ -18,10 +18,10 @@ module.exports = {
|
|
|
18
18
|
enableTaintTracking (config, telemetryVerbosity) {
|
|
19
19
|
enableRewriter(telemetryVerbosity)
|
|
20
20
|
enableTaintOperations(telemetryVerbosity)
|
|
21
|
-
taintTrackingPlugin.enable()
|
|
21
|
+
taintTrackingPlugin.enable(config)
|
|
22
22
|
|
|
23
|
-
kafkaContextPlugin.enable()
|
|
24
|
-
kafkaConsumerPlugin.enable()
|
|
23
|
+
kafkaContextPlugin.enable(config)
|
|
24
|
+
kafkaConsumerPlugin.enable(config)
|
|
25
25
|
|
|
26
26
|
setMaxTransactions(config.maxConcurrentRequests)
|
|
27
27
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const TaintedUtils = require('@datadog/native-iast-taint-tracking')
|
|
4
4
|
const { IAST_TRANSACTION_ID } = require('../iast-context')
|
|
5
|
-
const
|
|
5
|
+
const log = require('../../../log')
|
|
6
6
|
|
|
7
7
|
function taintObject (iastContext, object, type) {
|
|
8
8
|
let result = object
|
|
@@ -33,7 +33,7 @@ function taintObject (iastContext, object, type) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
} catch (e) {
|
|
36
|
-
|
|
36
|
+
log.error('[ASM] Error in taintObject when visiting property : %s', property, e)
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
HTTP_REQUEST_HEADER_NAME,
|
|
13
13
|
HTTP_REQUEST_PARAMETER,
|
|
14
14
|
HTTP_REQUEST_PATH_PARAM,
|
|
15
|
-
HTTP_REQUEST_URI
|
|
15
|
+
HTTP_REQUEST_URI,
|
|
16
|
+
SQL_ROW_VALUE
|
|
16
17
|
} = require('./source-types')
|
|
17
18
|
const { EXECUTED_SOURCE } = require('../telemetry/iast-metric')
|
|
18
19
|
|
|
@@ -26,6 +27,16 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
26
27
|
this._taintedURLs = new WeakMap()
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
configure (config) {
|
|
31
|
+
super.configure(config)
|
|
32
|
+
|
|
33
|
+
let rowsToTaint = this.iastConfig?.dbRowsToTaint
|
|
34
|
+
if (typeof rowsToTaint !== 'number') {
|
|
35
|
+
rowsToTaint = 1
|
|
36
|
+
}
|
|
37
|
+
this._rowsToTaint = rowsToTaint
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
onConfigure () {
|
|
30
41
|
const onRequestBody = ({ req }) => {
|
|
31
42
|
const iastContext = getIastContext(storage.getStore())
|
|
@@ -46,8 +57,13 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
46
57
|
)
|
|
47
58
|
|
|
48
59
|
this.addSub(
|
|
49
|
-
{ channelName: 'datadog:
|
|
50
|
-
({
|
|
60
|
+
{ channelName: 'datadog:query:read:finish', tag: HTTP_REQUEST_PARAMETER },
|
|
61
|
+
({ query }) => this._taintTrackingHandler(HTTP_REQUEST_PARAMETER, query)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
this.addSub(
|
|
65
|
+
{ channelName: 'datadog:express:query:finish', tag: HTTP_REQUEST_PARAMETER },
|
|
66
|
+
({ query }) => this._taintTrackingHandler(HTTP_REQUEST_PARAMETER, query)
|
|
51
67
|
)
|
|
52
68
|
|
|
53
69
|
this.addSub(
|
|
@@ -68,6 +84,16 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
68
84
|
({ cookies }) => this._cookiesTaintTrackingHandler(cookies)
|
|
69
85
|
)
|
|
70
86
|
|
|
87
|
+
this.addSub(
|
|
88
|
+
{ channelName: 'datadog:sequelize:query:finish', tag: SQL_ROW_VALUE },
|
|
89
|
+
({ result }) => this._taintDatabaseResult(result, 'sequelize')
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
this.addSub(
|
|
93
|
+
{ channelName: 'apm:pg:query:finish', tag: SQL_ROW_VALUE },
|
|
94
|
+
({ result }) => this._taintDatabaseResult(result, 'pg')
|
|
95
|
+
)
|
|
96
|
+
|
|
71
97
|
this.addSub(
|
|
72
98
|
{ channelName: 'datadog:express:process_params:start', tag: HTTP_REQUEST_PATH_PARAM },
|
|
73
99
|
({ req }) => {
|
|
@@ -77,6 +103,15 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
77
103
|
}
|
|
78
104
|
)
|
|
79
105
|
|
|
106
|
+
this.addSub(
|
|
107
|
+
{ channelName: 'datadog:router:param:start', tag: HTTP_REQUEST_PATH_PARAM },
|
|
108
|
+
({ req }) => {
|
|
109
|
+
if (req && req.params !== null && typeof req.params === 'object') {
|
|
110
|
+
this._taintTrackingHandler(HTTP_REQUEST_PATH_PARAM, req, 'params')
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
|
|
80
115
|
this.addSub(
|
|
81
116
|
{ channelName: 'apm:graphql:resolve:start', tag: HTTP_REQUEST_BODY },
|
|
82
117
|
(data) => {
|
|
@@ -170,6 +205,32 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
170
205
|
this.taintHeaders(req.headers, iastContext)
|
|
171
206
|
this.taintUrl(req, iastContext)
|
|
172
207
|
}
|
|
208
|
+
|
|
209
|
+
_taintDatabaseResult (result, dbOrigin, iastContext = getIastContext(storage.getStore()), name) {
|
|
210
|
+
if (!iastContext) return result
|
|
211
|
+
|
|
212
|
+
if (this._rowsToTaint === 0) return result
|
|
213
|
+
|
|
214
|
+
if (Array.isArray(result)) {
|
|
215
|
+
for (let i = 0; i < result.length && i < this._rowsToTaint; i++) {
|
|
216
|
+
const nextName = name ? `${name}.${i}` : '' + i
|
|
217
|
+
result[i] = this._taintDatabaseResult(result[i], dbOrigin, iastContext, nextName)
|
|
218
|
+
}
|
|
219
|
+
} else if (result && typeof result === 'object') {
|
|
220
|
+
if (dbOrigin === 'sequelize' && result.dataValues) {
|
|
221
|
+
result.dataValues = this._taintDatabaseResult(result.dataValues, dbOrigin, iastContext, name)
|
|
222
|
+
} else {
|
|
223
|
+
for (const key in result) {
|
|
224
|
+
const nextName = name ? `${name}.${key}` : key
|
|
225
|
+
result[key] = this._taintDatabaseResult(result[key], dbOrigin, iastContext, nextName)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
} else if (typeof result === 'string') {
|
|
229
|
+
result = newTaintedString(iastContext, result, name, SQL_ROW_VALUE)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return result
|
|
233
|
+
}
|
|
173
234
|
}
|
|
174
235
|
|
|
175
236
|
module.exports = new TaintTrackingPlugin()
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const Module = require('module')
|
|
4
4
|
const shimmer = require('../../../../../datadog-shimmer')
|
|
5
|
-
const iastLog = require('../iast-log')
|
|
6
5
|
const { isPrivateModule, isNotLibraryFile } = require('./filter')
|
|
7
6
|
const { csiMethods } = require('./csi-methods')
|
|
8
7
|
const { getName } = require('../telemetry/verbosity')
|
|
9
8
|
const { getRewriteFunction } = require('./rewriter-telemetry')
|
|
10
9
|
const dc = require('dc-polyfill')
|
|
10
|
+
const log = require('../../../log')
|
|
11
11
|
|
|
12
12
|
const hardcodedSecretCh = dc.channel('datadog:secrets:result')
|
|
13
13
|
let rewriter
|
|
@@ -60,8 +60,7 @@ function getRewriter (telemetryVerbosity) {
|
|
|
60
60
|
chainSourceMap
|
|
61
61
|
})
|
|
62
62
|
} catch (e) {
|
|
63
|
-
|
|
64
|
-
.errorAndPublish(e)
|
|
63
|
+
log.error('[ASM] Unable to initialize TaintTracking Rewriter', e)
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
return rewriter
|
|
@@ -99,8 +98,7 @@ function getCompileMethodFn (compileMethod) {
|
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
} catch (e) {
|
|
102
|
-
|
|
103
|
-
.errorAndPublish(e)
|
|
101
|
+
log.error('[ASM] Error rewriting file %s', filename, e)
|
|
104
102
|
}
|
|
105
103
|
return compileMethod.apply(this, [content, filename])
|
|
106
104
|
}
|
|
@@ -117,8 +115,7 @@ function enableRewriter (telemetryVerbosity) {
|
|
|
117
115
|
shimmer.wrap(Module.prototype, '_compile', compileMethod => getCompileMethodFn(compileMethod))
|
|
118
116
|
}
|
|
119
117
|
} catch (e) {
|
|
120
|
-
|
|
121
|
-
.errorAndPublish(e)
|
|
118
|
+
log.error('[ASM] Error enabling TaintTracking Rewriter', e)
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
|
|
@@ -132,7 +129,7 @@ function disableRewriter () {
|
|
|
132
129
|
|
|
133
130
|
Error.prepareStackTrace = originalPrepareStackTrace
|
|
134
131
|
} catch (e) {
|
|
135
|
-
|
|
132
|
+
log.warn('[ASM] Error disabling TaintTracking rewriter', e)
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
|
|
@@ -11,5 +11,6 @@ module.exports = {
|
|
|
11
11
|
HTTP_REQUEST_PATH_PARAM: 'http.request.path.parameter',
|
|
12
12
|
HTTP_REQUEST_URI: 'http.request.uri',
|
|
13
13
|
KAFKA_MESSAGE_KEY: 'kafka.message.key',
|
|
14
|
-
KAFKA_MESSAGE_VALUE: 'kafka.message.value'
|
|
14
|
+
KAFKA_MESSAGE_VALUE: 'kafka.message.value',
|
|
15
|
+
SQL_ROW_VALUE: 'sql.row.value'
|
|
15
16
|
}
|