dd-trace 5.86.0 → 5.88.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 +60 -32
- package/ext/exporters.d.ts +1 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +243 -7
- package/package.json +9 -6
- package/packages/datadog-instrumentations/src/ai.js +54 -90
- package/packages/datadog-instrumentations/src/cucumber.js +14 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +17 -11
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +55 -14
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +15 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +103 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.js +108 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transformer.js +21 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +138 -12
- package/packages/datadog-instrumentations/src/http/client.js +119 -1
- package/packages/datadog-instrumentations/src/jest.js +179 -15
- package/packages/datadog-instrumentations/src/kafkajs.js +20 -17
- package/packages/datadog-instrumentations/src/mocha/utils.js +6 -0
- package/packages/datadog-instrumentations/src/mysql2.js +131 -64
- package/packages/datadog-instrumentations/src/playwright.js +9 -1
- package/packages/datadog-instrumentations/src/stripe.js +92 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -10
- package/packages/datadog-plugin-amqplib/src/producer.js +23 -19
- package/packages/datadog-plugin-azure-functions/src/index.js +53 -37
- package/packages/datadog-plugin-bullmq/src/consumer.js +33 -11
- package/packages/datadog-plugin-bullmq/src/producer.js +60 -31
- package/packages/datadog-plugin-cucumber/src/index.js +9 -6
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +33 -0
- package/packages/datadog-plugin-cypress/src/support.js +48 -8
- package/packages/datadog-plugin-jest/src/index.js +12 -2
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +22 -12
- package/packages/datadog-plugin-kafkajs/src/producer.js +33 -22
- package/packages/datadog-plugin-mocha/src/index.js +9 -6
- package/packages/datadog-plugin-playwright/src/index.js +10 -6
- package/packages/datadog-plugin-vitest/src/index.js +13 -8
- package/packages/dd-trace/src/appsec/addresses.js +11 -0
- package/packages/dd-trace/src/appsec/channels.js +5 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +302 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +4 -5
- package/packages/dd-trace/src/appsec/iast/path-line.js +36 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +3 -2
- package/packages/dd-trace/src/appsec/index.js +103 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +66 -4
- package/packages/dd-trace/src/azure_metadata.js +0 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +14 -1
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
- package/packages/dd-trace/src/ci-visibility/requests/request.js +236 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +148 -195
- package/packages/dd-trace/src/config/helper.js +43 -1
- package/packages/dd-trace/src/config/index.js +42 -14
- package/packages/dd-trace/src/config/supported-configurations.json +4115 -510
- package/packages/dd-trace/src/constants.js +0 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -3
- package/packages/dd-trace/src/datastreams/pathway.js +22 -3
- package/packages/dd-trace/src/datastreams/processor.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -2
- package/packages/dd-trace/src/debugger/devtools_client/index.js +75 -23
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +23 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +3 -3
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +168 -36
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +18 -0
- package/packages/dd-trace/src/encode/agentless-json.js +141 -0
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +22 -8
- package/packages/dd-trace/src/exporters/agentless/index.js +89 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +184 -0
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +4 -4
- package/packages/dd-trace/src/llmobs/constants/writers.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -3
- package/packages/dd-trace/src/llmobs/sdk.js +34 -5
- package/packages/dd-trace/src/opentelemetry/context_manager.js +19 -46
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +3 -4
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -4
- package/packages/dd-trace/src/plugins/ci_plugin.js +57 -5
- package/packages/dd-trace/src/plugins/database.js +57 -45
- package/packages/dd-trace/src/plugins/outbound.js +27 -2
- package/packages/dd-trace/src/plugins/tracing.js +39 -4
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +7 -0
- package/packages/dd-trace/src/plugins/util/test.js +48 -0
- package/packages/dd-trace/src/plugins/util/web.js +8 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -0
- package/packages/dd-trace/src/propagation-hash/index.js +145 -0
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +0 -106
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -741
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +0 -11
- package/packages/dd-trace/src/plugins/util/serverless.js +0 -8
- package/packages/dd-trace/src/scope/noop/scope.js +0 -21
|
@@ -8,29 +8,40 @@ const { getOriginalPathAndLineFromSourceMap } = require('./taint-tracking/rewrit
|
|
|
8
8
|
const pathLine = {
|
|
9
9
|
getNodeModulesPaths,
|
|
10
10
|
getRelativePath,
|
|
11
|
-
|
|
11
|
+
getCallSiteFramesForLocation,
|
|
12
12
|
ddBasePath, // Exported only for test purposes
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const EXCLUDED_PATHS = [
|
|
16
16
|
path.join(path.sep, 'node_modules', 'dc-polyfill'),
|
|
17
17
|
]
|
|
18
|
-
const EXCLUDED_PATH_PREFIXES = [
|
|
19
|
-
'node:diagnostics_channel',
|
|
20
|
-
'diagnostics_channel',
|
|
21
|
-
'node:child_process',
|
|
22
|
-
'child_process',
|
|
23
|
-
'node:async_hooks',
|
|
24
|
-
'async_hooks',
|
|
25
|
-
'node:internal/async_local_storage',
|
|
26
|
-
]
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Processes and filters call site frames to find the best location for a vulnerability.
|
|
21
|
+
* Returns client frames if available, otherwise falls back to all processed frames.
|
|
22
|
+
* Excludes dd-trace frames and all Node.js built-in/internal modules (node:*).
|
|
23
|
+
* @param {CallSiteFrame[]} callSiteFrames
|
|
24
|
+
* @param {string[]} externallyExcludedPaths
|
|
25
|
+
* @returns {CallSiteFrame[]} Client frames if available, otherwise all processed frames
|
|
26
|
+
*
|
|
27
|
+
* @typedef {object} CallSiteFrame
|
|
28
|
+
* @property {number} id
|
|
29
|
+
* @property {string} file - Original file path
|
|
30
|
+
* @property {number} line
|
|
31
|
+
* @property {number} column
|
|
32
|
+
* @property {string} function
|
|
33
|
+
* @property {string} class_name
|
|
34
|
+
* @property {boolean} isNative
|
|
35
|
+
* @property {string} [path] - Relative path, added during processing
|
|
36
|
+
* @property {boolean} [isInternal] - Whether the frame is internal, added during processing
|
|
37
|
+
*/
|
|
38
|
+
function getCallSiteFramesForLocation (callSiteFrames, externallyExcludedPaths) {
|
|
29
39
|
if (!callSiteFrames) {
|
|
30
40
|
return []
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
const
|
|
43
|
+
const allFrames = []
|
|
44
|
+
const clientFrames = []
|
|
34
45
|
|
|
35
46
|
for (const callsite of callSiteFrames) {
|
|
36
47
|
let filepath = callsite.file?.startsWith('file://') ? fileURLToPath(callsite.file) : callsite.file
|
|
@@ -47,18 +58,22 @@ function getNonDDCallSiteFrames (callSiteFrames, externallyExcludedPaths) {
|
|
|
47
58
|
callsite.column = column
|
|
48
59
|
}
|
|
49
60
|
|
|
50
|
-
if (
|
|
51
|
-
!isExcluded(callsite, externallyExcludedPaths) &&
|
|
52
|
-
(!filepath.includes(pathLine.ddBasePath) || globalThis.__DD_ESBUILD_IAST_WITH_NO_SM)
|
|
53
|
-
) {
|
|
61
|
+
if (filepath) {
|
|
54
62
|
callsite.path = getRelativePath(filepath)
|
|
55
63
|
callsite.isInternal = !path.isAbsolute(filepath)
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
allFrames.push(callsite)
|
|
66
|
+
|
|
67
|
+
if (
|
|
68
|
+
!isExcluded(callsite, externallyExcludedPaths) &&
|
|
69
|
+
(!filepath.includes(pathLine.ddBasePath) || globalThis.__DD_ESBUILD_IAST_WITH_NO_SM)
|
|
70
|
+
) {
|
|
71
|
+
clientFrames.push(callsite)
|
|
72
|
+
}
|
|
58
73
|
}
|
|
59
74
|
}
|
|
60
75
|
|
|
61
|
-
return
|
|
76
|
+
return clientFrames.length > 0 ? clientFrames : allFrames
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
function getRelativePath (filepath) {
|
|
@@ -67,10 +82,12 @@ function getRelativePath (filepath) {
|
|
|
67
82
|
|
|
68
83
|
function isExcluded (callsite, externallyExcludedPaths) {
|
|
69
84
|
if (callsite.isNative) return true
|
|
85
|
+
|
|
70
86
|
const filename = globalThis.__DD_ESBUILD_IAST_WITH_SM ? callsite.path : callsite.file
|
|
71
|
-
if (!filename) {
|
|
87
|
+
if (!filename || filename.startsWith('node:')) {
|
|
72
88
|
return true
|
|
73
89
|
}
|
|
90
|
+
|
|
74
91
|
let excludedPaths = EXCLUDED_PATHS
|
|
75
92
|
if (externallyExcludedPaths) {
|
|
76
93
|
excludedPaths = [...excludedPaths, ...externallyExcludedPaths]
|
|
@@ -82,12 +99,6 @@ function isExcluded (callsite, externallyExcludedPaths) {
|
|
|
82
99
|
}
|
|
83
100
|
}
|
|
84
101
|
|
|
85
|
-
for (const EXCLUDED_PATH_PREFIX of EXCLUDED_PATH_PREFIXES) {
|
|
86
|
-
if (filename.indexOf(EXCLUDED_PATH_PREFIX) === 0) {
|
|
87
|
-
return true
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
102
|
return false
|
|
92
103
|
}
|
|
93
104
|
|
|
@@ -10,7 +10,7 @@ module.exports = function extractSensitiveRanges (evidence) {
|
|
|
10
10
|
pattern.lastIndex = 0
|
|
11
11
|
|
|
12
12
|
const regexResult = pattern.exec(evidence.value)
|
|
13
|
-
if (regexResult
|
|
13
|
+
if (regexResult?.length > 1) {
|
|
14
14
|
const start = regexResult.index + (regexResult[0].length - regexResult[1].length)
|
|
15
15
|
const end = start + regexResult[1].length
|
|
16
16
|
return [{ start, end }]
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
const log = require('../../../../log')
|
|
5
5
|
const vulnerabilities = require('../../vulnerabilities')
|
|
6
|
+
const defaults = require('../../../../config/defaults')
|
|
6
7
|
|
|
7
8
|
const { contains, intersects, remove } = require('./range-utils')
|
|
8
9
|
|
|
@@ -14,14 +15,12 @@ const sqlSensitiveAnalyzer = require('./sensitive-analyzers/sql-sensitive-analyz
|
|
|
14
15
|
const taintedRangeBasedSensitiveAnalyzer = require('./sensitive-analyzers/tainted-range-based-sensitive-analyzer')
|
|
15
16
|
const urlSensitiveAnalyzer = require('./sensitive-analyzers/url-sensitive-analyzer')
|
|
16
17
|
|
|
17
|
-
const { DEFAULT_IAST_REDACTION_NAME_PATTERN, DEFAULT_IAST_REDACTION_VALUE_PATTERN } = require('./sensitive-regex')
|
|
18
|
-
|
|
19
18
|
const REDACTED_SOURCE_BUFFER = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
|
20
19
|
|
|
21
20
|
class SensitiveHandler {
|
|
22
21
|
constructor () {
|
|
23
|
-
this._namePattern = new RegExp(
|
|
24
|
-
this._valuePattern = new RegExp(
|
|
22
|
+
this._namePattern = new RegExp(/** @type {string} */ (defaults['iast.redactionNamePattern']), 'gmi')
|
|
23
|
+
this._valuePattern = new RegExp(/** @type {string} */ (defaults['iast.redactionValuePattern']), 'gmi')
|
|
25
24
|
|
|
26
25
|
this._sensitiveAnalyzers = new Map()
|
|
27
26
|
this._sensitiveAnalyzers.set(vulnerabilities.CODE_INJECTION, taintedRangeBasedSensitiveAnalyzer)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const crypto = require('crypto')
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
const defaults = require('../../../config/defaults')
|
|
5
6
|
|
|
6
7
|
const STRINGIFY_RANGE_KEY = 'DD_' + crypto.randomBytes(20).toString('hex')
|
|
7
8
|
const STRINGIFY_SENSITIVE_KEY = STRINGIFY_RANGE_KEY + 'SENSITIVE'
|
|
@@ -11,7 +12,7 @@ const STRINGIFY_SENSITIVE_NOT_STRING_KEY = STRINGIFY_SENSITIVE_KEY + 'NOTSTRING'
|
|
|
11
12
|
const KEYS_REGEX_WITH_SENSITIVE_RANGES = new RegExp(String.raw`(?:"(${STRINGIFY_RANGE_KEY}_\d+_))|(?:"(${STRINGIFY_SENSITIVE_KEY}_\d+_(\d+)_))|("${STRINGIFY_SENSITIVE_NOT_STRING_KEY}_\d+_([\s0-9.a-zA-Z]*)")`, 'gm')
|
|
12
13
|
const KEYS_REGEX_WITHOUT_SENSITIVE_RANGES = new RegExp(String.raw`"(${STRINGIFY_RANGE_KEY}_\d+_)`, 'gm')
|
|
13
14
|
|
|
14
|
-
const sensitiveValueRegex = new RegExp(
|
|
15
|
+
const sensitiveValueRegex = new RegExp(/** @type {string} */ (defaults['iast.redactionValuePattern']), 'gmi')
|
|
15
16
|
|
|
16
17
|
function iterateObject (target, fn, levelKeys = [], depth = 10, visited = new Set()) {
|
|
17
18
|
for (const key of Object.keys(target)) {
|
|
@@ -30,6 +30,9 @@ const {
|
|
|
30
30
|
routerParam,
|
|
31
31
|
fastifyResponseChannel,
|
|
32
32
|
fastifyPathParams,
|
|
33
|
+
stripeCheckoutSessionCreate,
|
|
34
|
+
stripePaymentIntentCreate,
|
|
35
|
+
stripeConstructEvent,
|
|
33
36
|
} = require('./channels')
|
|
34
37
|
const waf = require('./waf')
|
|
35
38
|
const addresses = require('./addresses')
|
|
@@ -92,6 +95,9 @@ function enable (_config) {
|
|
|
92
95
|
fastifyResponseChannel.subscribe(onResponseBody)
|
|
93
96
|
responseWriteHead.subscribe(onResponseWriteHead)
|
|
94
97
|
responseSetHeader.subscribe(onResponseSetHeader)
|
|
98
|
+
stripeCheckoutSessionCreate.subscribe(onStripeCheckoutSessionCreate)
|
|
99
|
+
stripePaymentIntentCreate.subscribe(onStripePaymentIntentCreate)
|
|
100
|
+
stripeConstructEvent.subscribe(onStripeConstructEvent)
|
|
95
101
|
|
|
96
102
|
isEnabled = true
|
|
97
103
|
config = _config
|
|
@@ -382,6 +388,100 @@ function onResponseSetHeader ({ res, abortController }) {
|
|
|
382
388
|
}
|
|
383
389
|
}
|
|
384
390
|
|
|
391
|
+
function onStripeCheckoutSessionCreate (payload) {
|
|
392
|
+
if (payload?.mode !== 'payment') return
|
|
393
|
+
|
|
394
|
+
waf.run({
|
|
395
|
+
persistent: {
|
|
396
|
+
[addresses.PAYMENT_CREATION]: {
|
|
397
|
+
integration: 'stripe',
|
|
398
|
+
id: payload.id,
|
|
399
|
+
amount_total: payload.amount_total,
|
|
400
|
+
client_reference_id: payload.client_reference_id,
|
|
401
|
+
currency: payload.currency,
|
|
402
|
+
'discounts.coupon': payload.discounts?.[0]?.coupon,
|
|
403
|
+
'discounts.promotion_code': payload.discounts?.[0]?.promotion_code,
|
|
404
|
+
livemode: payload.livemode,
|
|
405
|
+
'total_details.amount_discount': payload.total_details?.amount_discount,
|
|
406
|
+
'total_details.amount_shipping': payload.total_details?.amount_shipping,
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function onStripePaymentIntentCreate (payload) {
|
|
413
|
+
if (payload === null || typeof payload !== 'object') return
|
|
414
|
+
|
|
415
|
+
waf.run({
|
|
416
|
+
persistent: {
|
|
417
|
+
[addresses.PAYMENT_CREATION]: {
|
|
418
|
+
integration: 'stripe',
|
|
419
|
+
id: payload.id,
|
|
420
|
+
amount: payload.amount,
|
|
421
|
+
currency: payload.currency,
|
|
422
|
+
livemode: payload.livemode,
|
|
423
|
+
payment_method: payload.payment_method,
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function onStripeConstructEvent (payload) {
|
|
430
|
+
const object = payload?.data?.object
|
|
431
|
+
if (object === null || typeof object !== 'object') return
|
|
432
|
+
|
|
433
|
+
let persistent
|
|
434
|
+
|
|
435
|
+
switch (payload.type) {
|
|
436
|
+
case 'payment_intent.succeeded':
|
|
437
|
+
persistent = {
|
|
438
|
+
[addresses.PAYMENT_SUCCESS]: {
|
|
439
|
+
integration: 'stripe',
|
|
440
|
+
id: object.id,
|
|
441
|
+
amount: object.amount,
|
|
442
|
+
currency: object.currency,
|
|
443
|
+
livemode: object.livemode,
|
|
444
|
+
payment_method: object.payment_method,
|
|
445
|
+
},
|
|
446
|
+
}
|
|
447
|
+
break
|
|
448
|
+
|
|
449
|
+
case 'payment_intent.payment_failed':
|
|
450
|
+
persistent = {
|
|
451
|
+
[addresses.PAYMENT_FAILURE]: {
|
|
452
|
+
integration: 'stripe',
|
|
453
|
+
id: object.id,
|
|
454
|
+
amount: object.amount,
|
|
455
|
+
currency: object.currency,
|
|
456
|
+
'last_payment_error.code': object.last_payment_error?.code,
|
|
457
|
+
'last_payment_error.decline_code': object.last_payment_error?.decline_code,
|
|
458
|
+
'last_payment_error.payment_method.id': object.last_payment_error?.payment_method?.id,
|
|
459
|
+
'last_payment_error.payment_method.type': object.last_payment_error?.payment_method?.type,
|
|
460
|
+
livemode: object.livemode,
|
|
461
|
+
},
|
|
462
|
+
}
|
|
463
|
+
break
|
|
464
|
+
|
|
465
|
+
case 'payment_intent.canceled':
|
|
466
|
+
persistent = {
|
|
467
|
+
[addresses.PAYMENT_CANCELLATION]: {
|
|
468
|
+
integration: 'stripe',
|
|
469
|
+
id: object.id,
|
|
470
|
+
amount: object.amount,
|
|
471
|
+
cancellation_reason: object.cancellation_reason,
|
|
472
|
+
currency: object.currency,
|
|
473
|
+
livemode: object.livemode,
|
|
474
|
+
},
|
|
475
|
+
}
|
|
476
|
+
break
|
|
477
|
+
|
|
478
|
+
default:
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
waf.run({ persistent })
|
|
483
|
+
}
|
|
484
|
+
|
|
385
485
|
function handleResults (actions, req, res, rootSpan, abortController) {
|
|
386
486
|
if (!actions || !req || !res || !rootSpan || !abortController) return
|
|
387
487
|
|
|
@@ -427,6 +527,9 @@ function disable () {
|
|
|
427
527
|
if (fastifyResponseChannel.hasSubscribers) fastifyResponseChannel.unsubscribe(onResponseBody)
|
|
428
528
|
if (responseWriteHead.hasSubscribers) responseWriteHead.unsubscribe(onResponseWriteHead)
|
|
429
529
|
if (responseSetHeader.hasSubscribers) responseSetHeader.unsubscribe(onResponseSetHeader)
|
|
530
|
+
if (stripeCheckoutSessionCreate.hasSubscribers) stripeCheckoutSessionCreate.unsubscribe(onStripeCheckoutSessionCreate)
|
|
531
|
+
if (stripePaymentIntentCreate.hasSubscribers) stripePaymentIntentCreate.unsubscribe(onStripePaymentIntentCreate)
|
|
532
|
+
if (stripeConstructEvent.hasSubscribers) stripeConstructEvent.unsubscribe(onStripeConstructEvent)
|
|
430
533
|
}
|
|
431
534
|
|
|
432
535
|
// this is faster than Object.keys().length === 0
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { format } = require('url')
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
httpClientRequestStart,
|
|
6
|
+
httpClientResponseFinish,
|
|
7
|
+
} = require('../channels')
|
|
5
8
|
const { storage } = require('../../../../datadog-core')
|
|
6
9
|
const addresses = require('../addresses')
|
|
7
10
|
const waf = require('../waf')
|
|
11
|
+
const downstream = require('../downstream_requests')
|
|
12
|
+
const { updateRaspRuleMatchMetricTags } = require('../telemetry')
|
|
8
13
|
const { RULE_TYPES, handleResult } = require('./utils')
|
|
9
14
|
|
|
10
15
|
let config
|
|
11
16
|
|
|
12
17
|
function enable (_config) {
|
|
13
18
|
config = _config
|
|
19
|
+
downstream.enable(_config)
|
|
20
|
+
|
|
14
21
|
httpClientRequestStart.subscribe(analyzeSsrf)
|
|
22
|
+
httpClientResponseFinish.subscribe(handleResponseFinish)
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
function disable () {
|
|
26
|
+
downstream.disable()
|
|
27
|
+
|
|
18
28
|
if (httpClientRequestStart.hasSubscribers) httpClientRequestStart.unsubscribe(analyzeSsrf)
|
|
29
|
+
if (httpClientResponseFinish.hasSubscribers) httpClientResponseFinish.unsubscribe(handleResponseFinish)
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
function analyzeSsrf (ctx) {
|
|
@@ -25,16 +36,67 @@ function analyzeSsrf (ctx) {
|
|
|
25
36
|
|
|
26
37
|
if (!req || !outgoingUrl) return
|
|
27
38
|
|
|
39
|
+
// Determine if we should collect the response body based on sampling rate and redirect URL
|
|
40
|
+
ctx.shouldCollectBody = downstream.shouldSampleBody(req, outgoingUrl)
|
|
41
|
+
|
|
42
|
+
const requestAddresses = downstream.extractRequestData(ctx)
|
|
43
|
+
|
|
28
44
|
const ephemeral = {
|
|
29
45
|
[addresses.HTTP_OUTGOING_URL]: outgoingUrl,
|
|
46
|
+
...requestAddresses,
|
|
30
47
|
}
|
|
31
48
|
|
|
32
|
-
const raspRule = { type: RULE_TYPES.SSRF }
|
|
49
|
+
const raspRule = { type: RULE_TYPES.SSRF, variant: 'request' }
|
|
33
50
|
|
|
34
51
|
const result = waf.run({ ephemeral }, req, raspRule)
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
handleResult(result, req, store?.res, ctx.abortController, config, raspRule)
|
|
54
|
+
|
|
55
|
+
downstream.incrementDownstreamAnalysisCount(req)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Finalizes body collection for the response and triggers RASP analysis.
|
|
60
|
+
* @param {{
|
|
61
|
+
* ctx: object,
|
|
62
|
+
* res: import('http').IncomingMessage,
|
|
63
|
+
* body: string|Buffer|null
|
|
64
|
+
* }} payload event payload from the channel.
|
|
65
|
+
*/
|
|
66
|
+
function handleResponseFinish ({ ctx, res, body }) {
|
|
67
|
+
// downstream response object
|
|
68
|
+
if (!res) return
|
|
69
|
+
|
|
70
|
+
const store = storage('legacy').getStore()
|
|
71
|
+
const originatingRequest = store?.req
|
|
72
|
+
if (!originatingRequest) return
|
|
73
|
+
|
|
74
|
+
// Skip body analysis for redirect responses
|
|
75
|
+
const evaluateBody = ctx.shouldCollectBody && !downstream.handleRedirectResponse(originatingRequest, res)
|
|
76
|
+
const responseBody = evaluateBody ? body : null
|
|
77
|
+
runResponseEvaluation(res, originatingRequest, responseBody)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Evaluates the downstream response and records telemetry.
|
|
82
|
+
* @param {import('http').IncomingMessage} res incoming response from downstream service.
|
|
83
|
+
* @param {import('http').IncomingMessage} req originating request.
|
|
84
|
+
* @param {string|Buffer|null} responseBody collected downstream response body.
|
|
85
|
+
*/
|
|
86
|
+
function runResponseEvaluation (res, req, responseBody) {
|
|
87
|
+
const responseAddresses = downstream.extractResponseData(res, responseBody)
|
|
88
|
+
|
|
89
|
+
if (!Object.keys(responseAddresses).length) return
|
|
90
|
+
|
|
91
|
+
const raspRule = { type: RULE_TYPES.SSRF, variant: 'response' }
|
|
92
|
+
const result = waf.run({ ephemeral: responseAddresses }, req, raspRule)
|
|
93
|
+
|
|
94
|
+
// TODO: this should be done in the waf functions directly instead of calling it everywhere
|
|
95
|
+
const ruleTriggered = !!result?.events?.length
|
|
96
|
+
|
|
97
|
+
if (ruleTriggered) {
|
|
98
|
+
updateRaspRuleMatchMetricTags(req, raspRule, false, false)
|
|
99
|
+
}
|
|
38
100
|
}
|
|
39
101
|
|
|
40
102
|
module.exports = { enable, disable }
|
|
@@ -58,7 +58,6 @@ function buildMetadata () {
|
|
|
58
58
|
WEBSITE_SITE_NAME,
|
|
59
59
|
} = getEnvironmentVariables()
|
|
60
60
|
|
|
61
|
-
const DD_AAS_DOTNET_EXTENSION_VERSION = getValueFromEnvSources('DD_AAS_DOTNET_EXTENSION_VERSION')
|
|
62
61
|
const DD_AZURE_RESOURCE_GROUP = getValueFromEnvSources('DD_AZURE_RESOURCE_GROUP')
|
|
63
62
|
|
|
64
63
|
const subscriptionID = extractSubscriptionID(WEBSITE_OWNER_NAME)
|
|
@@ -77,7 +76,6 @@ function buildMetadata () {
|
|
|
77
76
|
: (WEBSITE_RESOURCE_GROUP ?? extractResourceGroup(WEBSITE_OWNER_NAME))
|
|
78
77
|
|
|
79
78
|
return trimObject({
|
|
80
|
-
extensionVersion: DD_AAS_DOTNET_EXTENSION_VERSION,
|
|
81
79
|
functionRuntimeVersion: FUNCTIONS_EXTENSION_VERSION,
|
|
82
80
|
instanceID: WEBSITE_INSTANCE_ID,
|
|
83
81
|
instanceName: COMPUTERNAME,
|
|
@@ -16,6 +16,12 @@ const session = require('../../../debugger/devtools_client/session')
|
|
|
16
16
|
const { getGeneratedPosition } = require('../../../debugger/devtools_client/source-maps')
|
|
17
17
|
// TODO: move debugger/devtools_client/snapshot to common place
|
|
18
18
|
const { getLocalStateForCallFrame } = require('../../../debugger/devtools_client/snapshot')
|
|
19
|
+
const {
|
|
20
|
+
DEFAULT_MAX_REFERENCE_DEPTH,
|
|
21
|
+
DEFAULT_MAX_COLLECTION_SIZE,
|
|
22
|
+
DEFAULT_MAX_FIELD_COUNT,
|
|
23
|
+
DEFAULT_MAX_LENGTH,
|
|
24
|
+
} = require('../../../debugger/devtools_client/snapshot/constants')
|
|
19
25
|
// TODO: move debugger/devtools_client/state to common place
|
|
20
26
|
const {
|
|
21
27
|
findScriptFromPartialPath,
|
|
@@ -29,6 +35,13 @@ let sessionStarted = false
|
|
|
29
35
|
const breakpointIdToProbe = new Map()
|
|
30
36
|
const probeIdToBreakpointId = new Map()
|
|
31
37
|
|
|
38
|
+
const limits = {
|
|
39
|
+
maxReferenceDepth: DEFAULT_MAX_REFERENCE_DEPTH,
|
|
40
|
+
maxCollectionSize: DEFAULT_MAX_COLLECTION_SIZE,
|
|
41
|
+
maxFieldCount: DEFAULT_MAX_FIELD_COUNT,
|
|
42
|
+
maxLength: DEFAULT_MAX_LENGTH,
|
|
43
|
+
}
|
|
44
|
+
|
|
32
45
|
session.on('Debugger.paused', async ({ params: { hitBreakpoints: [hitBreakpoint], callFrames } }) => {
|
|
33
46
|
const probe = breakpointIdToProbe.get(hitBreakpoint)
|
|
34
47
|
if (!probe) {
|
|
@@ -38,7 +51,7 @@ session.on('Debugger.paused', async ({ params: { hitBreakpoints: [hitBreakpoint]
|
|
|
38
51
|
|
|
39
52
|
const stack = await getStackFromCallFrames(callFrames)
|
|
40
53
|
|
|
41
|
-
const { processLocalState } = await getLocalStateForCallFrame(callFrames[0])
|
|
54
|
+
const { processLocalState } = await getLocalStateForCallFrame(callFrames[0], limits)
|
|
42
55
|
|
|
43
56
|
await session.post('Debugger.resume')
|
|
44
57
|
|
|
@@ -206,6 +206,7 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
206
206
|
requireGit,
|
|
207
207
|
isEarlyFlakeDetectionEnabled,
|
|
208
208
|
earlyFlakeDetectionNumRetries,
|
|
209
|
+
earlyFlakeDetectionSlowTestRetries,
|
|
209
210
|
earlyFlakeDetectionFaultyThreshold,
|
|
210
211
|
isFlakyTestRetriesEnabled,
|
|
211
212
|
isDiEnabled,
|
|
@@ -222,6 +223,7 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
222
223
|
requireGit,
|
|
223
224
|
isEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled && this._config.isEarlyFlakeDetectionEnabled,
|
|
224
225
|
earlyFlakeDetectionNumRetries,
|
|
226
|
+
earlyFlakeDetectionSlowTestRetries,
|
|
225
227
|
earlyFlakeDetectionFaultyThreshold,
|
|
226
228
|
isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled,
|
|
227
229
|
flakyTestRetriesCount: this._config.flakyTestRetriesCount,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const request = require('../../exporters/common/request')
|
|
4
3
|
const id = require('../../id')
|
|
5
4
|
const log = require('../../log')
|
|
6
5
|
const { getValueFromEnvSources } = require('../../config/helper')
|
|
@@ -13,8 +12,10 @@ const {
|
|
|
13
12
|
TELEMETRY_GIT_REQUESTS_SETTINGS_RESPONSE,
|
|
14
13
|
} = require('../telemetry')
|
|
15
14
|
const { writeSettingsToCache } = require('../test-optimization-cache')
|
|
15
|
+
const request = require('./request')
|
|
16
16
|
|
|
17
17
|
const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2
|
|
18
|
+
const DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES = { '5s': 10, '10s': 5, '30s': 3, '5m': 2 }
|
|
18
19
|
const DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD = 30
|
|
19
20
|
|
|
20
21
|
function getLibraryConfiguration ({
|
|
@@ -115,6 +116,8 @@ function getLibraryConfiguration ({
|
|
|
115
116
|
isEarlyFlakeDetectionEnabled: isKnownTestsEnabled && (earlyFlakeDetectionConfig?.enabled ?? false),
|
|
116
117
|
earlyFlakeDetectionNumRetries:
|
|
117
118
|
earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
|
|
119
|
+
earlyFlakeDetectionSlowTestRetries:
|
|
120
|
+
earlyFlakeDetectionConfig?.slow_test_retries ?? DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
|
|
118
121
|
earlyFlakeDetectionFaultyThreshold:
|
|
119
122
|
earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
|
|
120
123
|
isFlakyTestRetriesEnabled,
|