dd-trace 4.15.0 → 4.17.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 (76) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/ext/tags.d.ts +1 -0
  3. package/ext/tags.js +1 -0
  4. package/index.d.ts +1 -0
  5. package/package.json +9 -6
  6. package/packages/datadog-esbuild/index.js +30 -25
  7. package/packages/datadog-instrumentations/src/body-parser.js +4 -3
  8. package/packages/datadog-instrumentations/src/cookie-parser.js +37 -0
  9. package/packages/datadog-instrumentations/src/cucumber.js +24 -4
  10. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +45 -0
  11. package/packages/datadog-instrumentations/src/express.js +3 -2
  12. package/packages/datadog-instrumentations/src/graphql.js +5 -0
  13. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -1
  14. package/packages/datadog-instrumentations/src/http/server.js +1 -1
  15. package/packages/datadog-instrumentations/src/jest.js +20 -11
  16. package/packages/datadog-instrumentations/src/knex.js +62 -1
  17. package/packages/datadog-instrumentations/src/mocha.js +19 -4
  18. package/packages/datadog-instrumentations/src/mongodb.js +63 -0
  19. package/packages/datadog-instrumentations/src/mongoose.js +140 -1
  20. package/packages/datadog-instrumentations/src/next.js +62 -80
  21. package/packages/datadog-instrumentations/src/pg.js +14 -15
  22. package/packages/datadog-instrumentations/src/playwright.js +26 -5
  23. package/packages/datadog-plugin-cucumber/src/index.js +17 -5
  24. package/packages/datadog-plugin-cypress/src/plugin.js +38 -8
  25. package/packages/datadog-plugin-jest/src/index.js +19 -4
  26. package/packages/datadog-plugin-jest/src/util.js +45 -2
  27. package/packages/datadog-plugin-memcached/src/index.js +10 -5
  28. package/packages/datadog-plugin-mocha/src/index.js +19 -6
  29. package/packages/datadog-plugin-mysql/src/index.js +2 -2
  30. package/packages/datadog-plugin-next/src/index.js +14 -5
  31. package/packages/datadog-plugin-pg/src/index.js +2 -2
  32. package/packages/dd-trace/src/appsec/channels.js +4 -1
  33. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  34. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +166 -0
  35. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +21 -1
  36. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +3 -3
  37. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -2
  38. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +4 -0
  39. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +25 -12
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +4 -4
  41. package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +13 -0
  42. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
  43. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +16 -0
  44. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
  45. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +9 -0
  46. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +13 -1
  47. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +169 -0
  48. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  49. package/packages/dd-trace/src/appsec/index.js +45 -14
  50. package/packages/dd-trace/src/appsec/recommended.json +549 -24
  51. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  52. package/packages/dd-trace/src/appsec/remote_config/index.js +2 -0
  53. package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -3
  54. package/packages/dd-trace/src/appsec/reporter.js +7 -5
  55. package/packages/dd-trace/src/appsec/telemetry.js +2 -2
  56. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +18 -5
  57. package/packages/dd-trace/src/appsec/waf/waf_manager.js +5 -4
  58. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +1 -14
  59. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -13
  60. package/packages/dd-trace/src/config.js +8 -0
  61. package/packages/dd-trace/src/datastreams/processor.js +6 -2
  62. package/packages/dd-trace/src/format.js +9 -1
  63. package/packages/dd-trace/src/opentracing/propagation/text_map.js +2 -2
  64. package/packages/dd-trace/src/opentracing/tracer.js +0 -2
  65. package/packages/dd-trace/src/plugin_manager.js +4 -3
  66. package/packages/dd-trace/src/plugins/database.js +14 -4
  67. package/packages/dd-trace/src/plugins/index.js +1 -0
  68. package/packages/dd-trace/src/plugins/outbound.js +4 -3
  69. package/packages/dd-trace/src/plugins/util/ci.js +17 -0
  70. package/packages/dd-trace/src/plugins/util/git.js +26 -4
  71. package/packages/dd-trace/src/plugins/util/test.js +16 -1
  72. package/packages/dd-trace/src/profiling/config.js +36 -5
  73. package/packages/dd-trace/src/profiling/profilers/wall.js +7 -1
  74. package/packages/dd-trace/src/service-naming/extra-services.js +24 -0
  75. package/packages/dd-trace/src/telemetry/index.js +10 -1
  76. package/packages/dd-trace/src/telemetry/metrics.js +0 -5
@@ -14,6 +14,7 @@ require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
14
14
  require,int64-buffer,MIT,Copyright 2015-2016 Yusuke Kawasaki
15
15
  require,ipaddr.js,MIT,Copyright 2011-2017 whitequark
16
16
  require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
17
+ require,jest-docblock,MIT,Copyright Meta Platforms, Inc. and affiliates.
17
18
  require,koalas,MIT,Copyright 2013-2017 Brian Woodward
18
19
  require,limiter,MIT,Copyright 2011 John Hurliman
19
20
  require,lodash.kebabcase,MIT,Copyright JS Foundation and other contributors
@@ -32,6 +33,7 @@ require,retry,MIT,Copyright 2011 Tim Koschützki Felix Geisendörfer
32
33
  require,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
33
34
  dev,@types/node,MIT,Copyright Authors
34
35
  dev,autocannon,MIT,Copyright 2016 Matteo Collina
36
+ dev,aws-sdk,Apache 2.0,Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
35
37
  dev,axios,MIT,Copyright 2014-present Matt Zabriskie
36
38
  dev,benchmark,MIT,Copyright 2010-2016 Mathias Bynens Robert Kieffer John-David Dalton
37
39
  dev,body-parser,MIT,Copyright 2014 Jonathan Ong 2014-2015 Douglas Christopher Wilson
package/ext/tags.d.ts CHANGED
@@ -9,6 +9,7 @@ declare const tags: {
9
9
  MANUAL_KEEP: 'manual.keep'
10
10
  MANUAL_DROP: 'manual.drop'
11
11
  MEASURED: '_dd.measured'
12
+ BASE_SERVICE: '_dd.base_service'
12
13
  HTTP_URL: 'http.url'
13
14
  HTTP_METHOD: 'http.method'
14
15
  HTTP_STATUS_CODE: 'http.status_code'
package/ext/tags.js CHANGED
@@ -12,6 +12,7 @@ const tags = {
12
12
  MANUAL_KEEP: 'manual.keep',
13
13
  MANUAL_DROP: 'manual.drop',
14
14
  MEASURED: '_dd.measured',
15
+ BASE_SERVICE: '_dd.base_service',
15
16
 
16
17
  // HTTP
17
18
  HTTP_URL: 'http.url',
package/index.d.ts CHANGED
@@ -829,6 +829,7 @@ interface Plugins {
829
829
  "mysql2": plugins.mysql2;
830
830
  "net": plugins.net;
831
831
  "next": plugins.next;
832
+ "openai": plugins.openai;
832
833
  "opensearch": plugins.opensearch;
833
834
  "oracledb": plugins.oracledb;
834
835
  "paperplane": plugins.paperplane;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "4.15.0",
3
+ "version": "4.17.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -37,7 +37,8 @@
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
39
  "test:integration:serverless": "mocha --colors --timeout 30000 \"integration-tests/serverless/*.spec.js\"",
40
- "test:integration:plugins": "mocha --colors --timeout 30000 \"packages/datadog-plugin-*/test/integration-test/*.spec.js\"",
40
+ "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
+ "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\"",
41
42
  "test:shimmer": "mocha --colors 'packages/datadog-shimmer/test/**/*.spec.js'",
42
43
  "test:shimmer:ci": "nyc --no-clean --include 'packages/datadog-shimmer/src/**/*.js' -- npm run test:shimmer",
43
44
  "leak:core": "node ./scripts/install_plugin_modules && (cd packages/memwatch && yarn) && NODE_PATH=./packages/memwatch/node_modules node --no-warnings ./node_modules/.bin/tape 'packages/dd-trace/test/leak/**/*.js'",
@@ -58,7 +59,7 @@
58
59
  "apm"
59
60
  ],
60
61
  "author": "Datadog Inc. <info@datadoghq.com>",
61
- "license": "BSD-3-Clause",
62
+ "license": "(Apache-2.0 OR BSD-3-Clause)",
62
63
  "bugs": {
63
64
  "url": "https://github.com/DataDog/dd-trace-js/issues"
64
65
  },
@@ -67,11 +68,11 @@
67
68
  "node": ">=16"
68
69
  },
69
70
  "dependencies": {
70
- "@datadog/native-appsec": "^3.2.0",
71
+ "@datadog/native-appsec": "^4.0.0",
71
72
  "@datadog/native-iast-rewriter": "2.1.3",
72
- "@datadog/native-iast-taint-tracking": "1.5.0",
73
+ "@datadog/native-iast-taint-tracking": "1.6.1",
73
74
  "@datadog/native-metrics": "^2.0.0",
74
- "@datadog/pprof": "3.2.0",
75
+ "@datadog/pprof": "4.0.0",
75
76
  "@datadog/sketches-js": "^2.1.0",
76
77
  "@opentelemetry/api": "^1.0.0",
77
78
  "@opentelemetry/core": "^1.14.0",
@@ -82,6 +83,7 @@
82
83
  "int64-buffer": "^0.1.9",
83
84
  "ipaddr.js": "^2.1.0",
84
85
  "istanbul-lib-coverage": "3.2.0",
86
+ "jest-docblock": "^29.7.0",
85
87
  "koalas": "^1.0.2",
86
88
  "limiter": "^1.1.4",
87
89
  "lodash.kebabcase": "^4.1.1",
@@ -102,6 +104,7 @@
102
104
  "devDependencies": {
103
105
  "@types/node": ">=16",
104
106
  "autocannon": "^4.5.2",
107
+ "aws-sdk": "^2.1446.0",
105
108
  "axios": "^0.21.2",
106
109
  "benchmark": "^2.1.4",
107
110
  "body-parser": "^1.20.2",
@@ -23,11 +23,12 @@ for (const instrumentation of Object.values(instrumentations)) {
23
23
  }
24
24
  }
25
25
 
26
- const NAMESPACE = 'datadog'
27
26
  const NM = 'node_modules/'
28
27
  const INSTRUMENTED = Object.keys(instrumentations)
29
28
  const RAW_BUILTINS = require('module').builtinModules
30
29
  const CHANNEL = 'dd-trace:bundler:load'
30
+ const path = require('path')
31
+ const fs = require('fs')
31
32
 
32
33
  const builtins = new Set()
33
34
 
@@ -109,55 +110,59 @@ module.exports.setup = function (build) {
109
110
  // https://esbuild.github.io/plugins/#on-resolve-arguments
110
111
  return {
111
112
  path: fullPathToModule,
112
- namespace: NAMESPACE,
113
113
  pluginData: {
114
114
  version: packageJson.version,
115
115
  pkg: extracted.pkg,
116
116
  path: extracted.path,
117
117
  full: fullPathToModule,
118
118
  raw: args.path,
119
+ pkgOfInterest: true,
119
120
  internal
120
121
  }
121
122
  }
122
- } else if (args.namespace === NAMESPACE) {
123
- // The datadog namespace is used when requiring files that are injected during the onLoad stage
124
-
125
- if (builtins.has(args.path)) return
126
-
127
- return {
128
- path: require.resolve(args.path, { paths: [ args.resolveDir ] }),
129
- namespace: 'file'
130
- }
131
123
  }
132
124
  })
133
125
 
134
- build.onLoad({ filter: /.*/, namespace: NAMESPACE }, args => {
126
+ build.onLoad({ filter: /.*/ }, args => {
127
+ if (!args.pluginData?.pkgOfInterest) {
128
+ return
129
+ }
130
+
135
131
  const data = args.pluginData
136
132
 
137
133
  if (DEBUG) console.log(`LOAD: ${data.pkg}@${data.version}, pkg "${data.path}"`)
138
134
 
139
- const path = data.raw !== data.pkg
135
+ const pkgPath = data.raw !== data.pkg
140
136
  ? `${data.pkg}/${data.path}`
141
137
  : data.pkg
142
138
 
139
+ // Read the content of the module file of interest
140
+ const fileCode = fs.readFileSync(args.path, 'utf8')
141
+
143
142
  const contents = `
144
- const dc = require('diagnostics_channel');
145
- const ch = dc.channel('${CHANNEL}');
146
- const mod = require('${args.path}');
147
- const payload = {
148
- module: mod,
149
- version: '${data.version}',
150
- package: '${data.pkg}',
151
- path: '${path}'
152
- };
153
- ch.publish(payload);
154
- module.exports = payload.module;
143
+ (function() {
144
+ ${fileCode}
145
+ })(...arguments);
146
+ {
147
+ const dc = require('diagnostics_channel');
148
+ const ch = dc.channel('${CHANNEL}');
149
+ const mod = module.exports
150
+ const payload = {
151
+ module: mod,
152
+ version: '${data.version}',
153
+ package: '${data.pkg}',
154
+ path: '${pkgPath}'
155
+ };
156
+ ch.publish(payload);
157
+ module.exports = payload.module;
158
+ }
155
159
  `
156
160
 
157
161
  // https://esbuild.github.io/plugins/#on-load-results
158
162
  return {
159
163
  contents,
160
- loader: 'js'
164
+ loader: 'js',
165
+ resolveDir: path.dirname(args.path)
161
166
  }
162
167
  })
163
168
  }
@@ -10,13 +10,14 @@ function publishRequestBodyAndNext (req, res, next) {
10
10
  return function () {
11
11
  if (bodyParserReadCh.hasSubscribers && req) {
12
12
  const abortController = new AbortController()
13
+ const body = req.body
13
14
 
14
- bodyParserReadCh.publish({ req, res, abortController })
15
+ bodyParserReadCh.publish({ req, res, body, abortController })
15
16
 
16
17
  if (abortController.signal.aborted) return
17
18
  }
18
19
 
19
- next.apply(this, arguments)
20
+ return next.apply(this, arguments)
20
21
  }
21
22
  }
22
23
 
@@ -27,6 +28,6 @@ addHook({
27
28
  }, read => {
28
29
  return shimmer.wrap(read, function (req, res, next) {
29
30
  arguments[2] = publishRequestBodyAndNext(req, res, next)
30
- read.apply(this, arguments)
31
+ return read.apply(this, arguments)
31
32
  })
32
33
  })
@@ -0,0 +1,37 @@
1
+ 'use strict'
2
+
3
+ const { AbortController } = require('node-abort-controller') // AbortController is not available in node <15
4
+ const shimmer = require('../../datadog-shimmer')
5
+ const { channel, addHook } = require('./helpers/instrument')
6
+
7
+ const cookieParserReadCh = channel('datadog:cookie-parser:read:finish')
8
+
9
+ function publishRequestCookieAndNext (req, res, next) {
10
+ return function cookieParserWrapper () {
11
+ if (cookieParserReadCh.hasSubscribers && req) {
12
+ const abortController = new AbortController()
13
+
14
+ const mergedCookies = Object.assign({}, req.cookies, req.signedCookies)
15
+
16
+ cookieParserReadCh.publish({ req, res, abortController, cookies: mergedCookies })
17
+
18
+ if (abortController.signal.aborted) return
19
+ }
20
+
21
+ return next.apply(this, arguments)
22
+ }
23
+ }
24
+
25
+ addHook({
26
+ name: 'cookie-parser',
27
+ versions: ['>=1.0.0']
28
+ }, cookieParser => {
29
+ return shimmer.wrap(cookieParser, function () {
30
+ const cookieMiddleware = cookieParser.apply(this, arguments)
31
+
32
+ return shimmer.wrap(cookieMiddleware, function (req, res, next) {
33
+ arguments[2] = publishRequestCookieAndNext(req, res, next)
34
+ return cookieMiddleware.apply(this, arguments)
35
+ })
36
+ })
37
+ })
@@ -31,6 +31,10 @@ const {
31
31
  getTestSuitePath
32
32
  } = require('../../dd-trace/src/plugins/util/test')
33
33
 
34
+ const isMarkedAsUnskippable = (pickle) => {
35
+ return !!pickle.tags.find(tag => tag.name === '@datadog:unskippable')
36
+ }
37
+
34
38
  // We'll preserve the original coverage here
35
39
  const originalCoverageMap = createCoverageMap()
36
40
 
@@ -39,6 +43,9 @@ const patched = new WeakSet()
39
43
 
40
44
  let pickleByFile = {}
41
45
  const pickleResultByFile = {}
46
+ let skippableSuites = []
47
+ let isForcedToRun = false
48
+ let isUnskippable = false
42
49
 
43
50
  function getSuiteStatusFromTestStatuses (testStatuses) {
44
51
  if (testStatuses.some(status => status === 'fail')) {
@@ -91,7 +98,11 @@ function wrapRun (pl, isLatestVersion) {
91
98
  const testSuiteFullPath = this.pickle.uri
92
99
 
93
100
  if (!pickleResultByFile[testSuiteFullPath]) { // first test in suite
94
- testSuiteStartCh.publish(testSuiteFullPath)
101
+ isUnskippable = isMarkedAsUnskippable(this.pickle)
102
+ const testSuitePath = getTestSuitePath(testSuiteFullPath, process.cwd())
103
+ isForcedToRun = isUnskippable && skippableSuites.includes(testSuitePath)
104
+
105
+ testSuiteStartCh.publish({ testSuitePath, isUnskippable, isForcedToRun })
95
106
  }
96
107
 
97
108
  const testSourceLine = this.gherkinDocument &&
@@ -221,8 +232,11 @@ function getFilteredPickles (runtime, suitesToSkip) {
221
232
  return runtime.pickleIds.reduce((acc, pickleId) => {
222
233
  const test = runtime.eventDataCollector.getPickle(pickleId)
223
234
  const testSuitePath = getTestSuitePath(test.uri, process.cwd())
235
+
236
+ const isUnskippable = isMarkedAsUnskippable(test)
224
237
  const isSkipped = suitesToSkip.includes(testSuitePath)
225
- if (isSkipped) {
238
+
239
+ if (isSkipped && !isUnskippable) {
226
240
  acc.skippedSuites.add(testSuitePath)
227
241
  } else {
228
242
  acc.picklesToRun.push(pickleId)
@@ -270,7 +284,11 @@ addHook({
270
284
  skippableSuitesCh.publish({ onDone })
271
285
  })
272
286
 
273
- const { err, skippableSuites } = await skippableSuitesPromise
287
+ const skippableResponse = await skippableSuitesPromise
288
+
289
+ const err = skippableResponse.err
290
+ skippableSuites = skippableResponse.skippableSuites
291
+
274
292
  let skippedSuites = []
275
293
  let isSuitesSkipped = false
276
294
 
@@ -315,7 +333,9 @@ addHook({
315
333
  status: success ? 'pass' : 'fail',
316
334
  isSuitesSkipped,
317
335
  testCodeCoverageLinesTotal,
318
- numSkippedSuites: skippedSuites.length
336
+ numSkippedSuites: skippedSuites.length,
337
+ hasUnskippableSuites: isUnskippable,
338
+ hasForcedToRunSuites: isForcedToRun
319
339
  })
320
340
  })
321
341
  return success
@@ -0,0 +1,45 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook
6
+ } = require('./helpers/instrument')
7
+ const shimmer = require('../../datadog-shimmer')
8
+
9
+ const sanitizeMethodFinished = channel('datadog:express-mongo-sanitize:sanitize:finish')
10
+ const sanitizeMiddlewareFinished = channel('datadog:express-mongo-sanitize:filter:finish')
11
+
12
+ const propertiesToSanitize = ['body', 'params', 'headers', 'query']
13
+
14
+ addHook({ name: 'express-mongo-sanitize', versions: ['>=1.0.0'] }, expressMongoSanitize => {
15
+ shimmer.wrap(expressMongoSanitize, 'sanitize', sanitize => function () {
16
+ const sanitizedObject = sanitize.apply(this, arguments)
17
+
18
+ if (sanitizeMethodFinished.hasSubscribers) {
19
+ sanitizeMethodFinished.publish({ sanitizedObject })
20
+ }
21
+
22
+ return sanitizedObject
23
+ })
24
+
25
+ return shimmer.wrap(expressMongoSanitize, function () {
26
+ const middleware = expressMongoSanitize.apply(this, arguments)
27
+
28
+ return shimmer.wrap(middleware, function (req, res, next) {
29
+ if (!sanitizeMiddlewareFinished.hasSubscribers) {
30
+ return middleware.apply(this, arguments)
31
+ }
32
+
33
+ const wrappedNext = shimmer.wrap(next, function () {
34
+ sanitizeMiddlewareFinished.publish({
35
+ sanitizedProperties: propertiesToSanitize,
36
+ req
37
+ })
38
+
39
+ return next.apply(this, arguments)
40
+ })
41
+
42
+ return middleware.call(this, req, res, wrappedNext)
43
+ })
44
+ })
45
+ })
@@ -33,13 +33,14 @@ function publishQueryParsedAndNext (req, res, next) {
33
33
  return function () {
34
34
  if (queryParserReadCh.hasSubscribers && req) {
35
35
  const abortController = new AbortController()
36
+ const query = req.query
36
37
 
37
- queryParserReadCh.publish({ req, res, abortController })
38
+ queryParserReadCh.publish({ req, res, query, abortController })
38
39
 
39
40
  if (abortController.signal.aborted) return
40
41
  }
41
42
 
42
- next.apply(this, arguments)
43
+ return next.apply(this, arguments)
43
44
  }
44
45
  }
45
46
 
@@ -350,6 +350,11 @@ function finishResolvers ({ fields }) {
350
350
  })
351
351
  }
352
352
 
353
+ addHook({ name: '@graphql-tools/executor', file: 'cjs/execution/execute.js', versions: ['>=0.0.14'] }, execute => {
354
+ shimmer.wrap(execute, 'execute', wrapExecute(execute))
355
+ return execute
356
+ })
357
+
353
358
  addHook({ name: 'graphql', file: 'execution/execute.js', versions: ['>=0.10'] }, execute => {
354
359
  shimmer.wrap(execute, 'execute', wrapExecute(execute))
355
360
  return execute
@@ -7,6 +7,7 @@ module.exports = {
7
7
  '@elastic/elasticsearch': () => require('../elasticsearch'),
8
8
  '@elastic/transport': () => require('../elasticsearch'),
9
9
  '@google-cloud/pubsub': () => require('../google-cloud-pubsub'),
10
+ '@graphql-tools/executor': () => require('../graphql'),
10
11
  '@grpc/grpc-js': () => require('../grpc'),
11
12
  '@hapi/hapi': () => require('../hapi'),
12
13
  '@jest/core': () => require('../jest'),
@@ -30,12 +31,14 @@ module.exports = {
30
31
  'node:child_process': () => require('../child-process'),
31
32
  'connect': () => require('../connect'),
32
33
  'cookie': () => require('../cookie'),
34
+ 'cookie-parser': () => require('../cookie-parser'),
33
35
  'couchbase': () => require('../couchbase'),
34
36
  'crypto': () => require('../crypto'),
35
37
  'cypress': () => require('../cypress'),
36
38
  'dns': () => require('../dns'),
37
39
  'elasticsearch': () => require('../elasticsearch'),
38
40
  'express': () => require('../express'),
41
+ 'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
39
42
  'fastify': () => require('../fastify'),
40
43
  'find-my-way': () => require('../find-my-way'),
41
44
  'fs': () => require('../fs'),
@@ -66,7 +69,7 @@ module.exports = {
66
69
  'mocha': () => require('../mocha'),
67
70
  'mocha-each': () => require('../mocha'),
68
71
  'moleculer': () => require('../moleculer'),
69
- 'mongodb': () => require('../mongodb-core'),
72
+ 'mongodb': () => require('../mongodb'),
70
73
  'mongodb-core': () => require('../mongodb-core'),
71
74
  'mongoose': () => require('../mongoose'),
72
75
  'mysql': () => require('../mysql'),
@@ -81,6 +84,7 @@ module.exports = {
81
84
  'pg': () => require('../pg'),
82
85
  'pino': () => require('../pino'),
83
86
  'pino-pretty': () => require('../pino'),
87
+ 'playwright': () => require('../playwright'),
84
88
  'promise-js': () => require('../promise-js'),
85
89
  'promise': () => require('../promise'),
86
90
  'q': () => require('../q'),
@@ -29,7 +29,7 @@ addHook({ name: 'http' }, http => {
29
29
 
30
30
  function wrapResponseEmit (emit) {
31
31
  return function (eventName, event) {
32
- if (!startServerCh.hasSubscribers) {
32
+ if (!finishServerCh.hasSubscribers) {
33
33
  return emit.apply(this, arguments)
34
34
  }
35
35
 
@@ -46,6 +46,8 @@ let isCodeCoverageEnabled = false
46
46
  let isSuitesSkippingEnabled = false
47
47
  let isSuitesSkipped = false
48
48
  let numSkippedSuites = 0
49
+ let hasUnskippableSuites = false
50
+ let hasForcedToRunSuites = false
49
51
 
50
52
  const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
51
53
 
@@ -205,15 +207,17 @@ addHook({
205
207
  const [test] = shardedTests
206
208
  const rootDir = test && test.context && test.context.config && test.context.config.rootDir
207
209
 
208
- const { skippedSuites, suitesToRun } = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
210
+ const jestSuitesToRun = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
211
+ hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
212
+ hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
209
213
 
210
- isSuitesSkipped = suitesToRun.length !== shardedTests.length
211
- numSkippedSuites = skippedSuites.length
214
+ isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== shardedTests.length
215
+ numSkippedSuites = jestSuitesToRun.skippedSuites.length
212
216
 
213
- itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
217
+ itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
214
218
 
215
219
  skippableSuites = []
216
- return suitesToRun
220
+ return jestSuitesToRun.suitesToRun
217
221
  })
218
222
  return sequencerPackage
219
223
  })
@@ -285,7 +289,9 @@ function cliWrapper (cli, jestVersion) {
285
289
  isSuitesSkippingEnabled,
286
290
  isCodeCoverageEnabled,
287
291
  testCodeCoverageLinesTotal,
288
- numSkippedSuites
292
+ numSkippedSuites,
293
+ hasUnskippableSuites,
294
+ hasForcedToRunSuites
289
295
  })
290
296
  })
291
297
 
@@ -500,16 +506,19 @@ addHook({
500
506
  const testPaths = await getTestPaths.apply(this, arguments)
501
507
  const { tests } = testPaths
502
508
 
503
- const { skippedSuites, suitesToRun } = getJestSuitesToRun(skippableSuites, tests, rootDir)
509
+ const jestSuitesToRun = getJestSuitesToRun(skippableSuites, tests, rootDir)
504
510
 
505
- isSuitesSkipped = suitesToRun.length !== tests.length
506
- numSkippedSuites = skippedSuites.length
511
+ hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
512
+ hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
507
513
 
508
- itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
514
+ isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== tests.length
515
+ numSkippedSuites = jestSuitesToRun.skippedSuites.length
516
+
517
+ itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
509
518
 
510
519
  skippableSuites = []
511
520
 
512
- return { ...testPaths, tests: suitesToRun }
521
+ return { ...testPaths, tests: jestSuitesToRun.suitesToRun }
513
522
  })
514
523
 
515
524
  return searchSourcePackage
@@ -1,9 +1,12 @@
1
1
  'use strict'
2
2
 
3
- const { addHook } = require('./helpers/instrument')
3
+ const { addHook, channel } = require('./helpers/instrument')
4
4
  const { wrapThen } = require('./helpers/promise')
5
5
  const shimmer = require('../../datadog-shimmer')
6
6
 
7
+ const startRawQueryCh = channel('datadog:knex:raw:start')
8
+ const finishRawQueryCh = channel('datadog:knex:raw:finish')
9
+
7
10
  patch('lib/query/builder.js')
8
11
  patch('lib/raw.js')
9
12
  patch('lib/schema/builder.js')
@@ -18,3 +21,61 @@ function patch (file) {
18
21
  return Builder
19
22
  })
20
23
  }
24
+
25
+ addHook({
26
+ name: 'knex',
27
+ versions: ['>=2'],
28
+ file: 'lib/knex-builder/Knex.js'
29
+ }, Knex => {
30
+ shimmer.wrap(Knex.Client.prototype, 'raw', raw => function () {
31
+ if (!startRawQueryCh.hasSubscribers) {
32
+ return raw.apply(this, arguments)
33
+ }
34
+
35
+ const sql = arguments[0]
36
+
37
+ // Skip query done by Knex to get the value used for undefined
38
+ if (sql === 'DEFAULT') {
39
+ return raw.apply(this, arguments)
40
+ }
41
+
42
+ function finish () {
43
+ finishRawQueryCh.publish()
44
+ }
45
+
46
+ startRawQueryCh.publish({ sql, dialect: this.dialect })
47
+
48
+ const rawResult = raw.apply(this, arguments)
49
+
50
+ shimmer.wrap(rawResult, 'then', originalThen => function () {
51
+ arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
52
+ arguments[1] = wrapCallbackWithFinish(arguments[1], finish)
53
+
54
+ const originalThenResult = originalThen.apply(this, arguments)
55
+
56
+ shimmer.wrap(originalThenResult, 'catch', originalCatch => function () {
57
+ arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
58
+ return originalCatch.apply(this, arguments)
59
+ })
60
+
61
+ return originalThenResult
62
+ })
63
+
64
+ shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function () {
65
+ arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
66
+ return originalAsCallback.apply(this, arguments)
67
+ })
68
+
69
+ return rawResult
70
+ })
71
+ return Knex
72
+ })
73
+
74
+ function wrapCallbackWithFinish (callback, finish) {
75
+ if (typeof callback !== 'function') return callback
76
+
77
+ return function () {
78
+ finish()
79
+ callback.apply(this, arguments)
80
+ }
81
+ }
@@ -1,9 +1,10 @@
1
1
  const { createCoverageMap } = require('istanbul-lib-coverage')
2
2
 
3
+ const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
4
+
3
5
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
6
  const shimmer = require('../../datadog-shimmer')
5
7
  const log = require('../../dd-trace/src/log')
6
-
7
8
  const {
8
9
  getCoveredFilenamesFromCoverage,
9
10
  resetCoverage,
@@ -50,6 +51,8 @@ let suitesToSkip = []
50
51
  let frameworkVersion
51
52
  let isSuitesSkipped = false
52
53
  let skippedSuites = []
54
+ const unskippableSuites = []
55
+ let isForcedToRun = false
53
56
 
54
57
  function getSuitesByTestFile (root) {
55
58
  const suitesByTestFile = {}
@@ -104,7 +107,8 @@ function getFilteredSuites (originalSuites) {
104
107
  return originalSuites.reduce((acc, suite) => {
105
108
  const testPath = getTestSuitePath(suite.file, process.cwd())
106
109
  const shouldSkip = suitesToSkip.includes(testPath)
107
- if (shouldSkip) {
110
+ const isUnskippable = unskippableSuites.includes(suite.file)
111
+ if (shouldSkip && !isUnskippable) {
108
112
  acc.skippedSuites.add(testPath)
109
113
  } else {
110
114
  acc.suitesToRun.push(suite)
@@ -151,7 +155,9 @@ function mochaHook (Runner) {
151
155
  status,
152
156
  isSuitesSkipped,
153
157
  testCodeCoverageLinesTotal,
154
- numSkippedSuites: skippedSuites.length
158
+ numSkippedSuites: skippedSuites.length,
159
+ hasForcedToRunSuites: isForcedToRun,
160
+ hasUnskippableSuites: !!unskippableSuites.length
155
161
  })
156
162
  }))
157
163
 
@@ -172,8 +178,10 @@ function mochaHook (Runner) {
172
178
  if (!asyncResource) {
173
179
  asyncResource = new AsyncResource('bound-anonymous-fn')
174
180
  testFileToSuiteAr.set(suite.file, asyncResource)
181
+ const isUnskippable = unskippableSuites.includes(suite.file)
182
+ isForcedToRun = isUnskippable && suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
175
183
  asyncResource.runInAsyncScope(() => {
176
- testSuiteStartCh.publish(suite)
184
+ testSuiteStartCh.publish({ testSuite: suite.file, isUnskippable, isForcedToRun })
177
185
  })
178
186
  }
179
187
  })
@@ -370,6 +378,13 @@ addHook({
370
378
 
371
379
  const runner = run.apply(this, arguments)
372
380
 
381
+ this.files.forEach(path => {
382
+ const isUnskippable = isMarkedAsUnskippable({ path })
383
+ if (isUnskippable) {
384
+ unskippableSuites.push(path)
385
+ }
386
+ })
387
+
373
388
  const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
374
389
  if (err) {
375
390
  suitesToSkip = []