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.
- package/LICENSE-3rdparty.csv +2 -0
- package/index.d.ts +33 -1
- package/package.json +10 -7
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +7 -0
- package/packages/datadog-instrumentations/src/http/server.js +7 -1
- package/packages/datadog-instrumentations/src/ldapjs.js +91 -0
- package/packages/datadog-instrumentations/src/mocha.js +33 -8
- package/packages/datadog-instrumentations/src/pg.js +6 -2
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +7 -3
- package/packages/datadog-plugin-jest/src/index.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +2 -2
- package/packages/datadog-plugin-pg/src/index.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +6 -3
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +44 -0
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
- package/packages/dd-trace/src/appsec/gateway/engine/engine.js +1 -1
- package/packages/dd-trace/src/appsec/gateway/engine/index.js +6 -1
- package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -3
- package/packages/dd-trace/src/appsec/iast/iast-context.js +3 -1
- package/packages/dd-trace/src/appsec/iast/index.js +15 -3
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +6 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +17 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -29
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +16 -15
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +103 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +63 -41
- package/packages/dd-trace/src/appsec/index.js +68 -27
- package/packages/dd-trace/src/{plugins/util → appsec}/ip_blocklist.js +0 -0
- package/packages/dd-trace/src/appsec/ip_extractor.js +98 -0
- package/packages/dd-trace/src/appsec/recommended.json +75 -8
- package/packages/dd-trace/src/appsec/remote_config/index.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
- package/packages/dd-trace/src/appsec/templates/blocked.html +99 -0
- package/packages/dd-trace/src/appsec/templates/blocked.json +8 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +4 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +18 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +12 -6
- package/packages/dd-trace/src/config.js +48 -7
- package/packages/dd-trace/src/exporters/common/request.js +33 -1
- package/packages/dd-trace/src/format.js +5 -1
- package/packages/dd-trace/src/lambda/handler.js +72 -0
- package/packages/dd-trace/src/lambda/index.js +5 -0
- package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
- package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
- package/packages/dd-trace/src/lambda/runtime/ritm.js +143 -0
- package/packages/dd-trace/src/plugin_manager.js +4 -10
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -0
- package/packages/dd-trace/src/plugins/database.js +4 -4
- package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
- package/packages/dd-trace/src/plugins/util/ci.js +5 -2
- package/packages/dd-trace/src/plugins/util/test.js +2 -2
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
- package/packages/dd-trace/src/plugins/util/web.js +1 -104
- package/packages/dd-trace/src/priority_sampler.js +6 -2
- package/packages/dd-trace/src/proxy.js +4 -3
- package/packages/dd-trace/src/ritm.js +7 -1
- package/packages/dd-trace/src/span_processor.js +13 -0
- package/packages/dd-trace/src/span_sampler.js +1 -4
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -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.
|
|
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:
|
|
26
|
-
"test:
|
|
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.
|
|
63
|
-
"@datadog/native-iast-taint-tracking": "1.
|
|
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'),
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
346
|
+
return global.run()
|
|
340
347
|
}
|
|
341
348
|
if (!skippableSuitesCh.hasSubscribers) {
|
|
342
|
-
return run
|
|
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({
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
148
|
+
this.testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
|
|
149
149
|
|
|
150
150
|
this.testSessionSpan.finish()
|
|
151
151
|
finishAllTraceSpans(this.testSessionSpan)
|
|
@@ -29,8 +29,9 @@ class RouterPlugin extends WebPlugin {
|
|
|
29
29
|
context.middleware.push(span)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
this.
|
|
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.
|
|
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
|
+
}
|
|
@@ -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, [
|
|
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 (
|
|
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
|
}
|
|
@@ -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', ({
|
|
9
|
+
this.addSub('apm:pg:query:start', ({ originalQuery }) => this.analyze(originalQuery))
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|