dd-trace 5.0.0 → 5.1.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/MIGRATING.md +15 -0
- package/README.md +11 -9
- package/package.json +4 -3
- package/packages/datadog-instrumentations/src/cucumber.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +1 -0
- package/packages/datadog-instrumentations/src/mocha.js +9 -2
- package/packages/datadog-plugin-cucumber/src/index.js +11 -7
- package/packages/datadog-plugin-cypress/src/plugin.js +60 -46
- package/packages/datadog-plugin-jest/src/index.js +7 -1
- package/packages/datadog-plugin-mocha/src/index.js +11 -2
- package/packages/datadog-plugin-playwright/src/index.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +3 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +1 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +12 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
- package/packages/dd-trace/src/appsec/reporter.js +2 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +4 -2
- package/packages/dd-trace/src/config.js +10 -6
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +25 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +9 -3
- package/packages/dd-trace/src/plugins/util/test.js +2 -0
- package/packages/dd-trace/src/profiling/config.js +19 -5
- package/packages/dd-trace/src/telemetry/index.js +8 -3
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/scripts/st.js +105 -0
package/MIGRATING.md
CHANGED
|
@@ -4,6 +4,21 @@ This guide describes the steps to upgrade dd-trace from a major version to the
|
|
|
4
4
|
next. If you are having any issues related to migrating, please feel free to
|
|
5
5
|
open an issue or contact our [support](https://www.datadoghq.com/support/) team.
|
|
6
6
|
|
|
7
|
+
## 4.0 to 5.0
|
|
8
|
+
|
|
9
|
+
### Node 16 is no longer supported
|
|
10
|
+
|
|
11
|
+
Node.js 16 has reached EOL in September 2023 and is no longer supported. Generally
|
|
12
|
+
speaking, we highly recommend always keeping Node.js up to date regardless of
|
|
13
|
+
our support policy.
|
|
14
|
+
|
|
15
|
+
### Update `trace<T>` TypeScript declaration
|
|
16
|
+
|
|
17
|
+
The TypeScript declaration for `trace<T>` has been updated to enforce
|
|
18
|
+
that calls to `tracer.trace(name, fn)` must receive a function which takes at least
|
|
19
|
+
the span object. Previously the span was technically optional when it should not have
|
|
20
|
+
been as the span must be handled.
|
|
21
|
+
|
|
7
22
|
## 3.0 to 4.0
|
|
8
23
|
|
|
9
24
|
### Node 14 is no longer supported
|
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# `dd-trace`: Node.js APM Tracer Library
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/dd-trace)
|
|
4
|
+
[](https://www.npmjs.com/package/dd-trace/v/latest-node16)
|
|
5
|
+
[](https://www.npmjs.com/package/dd-trace/v/latest-node14)
|
|
5
6
|
[](https://codecov.io/gh/DataDog/dd-trace-js)
|
|
6
7
|
|
|
7
8
|
<img align="right" src="https://user-images.githubusercontent.com/551402/208212084-1d0c07e2-4135-4c61-b2da-8f2fddbc66ed.png" alt="Bits the dog JavaScript" width="200px"/>
|
|
@@ -28,24 +29,25 @@ Most of the documentation for `dd-trace` is available on these webpages:
|
|
|
28
29
|
| [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) |  | `>= v12` | **End of Life** | 2021-07-13 | 2022-02-25 |
|
|
29
30
|
| [`v2`](https://github.com/DataDog/dd-trace-js/tree/v2.x) |  | `>= v12` | **End of Life** | 2022-01-28 | 2023-08-15 |
|
|
30
31
|
| [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) |  | `>= v14` | **Maintenance** | 2022-08-15 | 2024-05-15 |
|
|
31
|
-
| [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) |  | `>= v16` | **
|
|
32
|
+
| [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) |  | `>= v16` | **Maintenance** | 2023-05-12 | 2025-01-11 |
|
|
33
|
+
| [`v5`](https://github.com/DataDog/dd-trace-js/tree/v5.x) |  | `>= v18` | **Current** | 2024-01-11 | Unknown |
|
|
32
34
|
|
|
33
|
-
We currently maintain
|
|
34
|
-
Features and bug fixes that are merged are released to the `
|
|
35
|
+
We currently maintain three release lines, namely `v5`, `v4` and `v3`.
|
|
36
|
+
Features and bug fixes that are merged are released to the `v5` line and, if appropriate, also the `v4` & `v3` line.
|
|
35
37
|
|
|
36
|
-
For any new projects it is recommended to use the `
|
|
38
|
+
For any new projects it is recommended to use the `v5` release line:
|
|
37
39
|
|
|
38
40
|
```sh
|
|
39
41
|
$ npm install dd-trace
|
|
40
42
|
$ yarn add dd-trace
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
However, existing projects that already use the `v3` release line, or projects that need to support EOL versions of Node.js, may continue to use these release lines.
|
|
45
|
+
However, existing projects that already use the `v4` & `v3` release line, or projects that need to support EOL versions of Node.js, may continue to use these release lines.
|
|
44
46
|
This is done by specifying the version when installing the package.
|
|
45
47
|
|
|
46
48
|
```sh
|
|
47
|
-
$ npm install dd-trace@
|
|
48
|
-
$ yarn add dd-trace@
|
|
49
|
+
$ npm install dd-trace@4
|
|
50
|
+
$ yarn add dd-trace@4
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
Any backwards-breaking functionality that is introduced into the library will result in an increase of the major version of the library and therefore a new release line.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"test:integration:cucumber": "mocha --colors --timeout 30000 \"integration-tests/cucumber/*.spec.js\"",
|
|
37
37
|
"test:integration:cypress": "mocha --colors --timeout 30000 \"integration-tests/cypress/*.spec.js\"",
|
|
38
38
|
"test:integration:playwright": "mocha --colors --timeout 30000 \"integration-tests/playwright/*.spec.js\"",
|
|
39
|
+
"test:integration:profiler": "mocha --colors --timeout 90000 \"integration-tests/profiler/*.spec.js\"",
|
|
39
40
|
"test:integration:serverless": "mocha --colors --timeout 30000 \"integration-tests/serverless/*.spec.js\"",
|
|
40
41
|
"test:integration:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/integration-test/**/*.spec.js\"",
|
|
41
42
|
"test:unit:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\" --exclude \"packages/datadog-plugin-@($(echo $PLUGINS))/test/integration-test/**/*.spec.js\"",
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
"node": ">=18"
|
|
69
70
|
},
|
|
70
71
|
"dependencies": {
|
|
71
|
-
"@datadog/native-appsec": "
|
|
72
|
+
"@datadog/native-appsec": "7.0.0",
|
|
72
73
|
"@datadog/native-iast-rewriter": "2.2.2",
|
|
73
74
|
"@datadog/native-iast-taint-tracking": "1.6.4",
|
|
74
75
|
"@datadog/native-metrics": "^2.0.0",
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
"crypto-randomuuid": "^1.0.0",
|
|
80
81
|
"dc-polyfill": "^0.1.2",
|
|
81
82
|
"ignore": "^5.2.4",
|
|
82
|
-
"import-in-the-middle": "^1.7.
|
|
83
|
+
"import-in-the-middle": "^1.7.3",
|
|
83
84
|
"int64-buffer": "^0.1.9",
|
|
84
85
|
"ipaddr.js": "^2.1.0",
|
|
85
86
|
"istanbul-lib-coverage": "3.2.0",
|
|
@@ -44,6 +44,7 @@ const patched = new WeakSet()
|
|
|
44
44
|
let pickleByFile = {}
|
|
45
45
|
const pickleResultByFile = {}
|
|
46
46
|
let skippableSuites = []
|
|
47
|
+
let itrCorrelationId = ''
|
|
47
48
|
let isForcedToRun = false
|
|
48
49
|
let isUnskippable = false
|
|
49
50
|
|
|
@@ -102,7 +103,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
102
103
|
const testSuitePath = getTestSuitePath(testSuiteFullPath, process.cwd())
|
|
103
104
|
isForcedToRun = isUnskippable && skippableSuites.includes(testSuitePath)
|
|
104
105
|
|
|
105
|
-
testSuiteStartCh.publish({ testSuitePath, isUnskippable, isForcedToRun })
|
|
106
|
+
testSuiteStartCh.publish({ testSuitePath, isUnskippable, isForcedToRun, itrCorrelationId })
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
const testSourceLine = this.gherkinDocument &&
|
|
@@ -304,6 +305,7 @@ addHook({
|
|
|
304
305
|
this.pickleIds = picklesToRun
|
|
305
306
|
|
|
306
307
|
skippedSuites = Array.from(filteredPickles.skippedSuites)
|
|
308
|
+
itrCorrelationId = skippableResponse.itrCorrelationId
|
|
307
309
|
}
|
|
308
310
|
|
|
309
311
|
pickleByFile = getPickleByFile(this)
|
|
@@ -53,6 +53,7 @@ let isSuitesSkipped = false
|
|
|
53
53
|
let skippedSuites = []
|
|
54
54
|
const unskippableSuites = []
|
|
55
55
|
let isForcedToRun = false
|
|
56
|
+
let itrCorrelationId = ''
|
|
56
57
|
|
|
57
58
|
function getSuitesByTestFile (root) {
|
|
58
59
|
const suitesByTestFile = {}
|
|
@@ -191,7 +192,12 @@ function mochaHook (Runner) {
|
|
|
191
192
|
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
192
193
|
isForcedToRun = isUnskippable && suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
|
|
193
194
|
asyncResource.runInAsyncScope(() => {
|
|
194
|
-
testSuiteStartCh.publish({
|
|
195
|
+
testSuiteStartCh.publish({
|
|
196
|
+
testSuite: suite.file,
|
|
197
|
+
isUnskippable,
|
|
198
|
+
isForcedToRun,
|
|
199
|
+
itrCorrelationId
|
|
200
|
+
})
|
|
195
201
|
})
|
|
196
202
|
}
|
|
197
203
|
})
|
|
@@ -395,11 +401,12 @@ addHook({
|
|
|
395
401
|
}
|
|
396
402
|
})
|
|
397
403
|
|
|
398
|
-
const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
|
|
404
|
+
const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
|
|
399
405
|
if (err) {
|
|
400
406
|
suitesToSkip = []
|
|
401
407
|
} else {
|
|
402
408
|
suitesToSkip = skippableSuites
|
|
409
|
+
itrCorrelationId = responseItrCorrelationId
|
|
403
410
|
}
|
|
404
411
|
// We remove the suites that we skip through ITR
|
|
405
412
|
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
@@ -13,7 +13,8 @@ const {
|
|
|
13
13
|
addIntelligentTestRunnerSpanTags,
|
|
14
14
|
TEST_ITR_UNSKIPPABLE,
|
|
15
15
|
TEST_ITR_FORCED_RUN,
|
|
16
|
-
TEST_CODE_OWNERS
|
|
16
|
+
TEST_CODE_OWNERS,
|
|
17
|
+
ITR_CORRELATION_ID
|
|
17
18
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
18
19
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
19
20
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
@@ -74,7 +75,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
74
75
|
this.tracer._exporter.flush()
|
|
75
76
|
})
|
|
76
77
|
|
|
77
|
-
this.addSub('ci:cucumber:test-suite:start', ({ testSuitePath, isUnskippable, isForcedToRun }) => {
|
|
78
|
+
this.addSub('ci:cucumber:test-suite:start', ({ testSuitePath, isUnskippable, isForcedToRun, itrCorrelationId }) => {
|
|
78
79
|
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
79
80
|
this.command,
|
|
80
81
|
this.frameworkVersion,
|
|
@@ -89,6 +90,9 @@ class CucumberPlugin extends CiPlugin {
|
|
|
89
90
|
this.telemetry.count(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
|
|
90
91
|
testSuiteMetadata[TEST_ITR_FORCED_RUN] = 'true'
|
|
91
92
|
}
|
|
93
|
+
if (itrCorrelationId) {
|
|
94
|
+
testSuiteMetadata[ITR_CORRELATION_ID] = itrCorrelationId
|
|
95
|
+
}
|
|
92
96
|
this.testSuiteSpan = this.tracer.startSpan('cucumber.test_suite', {
|
|
93
97
|
childOf: this.testModuleSpan,
|
|
94
98
|
tags: {
|
|
@@ -169,12 +173,12 @@ class CucumberPlugin extends CiPlugin {
|
|
|
169
173
|
}
|
|
170
174
|
|
|
171
175
|
span.finish()
|
|
172
|
-
this.telemetry.ciVisEvent(
|
|
173
|
-
TELEMETRY_EVENT_FINISHED,
|
|
174
|
-
'test',
|
|
175
|
-
{ hasCodeOwners: !!span.context()._tags[TEST_CODE_OWNERS] }
|
|
176
|
-
)
|
|
177
176
|
if (!isStep) {
|
|
177
|
+
this.telemetry.ciVisEvent(
|
|
178
|
+
TELEMETRY_EVENT_FINISHED,
|
|
179
|
+
'test',
|
|
180
|
+
{ hasCodeOwners: !!span.context()._tags[TEST_CODE_OWNERS] }
|
|
181
|
+
)
|
|
178
182
|
finishAllTraceSpans(span)
|
|
179
183
|
}
|
|
180
184
|
})
|
|
@@ -23,7 +23,8 @@ const {
|
|
|
23
23
|
addIntelligentTestRunnerSpanTags,
|
|
24
24
|
TEST_SKIPPED_BY_ITR,
|
|
25
25
|
TEST_ITR_UNSKIPPABLE,
|
|
26
|
-
TEST_ITR_FORCED_RUN
|
|
26
|
+
TEST_ITR_FORCED_RUN,
|
|
27
|
+
ITR_CORRELATION_ID
|
|
27
28
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
28
29
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
29
30
|
const log = require('../../dd-trace/src/log')
|
|
@@ -39,6 +40,7 @@ const {
|
|
|
39
40
|
incrementCountMetric,
|
|
40
41
|
distributionMetric
|
|
41
42
|
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
43
|
+
const { appClosing: appClosingTelemetry } = require('../../dd-trace/src/telemetry')
|
|
42
44
|
const {
|
|
43
45
|
GIT_REPOSITORY_URL,
|
|
44
46
|
GIT_COMMIT_SHA,
|
|
@@ -137,10 +139,11 @@ function getSkippableTests (isSuitesSkippingEnabled, tracer, testConfiguration)
|
|
|
137
139
|
if (!tracer._tracer._exporter || !tracer._tracer._exporter.getItrConfiguration) {
|
|
138
140
|
return resolve({ err: new Error('CI Visibility was not initialized correctly') })
|
|
139
141
|
}
|
|
140
|
-
tracer._tracer._exporter.getSkippableSuites(testConfiguration, (err, skippableTests) => {
|
|
142
|
+
tracer._tracer._exporter.getSkippableSuites(testConfiguration, (err, skippableTests, correlationId) => {
|
|
141
143
|
resolve({
|
|
142
144
|
err,
|
|
143
|
-
skippableTests
|
|
145
|
+
skippableTests,
|
|
146
|
+
correlationId
|
|
144
147
|
})
|
|
145
148
|
})
|
|
146
149
|
})
|
|
@@ -214,6 +217,7 @@ module.exports = (on, config) => {
|
|
|
214
217
|
let isSuitesSkippingEnabled = false
|
|
215
218
|
let isCodeCoverageEnabled = false
|
|
216
219
|
let testsToSkip = []
|
|
220
|
+
let itrCorrelationId = ''
|
|
217
221
|
const unskippableSuites = []
|
|
218
222
|
let hasForcedToRunSuites = false
|
|
219
223
|
let hasUnskippableSuites = false
|
|
@@ -288,52 +292,54 @@ module.exports = (on, config) => {
|
|
|
288
292
|
isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
|
|
289
293
|
}
|
|
290
294
|
|
|
291
|
-
return getSkippableTests(isSuitesSkippingEnabled, tracer, testConfiguration)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
// `details.specs` are test files
|
|
299
|
-
details.specs.forEach(({ absolute, relative }) => {
|
|
300
|
-
const isUnskippableSuite = isMarkedAsUnskippable({ path: absolute })
|
|
301
|
-
if (isUnskippableSuite) {
|
|
302
|
-
unskippableSuites.push(relative)
|
|
295
|
+
return getSkippableTests(isSuitesSkippingEnabled, tracer, testConfiguration)
|
|
296
|
+
.then(({ err, skippableTests, correlationId }) => {
|
|
297
|
+
if (err) {
|
|
298
|
+
log.error(err)
|
|
299
|
+
} else {
|
|
300
|
+
testsToSkip = skippableTests || []
|
|
301
|
+
itrCorrelationId = correlationId
|
|
303
302
|
}
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
const childOf = getTestParentSpan(tracer)
|
|
307
|
-
rootDir = getRootDir(details)
|
|
308
|
-
|
|
309
|
-
command = getCypressCommand(details)
|
|
310
|
-
frameworkVersion = getCypressVersion(details)
|
|
311
|
-
|
|
312
|
-
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
|
|
313
|
-
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
|
|
314
303
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
304
|
+
// `details.specs` are test files
|
|
305
|
+
details.specs.forEach(({ absolute, relative }) => {
|
|
306
|
+
const isUnskippableSuite = isMarkedAsUnskippable({ path: absolute })
|
|
307
|
+
if (isUnskippableSuite) {
|
|
308
|
+
unskippableSuites.push(relative)
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
const childOf = getTestParentSpan(tracer)
|
|
313
|
+
rootDir = getRootDir(details)
|
|
314
|
+
|
|
315
|
+
command = getCypressCommand(details)
|
|
316
|
+
frameworkVersion = getCypressVersion(details)
|
|
317
|
+
|
|
318
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
|
|
319
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
|
|
320
|
+
|
|
321
|
+
testSessionSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_session`, {
|
|
322
|
+
childOf,
|
|
323
|
+
tags: {
|
|
324
|
+
[COMPONENT]: TEST_FRAMEWORK_NAME,
|
|
325
|
+
...testEnvironmentMetadata,
|
|
326
|
+
...testSessionSpanMetadata
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
ciVisEvent(TELEMETRY_EVENT_CREATED, 'session')
|
|
330
|
+
|
|
331
|
+
testModuleSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_module`, {
|
|
332
|
+
childOf: testSessionSpan,
|
|
333
|
+
tags: {
|
|
334
|
+
[COMPONENT]: TEST_FRAMEWORK_NAME,
|
|
335
|
+
...testEnvironmentMetadata,
|
|
336
|
+
...testModuleSpanMetadata
|
|
337
|
+
}
|
|
338
|
+
})
|
|
339
|
+
ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
|
|
340
|
+
|
|
341
|
+
return details
|
|
332
342
|
})
|
|
333
|
-
ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
|
|
334
|
-
|
|
335
|
-
return details
|
|
336
|
-
})
|
|
337
343
|
})
|
|
338
344
|
})
|
|
339
345
|
on('after:spec', (spec, { tests, stats }) => {
|
|
@@ -357,6 +363,9 @@ module.exports = (on, config) => {
|
|
|
357
363
|
if (isSkippedByItr) {
|
|
358
364
|
skippedTestSpan.setTag(TEST_SKIPPED_BY_ITR, 'true')
|
|
359
365
|
}
|
|
366
|
+
if (itrCorrelationId) {
|
|
367
|
+
skippedTestSpan.setTag(ITR_CORRELATION_ID, itrCorrelationId)
|
|
368
|
+
}
|
|
360
369
|
skippedTestSpan.finish()
|
|
361
370
|
})
|
|
362
371
|
|
|
@@ -378,6 +387,9 @@ module.exports = (on, config) => {
|
|
|
378
387
|
finishedTest.testSpan.setTag(TEST_STATUS, cypressTestStatus)
|
|
379
388
|
finishedTest.testSpan.setTag('error', latestError)
|
|
380
389
|
}
|
|
390
|
+
if (itrCorrelationId) {
|
|
391
|
+
finishedTest.testSpan.setTag(ITR_CORRELATION_ID, itrCorrelationId)
|
|
392
|
+
}
|
|
381
393
|
finishedTest.testSpan.finish(finishedTest.finishTime)
|
|
382
394
|
})
|
|
383
395
|
|
|
@@ -429,10 +441,12 @@ module.exports = (on, config) => {
|
|
|
429
441
|
}
|
|
430
442
|
if (exporter.flush) {
|
|
431
443
|
exporter.flush(() => {
|
|
444
|
+
appClosingTelemetry()
|
|
432
445
|
resolve(null)
|
|
433
446
|
})
|
|
434
447
|
} else if (exporter._writer) {
|
|
435
448
|
exporter._writer.flush(() => {
|
|
449
|
+
appClosingTelemetry()
|
|
436
450
|
resolve(null)
|
|
437
451
|
})
|
|
438
452
|
}
|
|
@@ -13,7 +13,8 @@ const {
|
|
|
13
13
|
TEST_SOURCE_START,
|
|
14
14
|
TEST_ITR_UNSKIPPABLE,
|
|
15
15
|
TEST_ITR_FORCED_RUN,
|
|
16
|
-
TEST_CODE_OWNERS
|
|
16
|
+
TEST_CODE_OWNERS,
|
|
17
|
+
ITR_CORRELATION_ID
|
|
17
18
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
18
19
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
19
20
|
const id = require('../../dd-trace/src/id')
|
|
@@ -121,6 +122,7 @@ class JestPlugin extends CiPlugin {
|
|
|
121
122
|
config._ddTestSessionId = this.testSessionSpan.context().toTraceId()
|
|
122
123
|
config._ddTestModuleId = this.testModuleSpan.context().toSpanId()
|
|
123
124
|
config._ddTestCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
|
|
125
|
+
config._ddItrCorrelationId = this.itrCorrelationId
|
|
124
126
|
})
|
|
125
127
|
})
|
|
126
128
|
|
|
@@ -129,6 +131,7 @@ class JestPlugin extends CiPlugin {
|
|
|
129
131
|
_ddTestSessionId: testSessionId,
|
|
130
132
|
_ddTestCommand: testCommand,
|
|
131
133
|
_ddTestModuleId: testModuleId,
|
|
134
|
+
_ddItrCorrelationId: itrCorrelationId,
|
|
132
135
|
_ddForcedToRun,
|
|
133
136
|
_ddUnskippable,
|
|
134
137
|
_ddTestCodeCoverageEnabled
|
|
@@ -155,6 +158,9 @@ class JestPlugin extends CiPlugin {
|
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
160
|
}
|
|
161
|
+
if (itrCorrelationId) {
|
|
162
|
+
testSuiteMetadata[ITR_CORRELATION_ID] = itrCorrelationId
|
|
163
|
+
}
|
|
158
164
|
|
|
159
165
|
this.testSuiteSpan = this.tracer.startSpan('jest.test_suite', {
|
|
160
166
|
childOf: testSessionSpanContext,
|
|
@@ -14,7 +14,8 @@ const {
|
|
|
14
14
|
TEST_SOURCE_START,
|
|
15
15
|
TEST_ITR_UNSKIPPABLE,
|
|
16
16
|
TEST_ITR_FORCED_RUN,
|
|
17
|
-
TEST_CODE_OWNERS
|
|
17
|
+
TEST_CODE_OWNERS,
|
|
18
|
+
ITR_CORRELATION_ID
|
|
18
19
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
19
20
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
20
21
|
const {
|
|
@@ -66,7 +67,12 @@ class MochaPlugin extends CiPlugin {
|
|
|
66
67
|
this.telemetry.distribution(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, relativeCoverageFiles.length)
|
|
67
68
|
})
|
|
68
69
|
|
|
69
|
-
this.addSub('ci:mocha:test-suite:start', ({
|
|
70
|
+
this.addSub('ci:mocha:test-suite:start', ({
|
|
71
|
+
testSuite,
|
|
72
|
+
isUnskippable,
|
|
73
|
+
isForcedToRun,
|
|
74
|
+
itrCorrelationId
|
|
75
|
+
}) => {
|
|
70
76
|
const store = storage.getStore()
|
|
71
77
|
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
72
78
|
this.command,
|
|
@@ -95,6 +101,9 @@ class MochaPlugin extends CiPlugin {
|
|
|
95
101
|
if (this.itrConfig?.isCodeCoverageEnabled) {
|
|
96
102
|
this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_STARTED, 'suite', { library: 'istanbul' })
|
|
97
103
|
}
|
|
104
|
+
if (itrCorrelationId) {
|
|
105
|
+
testSuiteSpan.setTag(ITR_CORRELATION_ID, itrCorrelationId)
|
|
106
|
+
}
|
|
98
107
|
this.enter(testSuiteSpan, store)
|
|
99
108
|
this._testSuites.set(testSuite, testSuiteSpan)
|
|
100
109
|
})
|
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
TELEMETRY_EVENT_CREATED,
|
|
18
18
|
TELEMETRY_EVENT_FINISHED
|
|
19
19
|
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
20
|
+
const { appClosing: appClosingTelemetry } = require('../../dd-trace/src/telemetry')
|
|
20
21
|
|
|
21
22
|
class PlaywrightPlugin extends CiPlugin {
|
|
22
23
|
static get id () {
|
|
@@ -37,6 +38,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
37
38
|
this.testSessionSpan.finish()
|
|
38
39
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'session')
|
|
39
40
|
finishAllTraceSpans(this.testSessionSpan)
|
|
41
|
+
appClosingTelemetry()
|
|
40
42
|
this.tracer._exporter.flush(onDone)
|
|
41
43
|
})
|
|
42
44
|
|
|
@@ -16,5 +16,6 @@ module.exports = {
|
|
|
16
16
|
'UNVALIDATED_REDIRECT_ANALYZER': require('./unvalidated-redirect-analyzer'),
|
|
17
17
|
'WEAK_CIPHER_ANALYZER': require('./weak-cipher-analyzer'),
|
|
18
18
|
'WEAK_HASH_ANALYZER': require('./weak-hash-analyzer'),
|
|
19
|
+
'WEAK_RANDOMNESS_ANALYZER': require('./weak-randomness-analyzer'),
|
|
19
20
|
'XCONTENTTYPE_HEADER_MISSING_ANALYZER': require('./xcontenttype-header-missing-analyzer')
|
|
20
21
|
}
|
|
@@ -48,7 +48,7 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
|
|
|
48
48
|
if (ranges?.length > 0) {
|
|
49
49
|
return !(this.isCookieExclusion(lowerCasedHeaderName, ranges) ||
|
|
50
50
|
this.isSameHeaderExclusion(lowerCasedHeaderName, ranges) ||
|
|
51
|
-
this.
|
|
51
|
+
this.isAccessControlAllowExclusion(lowerCasedHeaderName, ranges))
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
return false
|
|
@@ -84,8 +84,8 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
|
|
|
84
84
|
return false
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
if (name
|
|
87
|
+
isAccessControlAllowExclusion (name, ranges) {
|
|
88
|
+
if (name?.startsWith('access-control-allow-')) {
|
|
89
89
|
return ranges
|
|
90
90
|
.every(range => range.iinfo.type === HTTP_REQUEST_HEADER_VALUE)
|
|
91
91
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const Analyzer = require('./vulnerability-analyzer')
|
|
3
|
+
const { WEAK_RANDOMNESS } = require('../vulnerabilities')
|
|
4
|
+
|
|
5
|
+
class WeakRandomnessAnalyzer extends Analyzer {
|
|
6
|
+
constructor () {
|
|
7
|
+
super(WEAK_RANDOMNESS)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
onConfigure () {
|
|
11
|
+
this.addSub('datadog:random:call', ({ fn }) => this.analyze(fn))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_isVulnerable (fn) {
|
|
15
|
+
return fn === Math.random
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = new WeakRandomnessAnalyzer()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
3
4
|
const TaintedUtils = require('@datadog/native-iast-taint-tracking')
|
|
4
5
|
const { storage } = require('../../../../../datadog-core')
|
|
5
6
|
const iastContextFunctions = require('../iast-context')
|
|
@@ -7,12 +8,15 @@ const iastLog = require('../iast-log')
|
|
|
7
8
|
const { EXECUTED_PROPAGATION } = require('../telemetry/iast-metric')
|
|
8
9
|
const { isDebugAllowed } = require('../telemetry/verbosity')
|
|
9
10
|
|
|
11
|
+
const mathRandomCallCh = dc.channel('datadog:random:call')
|
|
12
|
+
|
|
10
13
|
function noop (res) { return res }
|
|
11
14
|
// NOTE: methods of this object must be synchronized with csi-methods.js file definitions!
|
|
12
15
|
// Otherwise you may end up rewriting a method and not providing its rewritten implementation
|
|
13
16
|
const TaintTrackingNoop = {
|
|
14
17
|
plusOperator: noop,
|
|
15
18
|
concat: noop,
|
|
19
|
+
random: noop,
|
|
16
20
|
replace: noop,
|
|
17
21
|
slice: noop,
|
|
18
22
|
substr: noop,
|
|
@@ -110,7 +114,14 @@ function csiMethodsOverrides (getContext) {
|
|
|
110
114
|
getContext,
|
|
111
115
|
String.prototype.trim,
|
|
112
116
|
String.prototype.trimStart
|
|
113
|
-
)
|
|
117
|
+
),
|
|
118
|
+
|
|
119
|
+
random: function (res, fn) {
|
|
120
|
+
if (mathRandomCallCh.hasSubscribers) {
|
|
121
|
+
mathRandomCallCh.publish({ fn })
|
|
122
|
+
}
|
|
123
|
+
return res
|
|
124
|
+
}
|
|
114
125
|
}
|
|
115
126
|
}
|
|
116
127
|
|
|
@@ -25,7 +25,8 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
25
25
|
super()
|
|
26
26
|
|
|
27
27
|
const pollInterval = Math.floor(config.remoteConfig.pollInterval * 1000)
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
this.url = config.url || new URL(format({
|
|
29
30
|
protocol: 'http:',
|
|
30
31
|
hostname: config.hostname || 'localhost',
|
|
31
32
|
port: config.port
|
|
@@ -33,12 +34,6 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
33
34
|
|
|
34
35
|
this.scheduler = new Scheduler((cb) => this.poll(cb), pollInterval)
|
|
35
36
|
|
|
36
|
-
this.requestOptions = {
|
|
37
|
-
url,
|
|
38
|
-
method: 'POST',
|
|
39
|
-
path: '/v0.7/config'
|
|
40
|
-
}
|
|
41
|
-
|
|
42
37
|
this.state = {
|
|
43
38
|
client: {
|
|
44
39
|
state: { // updated by `parseConfig()`
|
|
@@ -122,7 +117,13 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
poll (cb) {
|
|
125
|
-
|
|
120
|
+
const options = {
|
|
121
|
+
url: this.url,
|
|
122
|
+
method: 'POST',
|
|
123
|
+
path: '/v0.7/config'
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
request(this.getPayload(), options, (err, data, statusCode) => {
|
|
126
127
|
// 404 means RC is disabled, ignore it
|
|
127
128
|
if (statusCode === 404) return cb()
|
|
128
129
|
|
|
@@ -83,7 +83,8 @@ function getSkippableSuites ({
|
|
|
83
83
|
} else {
|
|
84
84
|
let skippableSuites = []
|
|
85
85
|
try {
|
|
86
|
-
|
|
86
|
+
const parsedResponse = JSON.parse(res)
|
|
87
|
+
skippableSuites = parsedResponse
|
|
87
88
|
.data
|
|
88
89
|
.filter(({ type }) => type === testLevel)
|
|
89
90
|
.map(({ attributes: { suite, name } }) => {
|
|
@@ -92,6 +93,7 @@ function getSkippableSuites ({
|
|
|
92
93
|
}
|
|
93
94
|
return { suite, name }
|
|
94
95
|
})
|
|
96
|
+
const { meta: { correlation_id: correlationId } } = parsedResponse
|
|
95
97
|
incrementCountMetric(
|
|
96
98
|
testLevel === 'test'
|
|
97
99
|
? TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS : TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_SUITES,
|
|
@@ -100,7 +102,7 @@ function getSkippableSuites ({
|
|
|
100
102
|
)
|
|
101
103
|
distributionMetric(TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES, {}, res.length)
|
|
102
104
|
log.debug(() => `Number of received skippable ${testLevel}s: ${skippableSuites.length}`)
|
|
103
|
-
done(null, skippableSuites)
|
|
105
|
+
done(null, skippableSuites, correlationId)
|
|
104
106
|
} catch (err) {
|
|
105
107
|
done(err)
|
|
106
108
|
}
|
|
@@ -795,9 +795,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
795
795
|
tagger.add(tags, DD_TRACE_TAGS)
|
|
796
796
|
tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
|
|
797
797
|
|
|
798
|
-
this.
|
|
799
|
-
this.
|
|
800
|
-
this.
|
|
798
|
+
this._setString(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service)
|
|
799
|
+
this._setString(env, 'env', DD_ENV || tags.env)
|
|
800
|
+
this._setString(env, 'version', DD_VERSION || tags.version)
|
|
801
801
|
this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE)
|
|
802
802
|
this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
|
|
803
803
|
this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
|
|
@@ -812,9 +812,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
812
812
|
|
|
813
813
|
tagger.add(tags, options.tags)
|
|
814
814
|
|
|
815
|
-
this.
|
|
816
|
-
this.
|
|
817
|
-
this.
|
|
815
|
+
this._setString(opts, 'service', options.service || tags.service)
|
|
816
|
+
this._setString(opts, 'env', options.env || tags.env)
|
|
817
|
+
this._setString(opts, 'version', options.version || tags.version)
|
|
818
818
|
this._setUnit(opts, 'sampleRate', coalesce(options.sampleRate, options.ingestion.sampleRate))
|
|
819
819
|
this._setBoolean(opts, 'logInjection', options.logInjection)
|
|
820
820
|
this._setArray(opts, 'headerTags', options.headerTags)
|
|
@@ -875,6 +875,10 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
875
875
|
}
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
+
_setString (obj, name, value) {
|
|
879
|
+
obj[name] = value || undefined // unset for empty strings
|
|
880
|
+
}
|
|
881
|
+
|
|
878
882
|
_setTags (obj, name, value) {
|
|
879
883
|
if (!value || Object.keys(value).length === 0) {
|
|
880
884
|
return this._setValue(obj, name, null)
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
const { truncateSpan, normalizeSpan } = require('./tags-processors')
|
|
3
3
|
const { AgentEncoder } = require('./0.4')
|
|
4
4
|
const { version: ddTraceVersion } = require('../../../../package.json')
|
|
5
|
-
const
|
|
5
|
+
const { ITR_CORRELATION_ID } = require('../../src/plugins/util/test')
|
|
6
|
+
const id = require('../../src/id')
|
|
6
7
|
const {
|
|
7
8
|
distributionMetric,
|
|
8
9
|
TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
|
|
@@ -45,7 +46,13 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
_encodeTestSuite (bytes, content) {
|
|
48
|
-
|
|
49
|
+
let keysLength = TEST_SUITE_KEYS_LENGTH
|
|
50
|
+
const itrCorrelationId = content.meta[ITR_CORRELATION_ID]
|
|
51
|
+
if (itrCorrelationId) {
|
|
52
|
+
keysLength++
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this._encodeMapPrefix(bytes, keysLength)
|
|
49
56
|
this._encodeString(bytes, 'type')
|
|
50
57
|
this._encodeString(bytes, content.type)
|
|
51
58
|
|
|
@@ -58,6 +65,12 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
58
65
|
this._encodeString(bytes, 'test_suite_id')
|
|
59
66
|
this._encodeId(bytes, content.span_id)
|
|
60
67
|
|
|
68
|
+
if (itrCorrelationId) {
|
|
69
|
+
this._encodeString(bytes, ITR_CORRELATION_ID)
|
|
70
|
+
this._encodeString(bytes, itrCorrelationId)
|
|
71
|
+
delete content.meta[ITR_CORRELATION_ID]
|
|
72
|
+
}
|
|
73
|
+
|
|
61
74
|
this._encodeString(bytes, 'error')
|
|
62
75
|
this._encodeNumber(bytes, content.error)
|
|
63
76
|
this._encodeString(bytes, 'name')
|
|
@@ -144,6 +157,10 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
144
157
|
if (content.meta.test_suite_id) {
|
|
145
158
|
totalKeysLength = totalKeysLength + 1
|
|
146
159
|
}
|
|
160
|
+
const itrCorrelationId = content.meta[ITR_CORRELATION_ID]
|
|
161
|
+
if (itrCorrelationId) {
|
|
162
|
+
totalKeysLength = totalKeysLength + 1
|
|
163
|
+
}
|
|
147
164
|
this._encodeMapPrefix(bytes, totalKeysLength)
|
|
148
165
|
if (content.type) {
|
|
149
166
|
this._encodeString(bytes, 'type')
|
|
@@ -194,6 +211,12 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
194
211
|
delete content.meta.test_suite_id
|
|
195
212
|
}
|
|
196
213
|
|
|
214
|
+
if (itrCorrelationId) {
|
|
215
|
+
this._encodeString(bytes, ITR_CORRELATION_ID)
|
|
216
|
+
this._encodeString(bytes, itrCorrelationId)
|
|
217
|
+
delete content.meta[ITR_CORRELATION_ID]
|
|
218
|
+
}
|
|
219
|
+
|
|
197
220
|
this._encodeString(bytes, 'meta')
|
|
198
221
|
this._encodeMap(bytes, content.meta)
|
|
199
222
|
this._encodeString(bytes, 'metrics')
|
|
@@ -15,7 +15,8 @@ const {
|
|
|
15
15
|
TEST_MODULE,
|
|
16
16
|
getTestSuiteCommonTags,
|
|
17
17
|
TEST_STATUS,
|
|
18
|
-
TEST_SKIPPED_BY_ITR
|
|
18
|
+
TEST_SKIPPED_BY_ITR,
|
|
19
|
+
ITR_CORRELATION_ID
|
|
19
20
|
} = require('./util/test')
|
|
20
21
|
const Plugin = require('./plugin')
|
|
21
22
|
const { COMPONENT } = require('../constants')
|
|
@@ -53,11 +54,13 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
53
54
|
if (!this.tracer._exporter || !this.tracer._exporter.getSkippableSuites) {
|
|
54
55
|
return onDone({ err: new Error('CI Visibility was not initialized correctly') })
|
|
55
56
|
}
|
|
56
|
-
this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
|
|
57
|
+
this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites, itrCorrelationId) => {
|
|
57
58
|
if (err) {
|
|
58
59
|
log.error(`Skippable suites could not be fetched. ${err.message}`)
|
|
60
|
+
} else {
|
|
61
|
+
this.itrCorrelationId = itrCorrelationId
|
|
59
62
|
}
|
|
60
|
-
onDone({ err, skippableSuites })
|
|
63
|
+
onDone({ err, skippableSuites, itrCorrelationId })
|
|
61
64
|
})
|
|
62
65
|
})
|
|
63
66
|
|
|
@@ -95,6 +98,9 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
95
98
|
const testCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
|
|
96
99
|
skippedSuites.forEach((testSuite) => {
|
|
97
100
|
const testSuiteMetadata = getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.constructor.id)
|
|
101
|
+
if (this.itrCorrelationId) {
|
|
102
|
+
testSuiteMetadata[ITR_CORRELATION_ID] = this.itrCorrelationId
|
|
103
|
+
}
|
|
98
104
|
|
|
99
105
|
this.tracer.startSpan(`${this.constructor.id}.test_suite`, {
|
|
100
106
|
childOf: this.testModuleSpan,
|
|
@@ -60,6 +60,7 @@ const TEST_ITR_SKIPPING_COUNT = 'test.itr.tests_skipping.count'
|
|
|
60
60
|
const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
|
|
61
61
|
const TEST_ITR_UNSKIPPABLE = 'test.itr.unskippable'
|
|
62
62
|
const TEST_ITR_FORCED_RUN = 'test.itr.forced_run'
|
|
63
|
+
const ITR_CORRELATION_ID = 'itr_correlation_id'
|
|
63
64
|
|
|
64
65
|
const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
|
|
65
66
|
|
|
@@ -111,6 +112,7 @@ module.exports = {
|
|
|
111
112
|
TEST_CODE_COVERAGE_LINES_PCT,
|
|
112
113
|
TEST_ITR_UNSKIPPABLE,
|
|
113
114
|
TEST_ITR_FORCED_RUN,
|
|
115
|
+
ITR_CORRELATION_ID,
|
|
114
116
|
addIntelligentTestRunnerSpanTags,
|
|
115
117
|
getCoveredFilenamesFromCoverage,
|
|
116
118
|
resetCoverage,
|
|
@@ -40,6 +40,7 @@ class Config {
|
|
|
40
40
|
DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
|
|
41
41
|
DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
|
|
42
42
|
DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
|
|
43
|
+
DD_PROFILING_TIMELINE_ENABLED,
|
|
43
44
|
DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED,
|
|
44
45
|
DD_PROFILING_CODEHOTSPOTS_ENABLED,
|
|
45
46
|
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
|
|
@@ -96,11 +97,15 @@ class Config {
|
|
|
96
97
|
// depending on those (code hotspots and endpoint collection) need to default
|
|
97
98
|
// to false on Windows.
|
|
98
99
|
const samplingContextsAvailable = process.platform !== 'win32'
|
|
99
|
-
function checkOptionAllowed (option, description) {
|
|
100
|
-
if (option && !
|
|
100
|
+
function checkOptionAllowed (option, description, condition) {
|
|
101
|
+
if (option && !condition) {
|
|
101
102
|
throw new Error(`${description} not supported on ${process.platform}.`)
|
|
102
103
|
}
|
|
103
104
|
}
|
|
105
|
+
function checkOptionWithSamplingContextAllowed (option, description) {
|
|
106
|
+
checkOptionAllowed(option, description, samplingContextsAvailable)
|
|
107
|
+
}
|
|
108
|
+
|
|
104
109
|
this.flushInterval = flushInterval
|
|
105
110
|
this.uploadTimeout = uploadTimeout
|
|
106
111
|
this.sourceMap = sourceMap
|
|
@@ -109,7 +114,7 @@ class Config {
|
|
|
109
114
|
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
|
|
110
115
|
DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED, samplingContextsAvailable))
|
|
111
116
|
logExperimentalVarDeprecation('ENDPOINT_COLLECTION_ENABLED')
|
|
112
|
-
|
|
117
|
+
checkOptionWithSamplingContextAllowed(this.endpointCollectionEnabled, 'Endpoint collection')
|
|
113
118
|
|
|
114
119
|
this.pprofPrefix = pprofPrefix
|
|
115
120
|
this.v8ProfilerBugWorkaroundEnabled = isTrue(coalesce(options.v8ProfilerBugWorkaround,
|
|
@@ -126,8 +131,13 @@ class Config {
|
|
|
126
131
|
new AgentExporter(this)
|
|
127
132
|
], this)
|
|
128
133
|
|
|
134
|
+
// OOM monitoring does not work well on Windows, so it is disabled by default.
|
|
135
|
+
const oomMonitoringSupported = process.platform !== 'win32'
|
|
136
|
+
|
|
129
137
|
const oomMonitoringEnabled = isTrue(coalesce(options.oomMonitoring,
|
|
130
|
-
DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED,
|
|
138
|
+
DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED, oomMonitoringSupported))
|
|
139
|
+
checkOptionAllowed(oomMonitoringEnabled, 'OOM monitoring', oomMonitoringSupported)
|
|
140
|
+
|
|
131
141
|
const heapLimitExtensionSize = coalesce(options.oomHeapLimitExtensionSize,
|
|
132
142
|
Number(DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE), 0)
|
|
133
143
|
const maxHeapExtensionCount = coalesce(options.oomMaxHeapExtensionCount,
|
|
@@ -154,16 +164,20 @@ class Config {
|
|
|
154
164
|
})
|
|
155
165
|
|
|
156
166
|
this.timelineEnabled = isTrue(coalesce(options.timelineEnabled,
|
|
167
|
+
DD_PROFILING_TIMELINE_ENABLED,
|
|
157
168
|
DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED, false))
|
|
169
|
+
logExperimentalVarDeprecation('TIMELINE_ENABLED')
|
|
170
|
+
checkOptionWithSamplingContextAllowed(this.timelineEnabled, 'Timeline view')
|
|
158
171
|
|
|
159
172
|
this.codeHotspotsEnabled = isTrue(coalesce(options.codeHotspotsEnabled,
|
|
160
173
|
DD_PROFILING_CODEHOTSPOTS_ENABLED,
|
|
161
174
|
DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, samplingContextsAvailable))
|
|
162
175
|
logExperimentalVarDeprecation('CODEHOTSPOTS_ENABLED')
|
|
163
|
-
|
|
176
|
+
checkOptionWithSamplingContextAllowed(this.codeHotspotsEnabled, 'Code hotspots')
|
|
164
177
|
|
|
165
178
|
this.cpuProfilingEnabled = isTrue(coalesce(options.cpuProfilingEnabled,
|
|
166
179
|
DD_PROFILING_EXPERIMENTAL_CPU_ENABLED, false))
|
|
180
|
+
checkOptionWithSamplingContextAllowed(this.cpuProfilingEnabled, 'CPU profiling')
|
|
167
181
|
|
|
168
182
|
this.profilers = ensureProfilers(profilers, this)
|
|
169
183
|
}
|
|
@@ -140,8 +140,7 @@ function appStarted (config) {
|
|
|
140
140
|
return app
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
function
|
|
144
|
-
process.removeListener('beforeExit', onBeforeExit)
|
|
143
|
+
function appClosing () {
|
|
145
144
|
const { reqType, payload } = createPayload('app-closing')
|
|
146
145
|
sendData(config, application, host, reqType, payload)
|
|
147
146
|
// we flush before shutting down. Only in CI Visibility
|
|
@@ -150,6 +149,11 @@ function onBeforeExit () {
|
|
|
150
149
|
}
|
|
151
150
|
}
|
|
152
151
|
|
|
152
|
+
function onBeforeExit () {
|
|
153
|
+
process.removeListener('beforeExit', onBeforeExit)
|
|
154
|
+
appClosing()
|
|
155
|
+
}
|
|
156
|
+
|
|
153
157
|
function createAppObject (config) {
|
|
154
158
|
return {
|
|
155
159
|
service_name: config.service,
|
|
@@ -339,5 +343,6 @@ module.exports = {
|
|
|
339
343
|
start,
|
|
340
344
|
stop,
|
|
341
345
|
updateIntegrations,
|
|
342
|
-
updateConfig
|
|
346
|
+
updateConfig,
|
|
347
|
+
appClosing
|
|
343
348
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
const request = require('../exporters/common/request')
|
|
3
3
|
const log = require('../log')
|
|
4
|
+
const { isTrue } = require('../util')
|
|
4
5
|
|
|
5
6
|
let agentTelemetry = true
|
|
6
7
|
|
|
@@ -49,13 +50,12 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
|
|
|
49
50
|
const {
|
|
50
51
|
hostname,
|
|
51
52
|
port,
|
|
52
|
-
experimental,
|
|
53
53
|
isCiVisibility
|
|
54
54
|
} = config
|
|
55
55
|
|
|
56
56
|
let url = config.url
|
|
57
57
|
|
|
58
|
-
const isCiVisibilityAgentlessMode = isCiVisibility &&
|
|
58
|
+
const isCiVisibilityAgentlessMode = isCiVisibility && isTrue(process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED)
|
|
59
59
|
|
|
60
60
|
if (isCiVisibilityAgentlessMode) {
|
|
61
61
|
try {
|
package/scripts/st.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console, no-fallthrough */
|
|
3
|
+
'use strict'
|
|
4
|
+
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const { writeFileSync } = require('fs')
|
|
7
|
+
const { execSync } = require('child_process')
|
|
8
|
+
|
|
9
|
+
const ddtracePath = path.join(__dirname, '..')
|
|
10
|
+
const defaultTestPath = process.env.DD_ST_PATH || path.join(ddtracePath, '..', 'system-tests')
|
|
11
|
+
|
|
12
|
+
const { buildAll, npm, testDir, testArgs } = parseArgs()
|
|
13
|
+
|
|
14
|
+
const binariesPath = path.join(testDir, 'binaries')
|
|
15
|
+
|
|
16
|
+
if (npm) {
|
|
17
|
+
console.log('Using NPM package:', npm)
|
|
18
|
+
|
|
19
|
+
writeFileSync(path.join(binariesPath, 'nodejs-load-from-npm'), npm)
|
|
20
|
+
} else {
|
|
21
|
+
console.log('Using local repo')
|
|
22
|
+
|
|
23
|
+
const packName = execSync(`npm pack ${ddtracePath}`, {
|
|
24
|
+
cwd: binariesPath,
|
|
25
|
+
stdio: [null, null, 'inherit'],
|
|
26
|
+
encoding: 'utf8'
|
|
27
|
+
}).slice(0, -1) // remove trailing newline
|
|
28
|
+
|
|
29
|
+
writeFileSync(path.join(binariesPath, 'nodejs-load-from-npm'), `/binaries/${packName}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
execSync(`./build.sh ${buildAll ? '' : '-i weblog'} && ./run.sh ${testArgs}`, {
|
|
34
|
+
cwd: testDir,
|
|
35
|
+
stdio: [null, 'inherit', 'inherit']
|
|
36
|
+
})
|
|
37
|
+
} catch (err) {
|
|
38
|
+
process.exit(err.status || 1)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function parseArgs () {
|
|
42
|
+
const args = {
|
|
43
|
+
buildAll: false,
|
|
44
|
+
npm: null,
|
|
45
|
+
testDir: defaultTestPath,
|
|
46
|
+
testArgs: ''
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = 2; i < process.argv.length; i++) {
|
|
50
|
+
switch (process.argv[i]) {
|
|
51
|
+
case '-b':
|
|
52
|
+
case '--build-all':
|
|
53
|
+
args.buildAll = true
|
|
54
|
+
break
|
|
55
|
+
|
|
56
|
+
case '-h':
|
|
57
|
+
case '--help':
|
|
58
|
+
helpAndExit()
|
|
59
|
+
break
|
|
60
|
+
|
|
61
|
+
case '-n':
|
|
62
|
+
case '--npm': {
|
|
63
|
+
const arg = process.argv[i + 1]
|
|
64
|
+
if (!arg || arg[0] === '-') {
|
|
65
|
+
args.npm = 'dd-trace'
|
|
66
|
+
} else {
|
|
67
|
+
args.npm = arg
|
|
68
|
+
i++
|
|
69
|
+
}
|
|
70
|
+
break
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case '-t':
|
|
74
|
+
case '--test-dir': {
|
|
75
|
+
const arg = process.argv[++i]
|
|
76
|
+
if (!arg || arg[0] === '-') helpAndExit()
|
|
77
|
+
args.testDir = arg
|
|
78
|
+
break
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
case '--':
|
|
82
|
+
args.testArgs = process.argv.slice(i + 1).join(' ')
|
|
83
|
+
return args
|
|
84
|
+
|
|
85
|
+
default:
|
|
86
|
+
console.log('Unknown option:', process.argv[i], '\n')
|
|
87
|
+
helpAndExit()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return args
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function helpAndExit () {
|
|
95
|
+
console.log('Usage: node st.js [options...] [-- test-args]')
|
|
96
|
+
console.log('Options:')
|
|
97
|
+
console.log(' -b, --build-all Rebuild all images (default: only build weblog)')
|
|
98
|
+
console.log(' -h, --help Print this message')
|
|
99
|
+
console.log(' -n, --npm [package] Build a remote package instead of the local repo (default: "dd-trace")')
|
|
100
|
+
console.log(' Can be a package name (e.g. "dd-trace@4.2.0") or a git URL (e.g.')
|
|
101
|
+
console.log(' "git+https://github.com/DataDog/dd-trace-js.git#mybranch")')
|
|
102
|
+
console.log(' -t, --test-dir <path> Specify the system-tests directory (default: "dd-trace/../system-tests/")')
|
|
103
|
+
console.log(' -- <test-args> Passed to system-tests run.sh (e.g. "-- SCENARIO_NAME tests/path_to_test.py")')
|
|
104
|
+
process.exit()
|
|
105
|
+
}
|