dd-trace 3.56.0 → 3.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ci/init.js +7 -0
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +14 -6
- package/package.json +4 -4
- package/packages/datadog-esbuild/index.js +8 -2
- package/packages/datadog-instrumentations/src/aws-sdk.js +4 -1
- package/packages/datadog-instrumentations/src/cucumber.js +182 -105
- package/packages/datadog-instrumentations/src/helpers/fetch.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/lodash.js +31 -0
- package/packages/datadog-instrumentations/src/openai.js +149 -0
- package/packages/datadog-instrumentations/src/playwright.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/index.js +3 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sfn.js +7 -0
- package/packages/datadog-plugin-aws-sdk/src/services/states.js +7 -0
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +64 -0
- package/packages/datadog-plugin-cucumber/src/index.js +83 -11
- package/packages/datadog-plugin-fetch/src/index.js +5 -2
- package/packages/datadog-plugin-openai/src/index.js +159 -32
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +3 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +1 -9
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +4 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +55 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/hardcoded-password-analyzer.js +13 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +6 -6
- package/packages/dd-trace/src/appsec/remote_config/index.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +56 -0
- package/packages/dd-trace/src/ci-visibility/exporters/{jest-worker → test-worker}/writer.js +7 -0
- package/packages/dd-trace/src/config.js +7 -0
- package/packages/dd-trace/src/exporter.js +2 -1
- package/packages/dd-trace/src/plugins/database.js +20 -5
- package/packages/dd-trace/src/plugins/util/test.js +7 -0
- package/packages/dd-trace/src/proxy.js +26 -6
- package/packages/dd-trace/src/telemetry/index.js +9 -3
- package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/index.js +0 -33
|
@@ -6,6 +6,7 @@ const vulnerabilities = require('../../vulnerabilities')
|
|
|
6
6
|
const { contains, intersects, remove } = require('./range-utils')
|
|
7
7
|
|
|
8
8
|
const commandSensitiveAnalyzer = require('./sensitive-analyzers/command-sensitive-analyzer')
|
|
9
|
+
const hardcodedPasswordAnalyzer = require('./sensitive-analyzers/hardcoded-password-analyzer')
|
|
9
10
|
const headerSensitiveAnalyzer = require('./sensitive-analyzers/header-sensitive-analyzer')
|
|
10
11
|
const jsonSensitiveAnalyzer = require('./sensitive-analyzers/json-sensitive-analyzer')
|
|
11
12
|
const ldapSensitiveAnalyzer = require('./sensitive-analyzers/ldap-sensitive-analyzer')
|
|
@@ -31,6 +32,9 @@ class SensitiveHandler {
|
|
|
31
32
|
this._sensitiveAnalyzers.set(vulnerabilities.HEADER_INJECTION, (evidence) => {
|
|
32
33
|
return headerSensitiveAnalyzer(evidence, this._namePattern, this._valuePattern)
|
|
33
34
|
})
|
|
35
|
+
this._sensitiveAnalyzers.set(vulnerabilities.HARDCODED_PASSWORD, (evidence) => {
|
|
36
|
+
return hardcodedPasswordAnalyzer(evidence, this._valuePattern)
|
|
37
|
+
})
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
isSensibleName (name) {
|
|
@@ -51,7 +55,9 @@ class SensitiveHandler {
|
|
|
51
55
|
const sensitiveAnalyzer = this._sensitiveAnalyzers.get(vulnerabilityType)
|
|
52
56
|
if (sensitiveAnalyzer) {
|
|
53
57
|
const sensitiveRanges = sensitiveAnalyzer(evidence)
|
|
54
|
-
|
|
58
|
+
if (evidence.ranges || sensitiveRanges?.length) {
|
|
59
|
+
return this.toRedactedJson(evidence, sensitiveRanges, sourcesIndexes, sources)
|
|
60
|
+
}
|
|
55
61
|
}
|
|
56
62
|
return null
|
|
57
63
|
}
|
|
@@ -67,7 +73,7 @@ class SensitiveHandler {
|
|
|
67
73
|
let nextTaintedIndex = 0
|
|
68
74
|
let sourceIndex
|
|
69
75
|
|
|
70
|
-
let nextTainted = ranges
|
|
76
|
+
let nextTainted = ranges?.shift()
|
|
71
77
|
let nextSensitive = sensitive.shift()
|
|
72
78
|
|
|
73
79
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -49,6 +49,10 @@ class VulnerabilityFormatter {
|
|
|
49
49
|
evidence.ranges = ranges
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
if (!evidence.ranges) {
|
|
53
|
+
return { value: evidence.value }
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
evidence.ranges.forEach((range, rangeIndex) => {
|
|
53
57
|
if (fromIndex < range.start) {
|
|
54
58
|
valueParts.push({ value: evidence.value.substring(fromIndex, range.start) })
|
|
@@ -65,12 +69,8 @@ class VulnerabilityFormatter {
|
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
formatEvidence (type, evidence, sourcesIndexes, sources) {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
return undefined
|
|
71
|
-
} else {
|
|
72
|
-
return { value: evidence.value }
|
|
73
|
-
}
|
|
72
|
+
if (typeof evidence.value === 'undefined') {
|
|
73
|
+
return undefined
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
return this._redactVulnearbilities
|
|
@@ -8,7 +8,7 @@ const apiSecuritySampler = require('../api_security_sampler')
|
|
|
8
8
|
|
|
9
9
|
let rc
|
|
10
10
|
|
|
11
|
-
function enable (config) {
|
|
11
|
+
function enable (config, appsec) {
|
|
12
12
|
rc = new RemoteConfigManager(config)
|
|
13
13
|
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_CUSTOM_TAGS, true)
|
|
14
14
|
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_HTTP_HEADER_TAGS, true)
|
|
@@ -31,7 +31,7 @@ function enable (config) {
|
|
|
31
31
|
if (!rcConfig) return
|
|
32
32
|
|
|
33
33
|
if (activation === Activation.ONECLICK) {
|
|
34
|
-
enableOrDisableAppsec(action, rcConfig, config)
|
|
34
|
+
enableOrDisableAppsec(action, rcConfig, config, appsec)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
apiSecuritySampler.setRequestSampling(rcConfig.api_security?.request_sample_rate)
|
|
@@ -41,7 +41,7 @@ function enable (config) {
|
|
|
41
41
|
return rc
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function enableOrDisableAppsec (action, rcConfig, config) {
|
|
44
|
+
function enableOrDisableAppsec (action, rcConfig, config, appsec) {
|
|
45
45
|
if (typeof rcConfig.asm?.enabled === 'boolean') {
|
|
46
46
|
let shouldEnable
|
|
47
47
|
|
|
@@ -52,9 +52,9 @@ function enableOrDisableAppsec (action, rcConfig, config) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (shouldEnable) {
|
|
55
|
-
|
|
55
|
+
appsec.enable(config)
|
|
56
56
|
} else {
|
|
57
|
-
|
|
57
|
+
appsec.disable()
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Writer = require('./writer')
|
|
4
|
+
const {
|
|
5
|
+
JEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
6
|
+
JEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
7
|
+
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE
|
|
8
|
+
} = require('../../../plugins/util/test')
|
|
9
|
+
|
|
10
|
+
function getInterprocessTraceCode () {
|
|
11
|
+
if (process.env.JEST_WORKER_ID) {
|
|
12
|
+
return JEST_WORKER_TRACE_PAYLOAD_CODE
|
|
13
|
+
}
|
|
14
|
+
if (process.env.CUCUMBER_WORKER_ID) {
|
|
15
|
+
return CUCUMBER_WORKER_TRACE_PAYLOAD_CODE
|
|
16
|
+
}
|
|
17
|
+
return null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// TODO: make it available with cucumber
|
|
21
|
+
function getInterprocessCoverageCode () {
|
|
22
|
+
if (process.env.JEST_WORKER_ID) {
|
|
23
|
+
return JEST_WORKER_COVERAGE_PAYLOAD_CODE
|
|
24
|
+
}
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Lightweight exporter whose writers only do simple JSON serialization
|
|
30
|
+
* of trace and coverage payloads, which they send to the test framework's main process.
|
|
31
|
+
* Currently used by Jest and Cucumber workers.
|
|
32
|
+
*/
|
|
33
|
+
class TestWorkerCiVisibilityExporter {
|
|
34
|
+
constructor () {
|
|
35
|
+
const interprocessTraceCode = getInterprocessTraceCode()
|
|
36
|
+
const interprocessCoverageCode = getInterprocessCoverageCode()
|
|
37
|
+
|
|
38
|
+
this._writer = new Writer(interprocessTraceCode)
|
|
39
|
+
this._coverageWriter = new Writer(interprocessCoverageCode)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export (payload) {
|
|
43
|
+
this._writer.append(payload)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
exportCoverage (formattedCoverage) {
|
|
47
|
+
this._coverageWriter.append(formattedCoverage)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
flush () {
|
|
51
|
+
this._writer.flush()
|
|
52
|
+
this._coverageWriter.flush()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = TestWorkerCiVisibilityExporter
|
|
@@ -23,11 +23,18 @@ class Writer {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
_sendPayload (data) {
|
|
26
|
+
// ## Jest
|
|
26
27
|
// Only available when `child_process` is used for the jest worker.
|
|
27
28
|
// eslint-disable-next-line
|
|
28
29
|
// https://github.com/facebook/jest/blob/bb39cb2c617a3334bf18daeca66bd87b7ccab28b/packages/jest-worker/README.md#experimental-worker
|
|
29
30
|
// If worker_threads is used, this will not work
|
|
30
31
|
// TODO: make it compatible with worker_threads
|
|
32
|
+
|
|
33
|
+
// ## Cucumber
|
|
34
|
+
// This reports to the test's main process the same way test data is reported by Cucumber
|
|
35
|
+
// See cucumber code:
|
|
36
|
+
// eslint-disable-next-line
|
|
37
|
+
// https://github.com/cucumber/cucumber-js/blob/5ce371870b677fe3d1a14915dc535688946f734c/src/runtime/parallel/run_worker.ts#L13
|
|
31
38
|
if (process.send) { // it only works if process.send is available
|
|
32
39
|
process.send([this._interprocessCode, data])
|
|
33
40
|
}
|
|
@@ -446,6 +446,7 @@ class Config {
|
|
|
446
446
|
this._setValue(defaults, 'appsec.obfuscatorValueRegex', defaultWafObfuscatorValueRegex)
|
|
447
447
|
this._setValue(defaults, 'appsec.rateLimit', 100)
|
|
448
448
|
this._setValue(defaults, 'appsec.rules', undefined)
|
|
449
|
+
this._setValue(defaults, 'appsec.sca.enabled', null)
|
|
449
450
|
this._setValue(defaults, 'appsec.wafTimeout', 5e3) // µs
|
|
450
451
|
this._setValue(defaults, 'clientIpEnabled', false)
|
|
451
452
|
this._setValue(defaults, 'clientIpHeader', null)
|
|
@@ -516,6 +517,7 @@ class Config {
|
|
|
516
517
|
this._setValue(defaults, 'tracing', true)
|
|
517
518
|
this._setValue(defaults, 'url', undefined)
|
|
518
519
|
this._setValue(defaults, 'version', pkg.version)
|
|
520
|
+
this._setValue(defaults, 'instrumentation_config_id', undefined)
|
|
519
521
|
}
|
|
520
522
|
|
|
521
523
|
_applyEnvironment () {
|
|
@@ -528,6 +530,7 @@ class Config {
|
|
|
528
530
|
DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
|
|
529
531
|
DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
|
|
530
532
|
DD_APPSEC_RULES,
|
|
533
|
+
DD_APPSEC_SCA_ENABLED,
|
|
531
534
|
DD_APPSEC_TRACE_RATE_LIMIT,
|
|
532
535
|
DD_APPSEC_WAF_TIMEOUT,
|
|
533
536
|
DD_DATA_STREAMS_ENABLED,
|
|
@@ -547,6 +550,7 @@ class Config {
|
|
|
547
550
|
DD_IAST_REQUEST_SAMPLING,
|
|
548
551
|
DD_IAST_TELEMETRY_VERBOSITY,
|
|
549
552
|
DD_INSTRUMENTATION_TELEMETRY_ENABLED,
|
|
553
|
+
DD_INSTRUMENTATION_CONFIG_ID,
|
|
550
554
|
DD_LOGS_INJECTION,
|
|
551
555
|
DD_OPENAI_LOGS_ENABLED,
|
|
552
556
|
DD_OPENAI_SPAN_CHAR_LIMIT,
|
|
@@ -615,6 +619,8 @@ class Config {
|
|
|
615
619
|
this._setString(env, 'appsec.obfuscatorValueRegex', DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP)
|
|
616
620
|
this._setValue(env, 'appsec.rateLimit', maybeInt(DD_APPSEC_TRACE_RATE_LIMIT))
|
|
617
621
|
this._setString(env, 'appsec.rules', DD_APPSEC_RULES)
|
|
622
|
+
// DD_APPSEC_SCA_ENABLED is never used locally, but only sent to the backend
|
|
623
|
+
this._setBoolean(env, 'appsec.sca.enabled', DD_APPSEC_SCA_ENABLED)
|
|
618
624
|
this._setValue(env, 'appsec.wafTimeout', maybeInt(DD_APPSEC_WAF_TIMEOUT))
|
|
619
625
|
this._setBoolean(env, 'clientIpEnabled', DD_TRACE_CLIENT_IP_ENABLED)
|
|
620
626
|
this._setString(env, 'clientIpHeader', DD_TRACE_CLIENT_IP_HEADER)
|
|
@@ -695,6 +701,7 @@ class Config {
|
|
|
695
701
|
DD_INSTRUMENTATION_TELEMETRY_ENABLED, // to comply with instrumentation telemetry specs
|
|
696
702
|
!(this._isInServerlessEnvironment() || JEST_WORKER_ID)
|
|
697
703
|
))
|
|
704
|
+
this._setString(env, 'instrumentation_config_id', DD_INSTRUMENTATION_CONFIG_ID)
|
|
698
705
|
this._setBoolean(env, 'telemetry.debug', DD_TELEMETRY_DEBUG)
|
|
699
706
|
this._setBoolean(env, 'telemetry.dependencyCollection', DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED)
|
|
700
707
|
this._setValue(env, 'telemetry.heartbeatInterval', maybeInt(Math.floor(DD_TELEMETRY_HEARTBEAT_INTERVAL * 1000)))
|
|
@@ -18,7 +18,8 @@ module.exports = name => {
|
|
|
18
18
|
case exporters.AGENT_PROXY:
|
|
19
19
|
return require('./ci-visibility/exporters/agent-proxy')
|
|
20
20
|
case exporters.JEST_WORKER:
|
|
21
|
-
|
|
21
|
+
case exporters.CUCUMBER_WORKER:
|
|
22
|
+
return require('./ci-visibility/exporters/test-worker')
|
|
22
23
|
default:
|
|
23
24
|
return inAWSLambda && !usingLambdaExtension ? require('./exporters/log') : require('./exporters/agent')
|
|
24
25
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const StoragePlugin = require('./storage')
|
|
4
|
-
const { PEER_SERVICE_KEY } = require('../constants')
|
|
4
|
+
const { PEER_SERVICE_KEY, PEER_SERVICE_SOURCE_KEY } = require('../constants')
|
|
5
5
|
|
|
6
6
|
class DatabasePlugin extends StoragePlugin {
|
|
7
7
|
static get operation () { return 'query' }
|
|
@@ -28,16 +28,31 @@ class DatabasePlugin extends StoragePlugin {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
createDBMPropagationCommentService (serviceName) {
|
|
31
|
+
createDBMPropagationCommentService (serviceName, span) {
|
|
32
32
|
this.encodingServiceTags('dddbs', 'encodedDddbs', serviceName)
|
|
33
33
|
this.encodingServiceTags('dde', 'encodedDde', this.tracer._env)
|
|
34
34
|
this.encodingServiceTags('ddps', 'encodedDdps', this.tracer._service)
|
|
35
35
|
this.encodingServiceTags('ddpv', 'encodedDdpv', this.tracer._version)
|
|
36
|
+
if (span.context()._tags['out.host']) {
|
|
37
|
+
this.encodingServiceTags('ddh', 'encodedDdh', span._spanContext._tags['out.host'])
|
|
38
|
+
}
|
|
39
|
+
if (span.context()._tags['db.name']) {
|
|
40
|
+
this.encodingServiceTags('dddb', 'encodedDddb', span._spanContext._tags['db.name'])
|
|
41
|
+
}
|
|
36
42
|
|
|
37
|
-
const { encodedDddbs, encodedDde, encodedDdps, encodedDdpv } = this.serviceTags
|
|
43
|
+
const { encodedDddb, encodedDddbs, encodedDde, encodedDdh, encodedDdps, encodedDdpv } = this.serviceTags
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
let dbmComment = `dddb='${encodedDddb}',dddbs='${encodedDddbs}',dde='${encodedDde}',ddh='${encodedDdh}',` +
|
|
40
46
|
`ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
|
|
47
|
+
|
|
48
|
+
const peerData = this.getPeerService(span.context()._tags)
|
|
49
|
+
if (peerData !== undefined && peerData[PEER_SERVICE_SOURCE_KEY] === PEER_SERVICE_KEY) {
|
|
50
|
+
this.encodingServiceTags('ddprs', 'encodedDdprs', peerData[PEER_SERVICE_KEY])
|
|
51
|
+
|
|
52
|
+
const { encodedDdprs } = this.serviceTags
|
|
53
|
+
dbmComment += `,ddprs='${encodedDdprs}'`
|
|
54
|
+
}
|
|
55
|
+
return dbmComment
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
getDbmServiceName (span, tracerService) {
|
|
@@ -56,7 +71,7 @@ class DatabasePlugin extends StoragePlugin {
|
|
|
56
71
|
return query
|
|
57
72
|
}
|
|
58
73
|
|
|
59
|
-
const servicePropagation = this.createDBMPropagationCommentService(dbmService)
|
|
74
|
+
const servicePropagation = this.createDBMPropagationCommentService(dbmService, span)
|
|
60
75
|
|
|
61
76
|
if (isPreparedStatement || mode === 'service') {
|
|
62
77
|
return `/*${servicePropagation}*/ ${query}`
|
|
@@ -61,6 +61,8 @@ const CI_APP_ORIGIN = 'ciapp-test'
|
|
|
61
61
|
const JEST_TEST_RUNNER = 'test.jest.test_runner'
|
|
62
62
|
const JEST_DISPLAY_NAME = 'test.jest.display_name'
|
|
63
63
|
|
|
64
|
+
const CUCUMBER_IS_PARALLEL = 'test.cucumber.is_parallel'
|
|
65
|
+
|
|
64
66
|
const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
|
|
65
67
|
const TEST_ITR_SKIPPING_ENABLED = 'test.itr.tests_skipping.enabled'
|
|
66
68
|
const TEST_ITR_SKIPPING_TYPE = 'test.itr.tests_skipping.type'
|
|
@@ -82,6 +84,9 @@ const TEST_BROWSER_VERSION = 'test.browser.version'
|
|
|
82
84
|
const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
|
|
83
85
|
const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
|
|
84
86
|
|
|
87
|
+
// cucumber worker variables
|
|
88
|
+
const CUCUMBER_WORKER_TRACE_PAYLOAD_CODE = 70
|
|
89
|
+
|
|
85
90
|
// Early flake detection util strings
|
|
86
91
|
const EFD_STRING = "Retried by Datadog's Early Flake Detection"
|
|
87
92
|
const EFD_TEST_NAME_REGEX = new RegExp(EFD_STRING + ' \\(#\\d+\\): ', 'g')
|
|
@@ -92,6 +97,7 @@ module.exports = {
|
|
|
92
97
|
TEST_FRAMEWORK_VERSION,
|
|
93
98
|
JEST_TEST_RUNNER,
|
|
94
99
|
JEST_DISPLAY_NAME,
|
|
100
|
+
CUCUMBER_IS_PARALLEL,
|
|
95
101
|
TEST_TYPE,
|
|
96
102
|
TEST_NAME,
|
|
97
103
|
TEST_SUITE,
|
|
@@ -104,6 +110,7 @@ module.exports = {
|
|
|
104
110
|
LIBRARY_VERSION,
|
|
105
111
|
JEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
106
112
|
JEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
113
|
+
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
107
114
|
TEST_SOURCE_START,
|
|
108
115
|
TEST_SKIPPED_BY_ITR,
|
|
109
116
|
TEST_CONFIGURATION_BROWSER_NAME,
|
|
@@ -15,6 +15,21 @@ const NoopDogStatsDClient = require('./noop/dogstatsd')
|
|
|
15
15
|
const spanleak = require('./spanleak')
|
|
16
16
|
const { SSITelemetry } = require('./profiling/ssi-telemetry')
|
|
17
17
|
|
|
18
|
+
class LazyModule {
|
|
19
|
+
constructor (provider) {
|
|
20
|
+
this.provider = provider
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
enable (...args) {
|
|
24
|
+
this.module = this.provider()
|
|
25
|
+
this.module.enable(...args)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
disable () {
|
|
29
|
+
this.module?.disable()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
class Tracer extends NoopProxy {
|
|
19
34
|
constructor () {
|
|
20
35
|
super()
|
|
@@ -24,6 +39,12 @@ class Tracer extends NoopProxy {
|
|
|
24
39
|
this._pluginManager = new PluginManager(this)
|
|
25
40
|
this.dogstatsd = new NoopDogStatsDClient()
|
|
26
41
|
this._tracingInitialized = false
|
|
42
|
+
|
|
43
|
+
// these requires must work with esm bundler
|
|
44
|
+
this._modules = {
|
|
45
|
+
appsec: new LazyModule(() => require('./appsec')),
|
|
46
|
+
iast: new LazyModule(() => require('./appsec/iast'))
|
|
47
|
+
}
|
|
27
48
|
}
|
|
28
49
|
|
|
29
50
|
init (options) {
|
|
@@ -58,7 +79,7 @@ class Tracer extends NoopProxy {
|
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
if (config.remoteConfig.enabled && !config.isCiVisibility) {
|
|
61
|
-
const rc = remoteConfig.enable(config)
|
|
82
|
+
const rc = remoteConfig.enable(config, this._modules.appsec)
|
|
62
83
|
|
|
63
84
|
rc.on('APM_TRACING', (action, conf) => {
|
|
64
85
|
if (action === 'unapply') {
|
|
@@ -113,9 +134,8 @@ class Tracer extends NoopProxy {
|
|
|
113
134
|
|
|
114
135
|
_enableOrDisableTracing (config) {
|
|
115
136
|
if (config.tracing !== false) {
|
|
116
|
-
// dirty require for now so zero appsec code is executed unless explicitly enabled
|
|
117
137
|
if (config.appsec.enabled) {
|
|
118
|
-
|
|
138
|
+
this._modules.appsec.enable(config)
|
|
119
139
|
}
|
|
120
140
|
if (!this._tracingInitialized) {
|
|
121
141
|
this._tracer = new DatadogTracer(config)
|
|
@@ -123,11 +143,11 @@ class Tracer extends NoopProxy {
|
|
|
123
143
|
this._tracingInitialized = true
|
|
124
144
|
}
|
|
125
145
|
if (config.iast.enabled) {
|
|
126
|
-
|
|
146
|
+
this._modules.iast.enable(config, this._tracer)
|
|
127
147
|
}
|
|
128
148
|
} else if (this._tracingInitialized) {
|
|
129
|
-
|
|
130
|
-
|
|
149
|
+
this._modules.appsec.disable()
|
|
150
|
+
this._modules.iast.disable()
|
|
131
151
|
}
|
|
132
152
|
|
|
133
153
|
if (this._tracingInitialized) {
|
|
@@ -6,7 +6,8 @@ const dependencies = require('./dependencies')
|
|
|
6
6
|
const { sendData } = require('./send-data')
|
|
7
7
|
const { errors } = require('../startup-log')
|
|
8
8
|
const { manager: metricsManager } = require('./metrics')
|
|
9
|
-
const
|
|
9
|
+
const telemetryLogger = require('./logs')
|
|
10
|
+
const logger = require('../log')
|
|
10
11
|
|
|
11
12
|
const telemetryStartChannel = dc.channel('datadog:telemetry:start')
|
|
12
13
|
const telemetryStopChannel = dc.channel('datadog:telemetry:stop')
|
|
@@ -211,7 +212,7 @@ function createPayload (currReqType, currPayload = {}) {
|
|
|
211
212
|
function heartbeat (config, application, host) {
|
|
212
213
|
heartbeatTimeout = setTimeout(() => {
|
|
213
214
|
metricsManager.send(config, application, host)
|
|
214
|
-
|
|
215
|
+
telemetryLogger.send(config, application, host)
|
|
215
216
|
|
|
216
217
|
const { reqType, payload } = createPayload('app-heartbeat')
|
|
217
218
|
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
@@ -235,6 +236,10 @@ function extendedHeartbeat (config) {
|
|
|
235
236
|
|
|
236
237
|
function start (aConfig, thePluginManager) {
|
|
237
238
|
if (!aConfig.telemetry.enabled) {
|
|
239
|
+
if (aConfig.sca?.enabled) {
|
|
240
|
+
logger.warn('DD_APPSEC_SCA_ENABLED requires enabling telemetry to work.')
|
|
241
|
+
}
|
|
242
|
+
|
|
238
243
|
return
|
|
239
244
|
}
|
|
240
245
|
config = aConfig
|
|
@@ -245,7 +250,7 @@ function start (aConfig, thePluginManager) {
|
|
|
245
250
|
integrations = getIntegrations()
|
|
246
251
|
|
|
247
252
|
dependencies.start(config, application, host, getRetryData, updateRetryData)
|
|
248
|
-
|
|
253
|
+
telemetryLogger.start(config)
|
|
249
254
|
|
|
250
255
|
sendData(config, application, host, 'app-started', appStarted(config))
|
|
251
256
|
|
|
@@ -318,6 +323,7 @@ function updateConfig (changes, config) {
|
|
|
318
323
|
|
|
319
324
|
for (const change of changes) {
|
|
320
325
|
const name = nameMapping[change.name] || change.name
|
|
326
|
+
|
|
321
327
|
names.push(name)
|
|
322
328
|
const { origin, value } = change
|
|
323
329
|
const entry = { name, value, origin }
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const Writer = require('./writer')
|
|
4
|
-
const {
|
|
5
|
-
JEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
6
|
-
JEST_WORKER_TRACE_PAYLOAD_CODE
|
|
7
|
-
} = require('../../../plugins/util/test')
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Lightweight exporter whose writers only do simple JSON serialization
|
|
11
|
-
* of trace and coverage payloads, which they send to the jest main process.
|
|
12
|
-
*/
|
|
13
|
-
class JestWorkerCiVisibilityExporter {
|
|
14
|
-
constructor () {
|
|
15
|
-
this._writer = new Writer(JEST_WORKER_TRACE_PAYLOAD_CODE)
|
|
16
|
-
this._coverageWriter = new Writer(JEST_WORKER_COVERAGE_PAYLOAD_CODE)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export (payload) {
|
|
20
|
-
this._writer.append(payload)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
exportCoverage (formattedCoverage) {
|
|
24
|
-
this._coverageWriter.append(formattedCoverage)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
flush () {
|
|
28
|
-
this._writer.flush()
|
|
29
|
-
this._coverageWriter.flush()
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
module.exports = JestWorkerCiVisibilityExporter
|