dd-trace 2.25.1 → 2.26.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.
Files changed (42) hide show
  1. package/index.d.ts +50 -0
  2. package/package.json +1 -1
  3. package/packages/datadog-instrumentations/src/fs.js +350 -4
  4. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  5. package/packages/datadog-instrumentations/src/jest.js +11 -1
  6. package/packages/datadog-instrumentations/src/mocha.js +3 -2
  7. package/packages/datadog-instrumentations/src/mysql.js +7 -1
  8. package/packages/datadog-instrumentations/src/mysql2.js +7 -1
  9. package/packages/datadog-instrumentations/src/playwright.js +236 -0
  10. package/packages/datadog-plugin-fs/src/index.js +37 -574
  11. package/packages/datadog-plugin-jest/src/index.js +45 -23
  12. package/packages/datadog-plugin-mocha/src/index.js +34 -6
  13. package/packages/datadog-plugin-mysql/src/index.js +8 -7
  14. package/packages/datadog-plugin-playwright/src/index.js +171 -0
  15. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
  16. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  17. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
  18. package/packages/dd-trace/src/appsec/index.js +1 -1
  19. package/packages/dd-trace/src/appsec/recommended.json +247 -112
  20. package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
  21. package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
  22. package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
  23. package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
  24. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  25. package/packages/dd-trace/src/config.js +7 -0
  26. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
  27. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
  28. package/packages/dd-trace/src/log/channels.js +47 -0
  29. package/packages/dd-trace/src/log/index.js +79 -0
  30. package/packages/dd-trace/src/log/writer.js +108 -0
  31. package/packages/dd-trace/src/noop/proxy.js +3 -0
  32. package/packages/dd-trace/src/plugins/index.js +1 -0
  33. package/packages/dd-trace/src/plugins/util/ci.js +13 -21
  34. package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
  35. package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
  36. package/packages/dd-trace/src/plugins/util/test.js +27 -10
  37. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
  38. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  39. package/packages/dd-trace/src/proxy.js +2 -0
  40. package/packages/dd-trace/src/startup-log.js +1 -1
  41. package/scripts/check-proposal-labels.js +71 -0
  42. package/packages/dd-trace/src/log.js +0 -143
@@ -0,0 +1,236 @@
1
+ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
2
+ const shimmer = require('../../datadog-shimmer')
3
+
4
+ const testStartCh = channel('ci:playwright:test:start')
5
+ const testFinishCh = channel('ci:playwright:test:finish')
6
+
7
+ const testSessionStartCh = channel('ci:playwright:session:start')
8
+ const testSessionFinishCh = channel('ci:playwright:session:finish')
9
+
10
+ const testSuiteStartCh = channel('ci:playwright:test-suite:start')
11
+ const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
12
+
13
+ const testToAr = new WeakMap()
14
+ const testSuiteToAr = new Map()
15
+ const testSuiteToTestStatuses = new Map()
16
+
17
+ let startedSuites = []
18
+
19
+ const STATUS_TO_TEST_STATUS = {
20
+ passed: 'pass',
21
+ failed: 'fail',
22
+ timedOut: 'fail',
23
+ skipped: 'skip'
24
+ }
25
+
26
+ let remainingTestsByFile = {}
27
+
28
+ function getTestsBySuiteFromTestsById (testsById) {
29
+ const testsByTestSuite = {}
30
+ for (const { test } of testsById.values()) {
31
+ const { _requireFile } = test
32
+ if (test._type === 'beforeAll' || test._type === 'afterAll') {
33
+ continue
34
+ }
35
+ if (testsByTestSuite[_requireFile]) {
36
+ testsByTestSuite[_requireFile].push(test)
37
+ } else {
38
+ testsByTestSuite[_requireFile] = [test]
39
+ }
40
+ }
41
+ return testsByTestSuite
42
+ }
43
+
44
+ function getPlaywrightConfig (playwrightRunner) {
45
+ try {
46
+ return playwrightRunner._configLoader.fullConfig()
47
+ } catch (e) {
48
+ try {
49
+ return playwrightRunner._loader.fullConfig()
50
+ } catch (e) {
51
+ return {}
52
+ }
53
+ }
54
+ }
55
+
56
+ function getRootDir (playwrightRunner) {
57
+ const config = getPlaywrightConfig(playwrightRunner)
58
+ if (config.rootDir) {
59
+ return config.rootDir
60
+ }
61
+ if (playwrightRunner._configDir) {
62
+ return playwrightRunner._configDir
63
+ }
64
+ return process.cwd()
65
+ }
66
+
67
+ function testBeginHandler (test) {
68
+ const { title: testName, location: { file: testSuiteAbsolutePath }, _type } = test
69
+
70
+ if (_type === 'beforeAll' || _type === 'afterAll') {
71
+ return
72
+ }
73
+
74
+ const isNewTestSuite = !startedSuites.includes(testSuiteAbsolutePath)
75
+
76
+ if (isNewTestSuite) {
77
+ startedSuites.push(testSuiteAbsolutePath)
78
+ const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
79
+ testSuiteToAr.set(testSuiteAbsolutePath, testSuiteAsyncResource)
80
+ testSuiteAsyncResource.runInAsyncScope(() => {
81
+ testSuiteStartCh.publish(testSuiteAbsolutePath)
82
+ })
83
+ }
84
+
85
+ const testAsyncResource = new AsyncResource('bound-anonymous-fn')
86
+ testToAr.set(test, testAsyncResource)
87
+ testAsyncResource.runInAsyncScope(() => {
88
+ testStartCh.publish({ testName, testSuiteAbsolutePath })
89
+ })
90
+ }
91
+
92
+ function testEndHandler (test, testStatus, error) {
93
+ const { location: { file: testSuiteAbsolutePath }, results, _type } = test
94
+
95
+ if (_type === 'beforeAll' || _type === 'afterAll') {
96
+ return
97
+ }
98
+
99
+ const testResult = results[results.length - 1]
100
+ const testAsyncResource = testToAr.get(test)
101
+ testAsyncResource.runInAsyncScope(() => {
102
+ testFinishCh.publish({ testStatus, steps: testResult.steps, error })
103
+ })
104
+
105
+ if (!testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
106
+ testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
107
+ } else {
108
+ testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
109
+ }
110
+
111
+ remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
112
+ .filter(currentTest => currentTest !== test)
113
+
114
+ if (!remainingTestsByFile[testSuiteAbsolutePath].length) {
115
+ const testStatuses = testSuiteToTestStatuses.get(testSuiteAbsolutePath)
116
+
117
+ let testSuiteStatus = 'pass'
118
+ if (testStatuses.some(status => status === 'fail')) {
119
+ testSuiteStatus = 'fail'
120
+ } else if (testStatuses.every(status => status === 'skip')) {
121
+ testSuiteStatus = 'skip'
122
+ }
123
+
124
+ const testSuiteAsyncResource = testSuiteToAr.get(testSuiteAbsolutePath)
125
+ testSuiteAsyncResource.runInAsyncScope(() => {
126
+ testSuiteFinishCh.publish(testSuiteStatus)
127
+ })
128
+ }
129
+ }
130
+
131
+ function dispatcherRunWrapper (run) {
132
+ return function () {
133
+ remainingTestsByFile = getTestsBySuiteFromTestsById(this._testById)
134
+ return run.apply(this, arguments)
135
+ }
136
+ }
137
+
138
+ function dispatcherHook (dispatcherExport) {
139
+ shimmer.wrap(dispatcherExport.Dispatcher.prototype, 'run', dispatcherRunWrapper)
140
+ shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
141
+ const dispatcher = this
142
+ const worker = createWorker.apply(this, arguments)
143
+
144
+ worker.process.on('message', ({ method, params }) => {
145
+ if (method === 'testBegin') {
146
+ const { test } = dispatcher._testById.get(params.testId)
147
+ testBeginHandler(test)
148
+ } else if (method === 'testEnd') {
149
+ const { test } = dispatcher._testById.get(params.testId)
150
+
151
+ const { results } = test
152
+ const testResult = results[results.length - 1]
153
+
154
+ testEndHandler(test, STATUS_TO_TEST_STATUS[testResult.status], testResult.error)
155
+ }
156
+ })
157
+
158
+ return worker
159
+ })
160
+ return dispatcherExport
161
+ }
162
+
163
+ function dispatcherHookNew (dispatcherExport) {
164
+ shimmer.wrap(dispatcherExport.Dispatcher.prototype, 'run', dispatcherRunWrapper)
165
+ shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
166
+ const dispatcher = this
167
+ const worker = createWorker.apply(this, arguments)
168
+
169
+ worker.on('testBegin', ({ testId }) => {
170
+ const { test } = dispatcher._testById.get(testId)
171
+ testBeginHandler(test)
172
+ })
173
+ worker.on('testEnd', ({ testId, status, errors }) => {
174
+ const { test } = dispatcher._testById.get(testId)
175
+
176
+ testEndHandler(test, STATUS_TO_TEST_STATUS[status], errors && errors[0])
177
+ })
178
+
179
+ return worker
180
+ })
181
+ return dispatcherExport
182
+ }
183
+
184
+ function runnerHook (runnerExport) {
185
+ shimmer.wrap(runnerExport.Runner.prototype, 'runAllTests', runAllTests => async function () {
186
+ const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
187
+ const { version: frameworkVersion } = getPlaywrightConfig(this)
188
+
189
+ const rootDir = getRootDir(this)
190
+
191
+ const processArgv = process.argv.slice(2).join(' ')
192
+ const command = `playwright ${processArgv}`
193
+ testSessionAsyncResource.runInAsyncScope(() => {
194
+ testSessionStartCh.publish({ command, frameworkVersion, rootDir })
195
+ })
196
+
197
+ const res = await runAllTests.apply(this, arguments)
198
+ const sessionStatus = STATUS_TO_TEST_STATUS[res.status]
199
+
200
+ let onDone
201
+
202
+ const flushWait = new Promise(resolve => {
203
+ onDone = resolve
204
+ })
205
+
206
+ testSessionAsyncResource.runInAsyncScope(() => {
207
+ testSessionFinishCh.publish({ status: sessionStatus, onDone })
208
+ })
209
+ await flushWait
210
+
211
+ startedSuites = []
212
+ remainingTestsByFile = {}
213
+
214
+ return res
215
+ })
216
+
217
+ return runnerExport
218
+ }
219
+
220
+ addHook({
221
+ name: '@playwright/test',
222
+ file: 'lib/runner.js',
223
+ versions: ['>=1.18.0']
224
+ }, runnerHook)
225
+
226
+ addHook({
227
+ name: '@playwright/test',
228
+ file: 'lib/dispatcher.js',
229
+ versions: ['>=1.18.0 <1.30.0']
230
+ }, dispatcherHook)
231
+
232
+ addHook({
233
+ name: '@playwright/test',
234
+ file: 'lib/dispatcher.js',
235
+ versions: ['>=1.30.0']
236
+ }, dispatcherHookNew)