dd-trace 3.10.0 → 3.12.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 (66) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/index.d.ts +33 -1
  3. package/package.json +10 -7
  4. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  5. package/packages/datadog-instrumentations/src/helpers/register.js +7 -0
  6. package/packages/datadog-instrumentations/src/http/server.js +7 -1
  7. package/packages/datadog-instrumentations/src/ldapjs.js +91 -0
  8. package/packages/datadog-instrumentations/src/mocha.js +33 -8
  9. package/packages/datadog-instrumentations/src/pg.js +6 -2
  10. package/packages/datadog-plugin-http/src/client.js +1 -1
  11. package/packages/datadog-plugin-http/src/server.js +7 -3
  12. package/packages/datadog-plugin-jest/src/index.js +2 -2
  13. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  14. package/packages/datadog-plugin-pg/src/index.js +1 -1
  15. package/packages/datadog-plugin-router/src/index.js +6 -3
  16. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  17. package/packages/dd-trace/src/appsec/blocking.js +44 -0
  18. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
  19. package/packages/dd-trace/src/appsec/gateway/engine/engine.js +1 -1
  20. package/packages/dd-trace/src/appsec/gateway/engine/index.js +6 -1
  21. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -1
  22. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -1
  23. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +11 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  25. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -3
  26. package/packages/dd-trace/src/appsec/iast/iast-context.js +3 -1
  27. package/packages/dd-trace/src/appsec/iast/index.js +15 -3
  28. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
  29. package/packages/dd-trace/src/appsec/iast/path-line.js +6 -5
  30. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +17 -0
  31. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -29
  32. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +16 -15
  33. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +103 -0
  34. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +63 -41
  35. package/packages/dd-trace/src/appsec/index.js +68 -27
  36. package/packages/dd-trace/src/{plugins/util → appsec}/ip_blocklist.js +0 -0
  37. package/packages/dd-trace/src/appsec/ip_extractor.js +98 -0
  38. package/packages/dd-trace/src/appsec/recommended.json +75 -8
  39. package/packages/dd-trace/src/appsec/remote_config/index.js +2 -1
  40. package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
  41. package/packages/dd-trace/src/appsec/templates/blocked.html +99 -0
  42. package/packages/dd-trace/src/appsec/templates/blocked.json +8 -0
  43. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +4 -0
  44. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +18 -2
  45. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +12 -6
  46. package/packages/dd-trace/src/config.js +48 -7
  47. package/packages/dd-trace/src/exporters/common/request.js +33 -1
  48. package/packages/dd-trace/src/format.js +5 -1
  49. package/packages/dd-trace/src/lambda/handler.js +72 -0
  50. package/packages/dd-trace/src/lambda/index.js +5 -0
  51. package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
  52. package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
  53. package/packages/dd-trace/src/lambda/runtime/ritm.js +143 -0
  54. package/packages/dd-trace/src/plugin_manager.js +4 -10
  55. package/packages/dd-trace/src/plugins/ci_plugin.js +6 -0
  56. package/packages/dd-trace/src/plugins/database.js +4 -4
  57. package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
  58. package/packages/dd-trace/src/plugins/util/ci.js +5 -2
  59. package/packages/dd-trace/src/plugins/util/test.js +2 -2
  60. package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
  61. package/packages/dd-trace/src/plugins/util/web.js +1 -104
  62. package/packages/dd-trace/src/priority_sampler.js +6 -2
  63. package/packages/dd-trace/src/proxy.js +4 -3
  64. package/packages/dd-trace/src/ritm.js +7 -1
  65. package/packages/dd-trace/src/span_processor.js +13 -0
  66. package/packages/dd-trace/src/span_sampler.js +1 -4
@@ -20,6 +20,7 @@ require,lodash.uniq,MIT,Copyright JS Foundation and other contributors
20
20
  require,lru-cache,ISC,Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors
21
21
  require,methods,MIT,Copyright 2013-2014 TJ Holowaychuk
22
22
  require,module-details-from-path,MIT,Copyright 2016 Thomas Watson Steen
23
+ require,node-abort-controller,MIT,Copyright (c) 2019 Steve Faulkner
23
24
  require,opentracing,MIT,Copyright 2016 Resonance Labs Inc
24
25
  require,path-to-regexp,MIT,Copyright 2014 Blake Embrey
25
26
  require,protobufjs,BSD-3-Clause,Copyright 2016 Daniel Wirtz
@@ -62,4 +63,5 @@ dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
62
63
  dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
63
64
  dev,tape,MIT,Copyright James Halliday
64
65
  dev,wait-on,MIT,Copyright 2015 Jeff Barczewski
66
+ file,aws-lambda-nodejs-runtime-interface-client,Apache 2.0,Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
65
67
  file,profile.proto,Apache license 2.0,Copyright 2016 Google Inc.
package/index.d.ts CHANGED
@@ -242,6 +242,11 @@ export declare interface TracerOptions {
242
242
  */
243
243
  service?: string;
244
244
 
245
+ /**
246
+ * Provide service name mappings for each plugin.
247
+ */
248
+ serviceMapping?: { [key: string]: string };
249
+
245
250
  /**
246
251
  * The url of the trace agent that the tracer will submit to.
247
252
  * Takes priority over hostname and port, if set.
@@ -509,8 +514,29 @@ export declare interface TracerOptions {
509
514
  /**
510
515
  * Specifies a regex that will redact sensitive data by its value in attack reports.
511
516
  */
512
- obfuscatorValueRegex?: string
517
+ obfuscatorValueRegex?: string,
518
+
519
+ /**
520
+ * Specifies a path to a custom blocking template html file.
521
+ */
522
+ blockedTemplateHtml?: string,
523
+
524
+ /**
525
+ * Specifies a path to a custom blocking template json file.
526
+ */
527
+ blockedTemplateJson?: string,
513
528
  };
529
+
530
+ /**
531
+ * Configuration of ASM Remote Configuration
532
+ */
533
+ remoteConfig?: {
534
+ /**
535
+ * Specifies the remote configuration polling interval in seconds
536
+ * @default 5
537
+ */
538
+ pollInterval?: number,
539
+ }
514
540
  }
515
541
 
516
542
  /**
@@ -1208,6 +1234,12 @@ declare namespace plugins {
1208
1234
  */
1209
1235
  interface kafkajs extends Instrumentation {}
1210
1236
 
1237
+ /**
1238
+ * This plugin automatically instruments the
1239
+ * [ldapjs](https://github.com/ldapjs/node-ldapjs/) module.
1240
+ */
1241
+ interface ldapjs extends Instrumentation {}
1242
+
1211
1243
  /**
1212
1244
  * This plugin automatically instruments the
1213
1245
  * [mariadb](https://github.com/mariadb-corporation/mariadb-connector-nodejs) module.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "3.10.0",
3
+ "version": "3.12.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -16,14 +16,16 @@
16
16
  "services": "node ./scripts/install_plugin_modules && node packages/dd-trace/test/setup/services",
17
17
  "tdd": "node scripts/tdd.js",
18
18
  "test": "SERVICES=* yarn services && mocha --colors --exit --expose-gc 'packages/dd-trace/test/setup/node.js' 'packages/*/test/**/*.spec.js'",
19
- "test:trace:core": "mocha --colors --exit --expose-gc --file packages/dd-trace/test/setup/core.js --exclude \"packages/dd-trace/test/profiling/**/*.spec.js\" \"packages/dd-trace/test/**/*.spec.js\"",
20
- "test:trace:core:ci": "nyc --no-clean --include \"packages/dd-trace/src/**/*.js\" --exclude \"packages/dd-trace/src/profiling/**/*.js\" -- npm run test:trace:core -- --reporter mocha-multi-reporters --reporter-options configFile=mocha-reporter.json",
19
+ "test:trace:core": "mocha --colors --exit --expose-gc --file packages/dd-trace/test/setup/core.js --exclude \"packages/dd-trace/test/lambda/**/*.spec.js\" --exclude \"packages/dd-trace/test/profiling/**/*.spec.js\" --exclude \"packages/dd-trace/test/appsec/iast/**/*.plugin.spec.js\" \"packages/dd-trace/test/**/*.spec.js\"",
20
+ "test:trace:core:ci": "nyc --no-clean --include \"packages/dd-trace/src/**/*.js\" --exclude \"packages/dd-trace/src/lambda/**/*.spec.js\" --exclude \"packages/dd-trace/src/profiling/**/*.js\" --exclude \"packages/dd-trace/test/appsec/iast/**/*.plugin.spec.js\" -- npm run test:trace:core -- --reporter mocha-multi-reporters --reporter-options configFile=mocha-reporter.json",
21
21
  "test:instrumentations": "mocha --colors --file 'packages/dd-trace/test/setup/core.js' 'packages/datadog-instrumentations/test/**/*.spec.js'",
22
22
  "test:instrumentations:ci": "nyc --no-clean --include 'packages/datadog-instrumentations/src/**/*.js' -- npm run test:instrumentations",
23
23
  "test:core": "mocha --colors --file packages/datadog-core/test/setup.js 'packages/datadog-core/test/**/*.spec.js'",
24
24
  "test:core:ci": "nyc --no-clean --include 'packages/datadog-core/src/**/*.js' -- npm run test:core",
25
- "test:plugins": "mocha --colors --exit --file \"packages/dd-trace/test/setup/core.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\"",
26
- "test:plugins:ci": "yarn services && nyc --no-clean --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS)).js\" --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS))/**/*.js\" --include \"packages/datadog-plugin-@($(echo $PLUGINS))/src/**/*.js\" -- npm run test:plugins",
25
+ "test:lambda": "mocha --colors --exit --file \"packages/dd-trace/test/setup/core.js\" \"packages/dd-trace/test/lambda/**/*.spec.js\"",
26
+ "test:lambda:ci": "nyc --no-clean --include \"packages/dd-trace/src/lambda/**/*.js\" -- npm run test:lambda",
27
+ "test:plugins": "mocha --colors --exit --file \"packages/dd-trace/test/setup/core.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\" \"packages/dd-trace/test/appsec/iast/**/*.@($(echo $PLUGINS)).plugin.spec.js\"",
28
+ "test:plugins:ci": "yarn services && nyc --no-clean --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS)).js\" --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS))/**/*.js\" --include \"packages/datadog-plugin-@($(echo $PLUGINS))/src/**/*.js\" --include \"packages/dd-trace/test/appsec/iast/**/*.@($(echo $PLUGINS)).plugin.spec.js\" -- npm run test:plugins",
27
29
  "test:plugins:upstream": "node ./packages/dd-trace/test/plugins/suite.js",
28
30
  "test:profiler": "mocha --colors --exit --file \"packages/dd-trace/test/setup/core.js\" \"packages/dd-trace/test/profiling/**/*.spec.js\"",
29
31
  "test:profiler:ci": "nyc --no-clean --include \"packages/dd-trace/src/profiling/**/*.js\" -- npm run test:profiler",
@@ -59,8 +61,8 @@
59
61
  },
60
62
  "dependencies": {
61
63
  "@datadog/native-appsec": "2.0.0",
62
- "@datadog/native-iast-rewriter": "1.0.1",
63
- "@datadog/native-iast-taint-tracking": "1.0.0",
64
+ "@datadog/native-iast-rewriter": "1.1.2",
65
+ "@datadog/native-iast-taint-tracking": "1.1.0",
64
66
  "@datadog/native-metrics": "^1.5.0",
65
67
  "@datadog/pprof": "^1.1.1",
66
68
  "@datadog/sketches-js": "^2.1.0",
@@ -79,6 +81,7 @@
79
81
  "lru-cache": "^7.14.0",
80
82
  "methods": "^1.1.2",
81
83
  "module-details-from-path": "^1.0.3",
84
+ "node-abort-controller": "^3.0.1",
82
85
  "opentracing": ">=0.12.1",
83
86
  "path-to-regexp": "^0.1.2",
84
87
  "protobufjs": "^7.1.2",
@@ -46,6 +46,7 @@ module.exports = {
46
46
  'koa': () => require('../koa'),
47
47
  'koa-router': () => require('../koa'),
48
48
  'kafkajs': () => require('../kafkajs'),
49
+ 'ldapjs': () => require('../ldapjs'),
49
50
  'limitd-client': () => require('../limitd-client'),
50
51
  'mariadb': () => require('../mariadb'),
51
52
  'memcached': () => require('../memcached'),
@@ -57,3 +57,10 @@ function getVersion (moduleBaseDir) {
57
57
  function filename (name, file) {
58
58
  return [name, file].filter(val => val).join('/')
59
59
  }
60
+
61
+ module.exports = {
62
+ filename,
63
+ getVersion,
64
+ matchVersion,
65
+ pathSepExpr
66
+ }
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { AbortController } = require('node-abort-controller') // AbortController is not available in node <15
3
4
  const {
4
5
  channel,
5
6
  addHook
@@ -48,9 +49,14 @@ function wrapEmit (emit) {
48
49
  if (eventName === 'request') {
49
50
  res.req = req
50
51
 
51
- startServerCh.publish({ req, res })
52
+ const abortController = new AbortController()
53
+
54
+ startServerCh.publish({ req, res, abortController })
52
55
 
53
56
  try {
57
+ if (abortController.signal.aborted) {
58
+ return res.end()
59
+ }
54
60
  return emit.apply(this, arguments)
55
61
  } catch (err) {
56
62
  errorServerCh.publish(err)
@@ -0,0 +1,91 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook,
6
+ AsyncResource
7
+ } = require('./helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+
10
+ function isString (value) {
11
+ return typeof value === 'string' || value instanceof String
12
+ }
13
+
14
+ function getCallbackArgIndex (args) {
15
+ let callbackIndex = -1
16
+ for (let i = args.length - 1; i >= 0; i--) {
17
+ if (typeof args[i] === 'function') {
18
+ callbackIndex = i
19
+ break
20
+ }
21
+ }
22
+ return callbackIndex
23
+ }
24
+
25
+ function wrapEmitter (corkedEmitter) {
26
+ const callbackMap = new WeakMap()
27
+
28
+ const addListener = on => function (name, fn) {
29
+ if (typeof fn === 'function') {
30
+ let bindedFn = callbackMap.get(fn)
31
+ if (!bindedFn) {
32
+ const callbackResource = new AsyncResource('bound-anonymous-fn')
33
+ bindedFn = callbackResource.bind(fn)
34
+ callbackMap.set(fn, bindedFn)
35
+ }
36
+ arguments[1] = bindedFn
37
+ }
38
+ on.apply(this, arguments)
39
+ }
40
+ shimmer.wrap(corkedEmitter, 'on', addListener)
41
+ shimmer.wrap(corkedEmitter, 'addListener', addListener)
42
+
43
+ const removeListener = off => function (name, fn) {
44
+ if (typeof fn === 'function') {
45
+ const emitterOn = callbackMap.get(fn)
46
+ if (emitterOn) {
47
+ arguments[1] = emitterOn
48
+ }
49
+ }
50
+ off.apply(this, arguments)
51
+ }
52
+ shimmer.wrap(corkedEmitter, 'off', removeListener)
53
+ shimmer.wrap(corkedEmitter, 'removeListener', removeListener)
54
+ }
55
+
56
+ addHook({ name: 'ldapjs', versions: ['>=2'] }, ldapjs => {
57
+ const ldapSearchCh = channel('datadog:ldapjs:client:search')
58
+
59
+ shimmer.wrap(ldapjs.Client.prototype, 'search', search => function (base, options) {
60
+ if (ldapSearchCh.hasSubscribers) {
61
+ let filter
62
+ if (isString(options)) {
63
+ filter = options
64
+ } else if (typeof options === 'object' && options.filter) {
65
+ if (isString(options.filter)) {
66
+ filter = options.filter
67
+ }
68
+ }
69
+ ldapSearchCh.publish({ base, filter })
70
+ }
71
+
72
+ return search.apply(this, arguments)
73
+ })
74
+
75
+ shimmer.wrap(ldapjs.Client.prototype, '_send', _send => function () {
76
+ const callbackIndex = getCallbackArgIndex(arguments)
77
+ if (callbackIndex > -1) {
78
+ const callback = arguments[callbackIndex]
79
+ arguments[callbackIndex] = shimmer.wrap(callback, function (err, corkedEmitter) {
80
+ if (typeof corkedEmitter === 'object' && typeof corkedEmitter['on'] === 'function') {
81
+ wrapEmitter(corkedEmitter)
82
+ }
83
+ callback.apply(this, arguments)
84
+ })
85
+ }
86
+
87
+ return _send.apply(this, arguments)
88
+ })
89
+
90
+ return ldapjs
91
+ })
@@ -89,6 +89,12 @@ function getTestAsyncResource (test) {
89
89
  return testToAr.get(originalFn)
90
90
  }
91
91
 
92
+ function getSuitesToRun (originalSuites) {
93
+ return originalSuites.filter(suite =>
94
+ !suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
95
+ )
96
+ }
97
+
92
98
  function mochaHook (Runner) {
93
99
  if (patched.has(Runner)) return Runner
94
100
 
@@ -279,11 +285,6 @@ function mochaHook (Runner) {
279
285
  }
280
286
  })
281
287
 
282
- // We remove the suites that we skip through ITR
283
- this.suite.suites = this.suite.suites.filter(suite =>
284
- !suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
285
- )
286
-
287
288
  return run.apply(this, arguments)
288
289
  })
289
290
 
@@ -323,6 +324,10 @@ addHook({
323
324
  if (!itrConfigurationCh.hasSubscribers) {
324
325
  return run.apply(this, arguments)
325
326
  }
327
+ this.options.delay = true
328
+
329
+ const runner = run.apply(this, arguments)
330
+
326
331
  const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
327
332
  if (err) {
328
333
  log.error(err)
@@ -330,16 +335,18 @@ addHook({
330
335
  } else {
331
336
  suitesToSkip = skippableSuites
332
337
  }
333
- run.apply(this, arguments)
338
+ // We remove the suites that we skip through ITR
339
+ runner.suite.suites = getSuitesToRun(runner.suite.suites)
340
+ global.run()
334
341
  }
335
342
 
336
343
  const onReceivedConfiguration = ({ err }) => {
337
344
  if (err) {
338
345
  log.error(err)
339
- return run.apply(this, arguments)
346
+ return global.run()
340
347
  }
341
348
  if (!skippableSuitesCh.hasSubscribers) {
342
- return run.apply(this, arguments)
349
+ return global.run()
343
350
  }
344
351
 
345
352
  skippableSuitesCh.publish({
@@ -352,6 +359,7 @@ addHook({
352
359
  onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
353
360
  })
354
361
  })
362
+ return runner
355
363
  })
356
364
  return Mocha
357
365
  })
@@ -362,6 +370,23 @@ addHook({
362
370
  file: 'lib/runner.js'
363
371
  }, mochaHook)
364
372
 
373
+ addHook({
374
+ name: 'mocha',
375
+ versions: ['>=5.2.0'],
376
+ file: 'lib/cli/run-helpers.js'
377
+ }, (run) => {
378
+ shimmer.wrap(run, 'runMocha', runMocha => async function () {
379
+ const mocha = arguments[0]
380
+ /**
381
+ * This attaches `run` to the global context, which we'll call after
382
+ * our configuration and skippable suites requests
383
+ */
384
+ mocha.options.delay = true
385
+ return runMocha.apply(this, arguments)
386
+ })
387
+ return run
388
+ })
389
+
365
390
  addHook({
366
391
  name: 'mocha',
367
392
  versions: ['>=5.2.0'],
@@ -40,9 +40,13 @@ function wrapQuery (query) {
40
40
  const callbackResource = new AsyncResource('bound-anonymous-fn')
41
41
  const asyncResource = new AsyncResource('bound-anonymous-fn')
42
42
  const processId = this.processID
43
-
44
43
  return asyncResource.runInAsyncScope(() => {
45
- startCh.publish({ params: this.connectionParameters, query: pgQuery, processId })
44
+ startCh.publish({
45
+ params: this.connectionParameters,
46
+ originalQuery: pgQuery.text,
47
+ query: pgQuery,
48
+ processId
49
+ })
46
50
 
47
51
  const finish = asyncResource.bind(function (error) {
48
52
  if (error) {
@@ -117,7 +117,7 @@ function addRequestHeaders (req, span, config) {
117
117
  const value = req.getHeader(key)
118
118
 
119
119
  if (value) {
120
- span.setTag(`${HTTP_REQUEST_HEADERS}.${key}`, value)
120
+ span.setTag(`${HTTP_REQUEST_HEADERS}.${key}`, Array.isArray(value) ? value.toString() : value)
121
121
  }
122
122
  })
123
123
  }
@@ -3,7 +3,7 @@
3
3
  const Plugin = require('../../dd-trace/src/plugins/plugin')
4
4
  const { storage } = require('../../datadog-core')
5
5
  const web = require('../../dd-trace/src/plugins/util/web')
6
- const { incomingHttpRequestStart } = require('../../dd-trace/src/appsec/gateway/channels')
6
+ const { incomingHttpRequestStart, incomingHttpRequestEnd } = require('../../dd-trace/src/appsec/gateway/channels')
7
7
  const { COMPONENT } = require('../../dd-trace/src/constants')
8
8
 
9
9
  class HttpServerPlugin extends Plugin {
@@ -16,7 +16,7 @@ class HttpServerPlugin extends Plugin {
16
16
 
17
17
  this._parentStore = undefined
18
18
 
19
- this.addSub('apm:http:server:request:start', ({ req, res }) => {
19
+ this.addSub('apm:http:server:request:start', ({ req, res, abortController }) => {
20
20
  const store = storage.getStore()
21
21
  const span = web.startSpan(this.tracer, this.config, req, res, 'web.request')
22
22
 
@@ -33,7 +33,7 @@ class HttpServerPlugin extends Plugin {
33
33
  }
34
34
 
35
35
  if (incomingHttpRequestStart.hasSubscribers) {
36
- incomingHttpRequestStart.publish({ req, res })
36
+ incomingHttpRequestStart.publish({ req, res, abortController })
37
37
  }
38
38
  })
39
39
 
@@ -52,6 +52,10 @@ class HttpServerPlugin extends Plugin {
52
52
 
53
53
  if (!context || !context.res) return // Not created by a http.Server instance.
54
54
 
55
+ if (incomingHttpRequestEnd.hasSubscribers) {
56
+ incomingHttpRequestEnd.publish({ req, res: context.res })
57
+ }
58
+
55
59
  web.finishAll(context)
56
60
  })
57
61
  }
@@ -15,7 +15,7 @@ const {
15
15
  TEST_SUITE_ID,
16
16
  TEST_COMMAND,
17
17
  TEST_ITR_TESTS_SKIPPED,
18
- TEST_SESSION_ITR_CODE_COVERAGE_ENABLED,
18
+ TEST_SESSION_CODE_COVERAGE_ENABLED,
19
19
  TEST_SESSION_ITR_SKIPPING_ENABLED,
20
20
  TEST_CODE_COVERAGE_LINES_TOTAL
21
21
  } = require('../../dd-trace/src/plugins/util/test')
@@ -77,7 +77,7 @@ class JestPlugin extends CiPlugin {
77
77
  testSessionSpan.setTag(TEST_STATUS, status)
78
78
  testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false')
79
79
  testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
80
- testSessionSpan.setTag(TEST_SESSION_ITR_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
80
+ testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
81
81
 
82
82
  if (testCodeCoverageLinesTotal !== undefined) {
83
83
  testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal)
@@ -16,7 +16,7 @@ const {
16
16
  TEST_SESSION_ID,
17
17
  TEST_COMMAND,
18
18
  TEST_ITR_TESTS_SKIPPED,
19
- TEST_SESSION_ITR_CODE_COVERAGE_ENABLED,
19
+ TEST_SESSION_CODE_COVERAGE_ENABLED,
20
20
  TEST_SESSION_ITR_SKIPPING_ENABLED
21
21
  } = require('../../dd-trace/src/plugins/util/test')
22
22
  const { COMPONENT } = require('../../dd-trace/src/constants')
@@ -145,7 +145,7 @@ class MochaPlugin extends CiPlugin {
145
145
  this.testSessionSpan.setTag(TEST_STATUS, status)
146
146
  this.testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false')
147
147
  this.testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
148
- this.testSessionSpan.setTag(TEST_SESSION_ITR_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
148
+ this.testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
149
149
 
150
150
  this.testSessionSpan.finish()
151
151
  finishAllTraceSpans(this.testSessionSpan)
@@ -26,7 +26,7 @@ class PGPlugin extends DatabasePlugin {
26
26
  }
27
27
  })
28
28
 
29
- query.text = this.injectDbmQuery(query.text)
29
+ query.text = this.injectDbmQuery(query.text, service)
30
30
  }
31
31
  }
32
32
 
@@ -29,8 +29,9 @@ class RouterPlugin extends WebPlugin {
29
29
  context.middleware.push(span)
30
30
  }
31
31
 
32
- this._storeStack.push(storage.getStore())
33
- this.enter(span)
32
+ const store = storage.getStore()
33
+ this._storeStack.push(store)
34
+ this.enter(span, store)
34
35
 
35
36
  web.patch(req)
36
37
  web.setRoute(req, context.route)
@@ -53,7 +54,9 @@ class RouterPlugin extends WebPlugin {
53
54
  })
54
55
 
55
56
  this.addSub(`apm:${this.constructor.name}:middleware:exit`, ({ req }) => {
56
- this.enter(this._storeStack.pop())
57
+ const savedStore = this._storeStack.pop()
58
+ const span = savedStore && savedStore.span
59
+ this.enter(span, savedStore)
57
60
  })
58
61
 
59
62
  this.addSub(`apm:${this.constructor.name}:middleware:error`, ({ req, error }) => {
@@ -14,5 +14,7 @@ module.exports = {
14
14
  HTTP_INCOMING_RESPONSE_HEADERS: 'server.response.headers.no_cookies',
15
15
  // TODO: 'server.response.trailers',
16
16
  HTTP_INCOMING_REMOTE_IP: 'server.request.client_ip',
17
- HTTP_INCOMING_REMOTE_PORT: 'server.request.client_port'
17
+ HTTP_INCOMING_REMOTE_PORT: 'server.request.client_port',
18
+
19
+ HTTP_CLIENT_IP: 'http.client_ip'
18
20
  }
@@ -0,0 +1,44 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+ let templateHtml, templateJson
5
+ function block (req, res, topSpan, abortController) {
6
+ let type
7
+ let body
8
+
9
+ // parse the Accept header, ex: Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
10
+ const accept = req.headers.accept && req.headers.accept.split(',').map((str) => str.split(';', 1)[0].trim())
11
+
12
+ if (accept && accept.includes('text/html') && !accept.includes('application/json')) {
13
+ type = 'text/html'
14
+ body = templateHtml
15
+ } else {
16
+ type = 'application/json'
17
+ body = templateJson
18
+ }
19
+
20
+ topSpan.addTags({
21
+ 'appsec.blocked': 'true'
22
+ })
23
+
24
+ res.statusCode = 403
25
+ res.setHeader('Content-Type', type)
26
+ res.setHeader('Content-Length', Buffer.byteLength(body))
27
+ res.end(body)
28
+
29
+ abortController.abort()
30
+ }
31
+
32
+ function loadTemplates (config) {
33
+ templateHtml = fs.readFileSync(config.appsec.blockedTemplateHtml)
34
+ templateJson = fs.readFileSync(config.appsec.blockedTemplateJson)
35
+ }
36
+
37
+ async function loadTemplatesAsync (config) {
38
+ templateHtml = await fs.promises.readFile(config.appsec.blockedTemplateHtml)
39
+ templateJson = await fs.promises.readFile(config.appsec.blockedTemplateJson)
40
+ }
41
+
42
+ module.exports = {
43
+ block, loadTemplates, loadTemplatesAsync
44
+ }
@@ -61,7 +61,7 @@ class WAFCallback {
61
61
 
62
62
  subscribedAddresses.add(address)
63
63
 
64
- Gateway.manager.addSubscription({ addresses: [ address ], callback })
64
+ Gateway.manager.addSubscription({ addresses: [address], callback })
65
65
  }
66
66
  }
67
67
  }
@@ -28,7 +28,7 @@ class SubscriptionManager {
28
28
  const list = this.addressToSubscriptions.get(address)
29
29
 
30
30
  if (list === undefined) {
31
- this.addressToSubscriptions.set(address, [ subscription ])
31
+ this.addressToSubscriptions.set(address, [subscription])
32
32
  } else {
33
33
  list.push(subscription)
34
34
  }
@@ -22,6 +22,10 @@ function getContext () {
22
22
  return store && store.get('context')
23
23
  }
24
24
 
25
+ function needsAddress (address) {
26
+ return manager.addresses.has(address)
27
+ }
28
+
25
29
  function propagate (data, context = getContext()) {
26
30
  if (!context) return
27
31
 
@@ -30,7 +34,7 @@ function propagate (data, context = getContext()) {
30
34
  for (let i = 0; i < keys.length; ++i) {
31
35
  const key = keys[i]
32
36
 
33
- if (manager.addresses.has(key)) {
37
+ if (needsAddress(key)) {
34
38
  context.setValue(key, data[key])
35
39
  }
36
40
  }
@@ -42,5 +46,6 @@ module.exports = {
42
46
  manager,
43
47
  startContext,
44
48
  getContext,
49
+ needsAddress,
45
50
  propagate
46
51
  }
@@ -26,7 +26,6 @@ function runSubscriptions (subscriptions, params) {
26
26
  result = subscription.callback.method(params, store)
27
27
  } catch (err) {
28
28
  // TODO: log ?
29
- result = {}
30
29
  }
31
30
 
32
31
  results.push(result)
@@ -2,5 +2,6 @@ module.exports = {
2
2
  'WEAK_CIPHER_ANALYZER': require('./weak-cipher-analyzer'),
3
3
  'WEAK_HASH_ANALYZER': require('./weak-hash-analyzer'),
4
4
  'SQL_INJECTION_ANALYZER': require('./sql-injection-analyzer'),
5
- 'COMMAND_INJECTION_ANALYZER': require('./command-injection-analyzer')
5
+ 'COMMAND_INJECTION_ANALYZER': require('./command-injection-analyzer'),
6
+ 'LDAP_ANALYZER': require('./ldap-injection-analyzer')
6
7
  }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+ const InjectionAnalyzer = require('./injection-analyzer')
3
+
4
+ class LdapInjectionAnalyzer extends InjectionAnalyzer {
5
+ constructor () {
6
+ super('LDAP_INJECTION')
7
+ this.addSub('datadog:ldapjs:client:search', ({ base, filter }) => this.analyzeAll(base, filter))
8
+ }
9
+ }
10
+
11
+ module.exports = new LdapInjectionAnalyzer()
@@ -6,7 +6,7 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {
6
6
  super('SQL_INJECTION')
7
7
  this.addSub('apm:mysql:query:start', ({ sql }) => this.analyze(sql))
8
8
  this.addSub('apm:mysql2:query:start', ({ sql }) => this.analyze(sql))
9
- this.addSub('apm:pg:query:start', ({ query }) => query && this.analyze(query.text))
9
+ this.addSub('apm:pg:query:start', ({ originalQuery }) => this.analyze(originalQuery))
10
10
  }
11
11
  }
12
12