dd-trace 3.11.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 (38) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +16 -0
  3. package/package.json +6 -4
  4. package/packages/datadog-instrumentations/src/helpers/register.js +7 -0
  5. package/packages/datadog-instrumentations/src/mocha.js +33 -8
  6. package/packages/datadog-instrumentations/src/pg.js +6 -1
  7. package/packages/datadog-plugin-http/src/client.js +1 -1
  8. package/packages/datadog-plugin-jest/src/index.js +2 -2
  9. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  10. package/packages/datadog-plugin-pg/src/index.js +1 -1
  11. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +6 -6
  12. package/packages/dd-trace/src/appsec/iast/index.js +8 -3
  13. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
  14. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +6 -1
  15. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +24 -6
  16. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +63 -41
  17. package/packages/dd-trace/src/appsec/recommended.json +75 -8
  18. package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
  19. package/packages/dd-trace/src/config.js +24 -5
  20. package/packages/dd-trace/src/exporters/common/request.js +33 -1
  21. package/packages/dd-trace/src/format.js +5 -1
  22. package/packages/dd-trace/src/lambda/handler.js +72 -0
  23. package/packages/dd-trace/src/lambda/index.js +5 -0
  24. package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
  25. package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
  26. package/packages/dd-trace/src/lambda/runtime/ritm.js +143 -0
  27. package/packages/dd-trace/src/plugin_manager.js +4 -0
  28. package/packages/dd-trace/src/plugins/ci_plugin.js +6 -0
  29. package/packages/dd-trace/src/plugins/database.js +4 -4
  30. package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
  31. package/packages/dd-trace/src/plugins/util/ci.js +5 -2
  32. package/packages/dd-trace/src/plugins/util/test.js +2 -2
  33. package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
  34. package/packages/dd-trace/src/priority_sampler.js +6 -2
  35. package/packages/dd-trace/src/proxy.js +4 -3
  36. package/packages/dd-trace/src/ritm.js +7 -1
  37. package/packages/dd-trace/src/span_processor.js +13 -0
  38. package/packages/dd-trace/src/span_sampler.js +1 -4
@@ -63,4 +63,5 @@ dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
63
63
  dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
64
64
  dev,tape,MIT,Copyright James Halliday
65
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.
66
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.
@@ -521,6 +526,17 @@ export declare interface TracerOptions {
521
526
  */
522
527
  blockedTemplateJson?: string,
523
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
+ }
524
540
  }
525
541
 
526
542
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "3.11.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,12 +16,14 @@
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\" --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/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",
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: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",
25
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\"",
26
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",
@@ -60,7 +62,7 @@
60
62
  "dependencies": {
61
63
  "@datadog/native-appsec": "2.0.0",
62
64
  "@datadog/native-iast-rewriter": "1.1.2",
63
- "@datadog/native-iast-taint-tracking": "1.0.0",
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",
@@ -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
+ }
@@ -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'],
@@ -41,7 +41,12 @@ function wrapQuery (query) {
41
41
  const asyncResource = new AsyncResource('bound-anonymous-fn')
42
42
  const processId = this.processID
43
43
  return asyncResource.runInAsyncScope(() => {
44
- startCh.publish({ params: this.connectionParameters, originalQuery: pgQuery.text, query: pgQuery, processId })
44
+ startCh.publish({
45
+ params: this.connectionParameters,
46
+ originalQuery: pgQuery.text,
47
+ query: pgQuery,
48
+ processId
49
+ })
45
50
 
46
51
  const finish = asyncResource.bind(function (error) {
47
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
  }
@@ -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
 
@@ -57,16 +57,16 @@ class Analyzer extends Plugin {
57
57
  }
58
58
 
59
59
  analyze (value) {
60
- const iastContext = getIastContext(storage.getStore())
61
- if (!iastContext) return
62
-
60
+ const store = storage.getStore()
61
+ const iastContext = getIastContext(store)
62
+ if (store && !iastContext) return
63
63
  this._reportIfVulnerable(value, iastContext)
64
64
  }
65
65
 
66
66
  analyzeAll (...values) {
67
- const iastContext = getIastContext(storage.getStore())
68
- if (!iastContext) return
69
-
67
+ const store = storage.getStore()
68
+ const iastContext = getIastContext(store)
69
+ if (store && !iastContext) return
70
70
  for (let i = 0; i < values.length; i++) {
71
71
  const value = values[i]
72
72
  if (this._isVulnerable(value, iastContext)) {
@@ -1,4 +1,4 @@
1
- const { sendVulnerabilities } = require('./vulnerability-reporter')
1
+ const { sendVulnerabilities, setTracer } = require('./vulnerability-reporter')
2
2
  const { enableAllAnalyzers, disableAllAnalyzers } = require('./analyzers')
3
3
  const web = require('../../plugins/util/web')
4
4
  const { storage } = require('../../../../datadog-core')
@@ -14,17 +14,20 @@ const IAST_ENABLED_TAG_KEY = '_dd.iast.enabled'
14
14
  const requestStart = dc.channel('dd-trace:incomingHttpRequestStart')
15
15
  const requestClose = dc.channel('dd-trace:incomingHttpRequestEnd')
16
16
 
17
- function enable (config) {
17
+ function enable (config, _tracer) {
18
18
  enableAllAnalyzers()
19
19
  enableTaintTracking()
20
20
  requestStart.subscribe(onIncomingHttpRequestStart)
21
21
  requestClose.subscribe(onIncomingHttpRequestEnd)
22
22
  overheadController.configure(config.iast)
23
+ overheadController.startGlobalContext()
24
+ setTracer(_tracer)
23
25
  }
24
26
 
25
27
  function disable () {
26
28
  disableAllAnalyzers()
27
29
  disableTaintTracking()
30
+ overheadController.finishGlobalContext()
28
31
  if (requestStart.hasSubscribers) requestStart.unsubscribe(onIncomingHttpRequestStart)
29
32
  if (requestClose.hasSubscribers) requestClose.unsubscribe(onIncomingHttpRequestEnd)
30
33
  }
@@ -57,7 +60,9 @@ function onIncomingHttpRequestEnd (data) {
57
60
  const store = storage.getStore()
58
61
  const iastContext = iastContextFunctions.getIastContext(storage.getStore())
59
62
  if (iastContext && iastContext.rootSpan) {
60
- sendVulnerabilities(iastContext, iastContext.rootSpan)
63
+ const vulnerabilities = iastContext.vulnerabilities
64
+ const rootSpan = iastContext.rootSpan
65
+ sendVulnerabilities(vulnerabilities, rootSpan)
61
66
  removeTransaction(iastContext)
62
67
  }
63
68
  // TODO web.getContext(data.req) is required when the request is aborted
@@ -2,8 +2,11 @@
2
2
 
3
3
  const OVERHEAD_CONTROLLER_CONTEXT_KEY = 'oce'
4
4
  const REPORT_VULNERABILITY = 'REPORT_VULNERABILITY'
5
+ const INTERVAL_RESET_GLOBAL_CONTEXT = 60 * 1000
5
6
 
6
7
  const GLOBAL_OCE_CONTEXT = {}
8
+
9
+ let resetGlobalContextInterval
7
10
  let config = {}
8
11
  let availableRequest = 0
9
12
  const OPERATIONS = {
@@ -80,11 +83,27 @@ function configure (cfg) {
80
83
  availableRequest = config.maxConcurrentRequests
81
84
  }
82
85
 
83
- _resetGlobalContext()
86
+ function startGlobalContext () {
87
+ if (resetGlobalContextInterval) return
88
+ _resetGlobalContext()
89
+ resetGlobalContextInterval = setInterval(() => {
90
+ _resetGlobalContext()
91
+ }, INTERVAL_RESET_GLOBAL_CONTEXT)
92
+ resetGlobalContextInterval.unref && resetGlobalContextInterval.unref()
93
+ }
94
+
95
+ function finishGlobalContext () {
96
+ if (resetGlobalContextInterval) {
97
+ clearInterval(resetGlobalContextInterval)
98
+ resetGlobalContextInterval = null
99
+ }
100
+ }
84
101
 
85
102
  module.exports = {
86
103
  OVERHEAD_CONTROLLER_CONTEXT_KEY,
87
104
  OPERATIONS,
105
+ startGlobalContext,
106
+ finishGlobalContext,
88
107
  _resetGlobalContext,
89
108
  initializeRequestContext,
90
109
  hasQuota,
@@ -4,7 +4,12 @@ const csiMethods = [
4
4
  { src: 'plusOperator', operator: true },
5
5
  { src: 'trim' },
6
6
  { src: 'trimStart', dst: 'trim' },
7
- { src: 'trimEnd' }
7
+ { src: 'trimEnd' },
8
+ { src: 'concat' },
9
+ { src: 'substring' },
10
+ { src: 'substr' },
11
+ { src: 'slice' },
12
+ { src: 'replace' }
8
13
  ]
9
14
 
10
15
  module.exports = {
@@ -9,7 +9,12 @@ function noop (res) { return res }
9
9
  const TaintTrackingDummy = {
10
10
  plusOperator: noop,
11
11
  trim: noop,
12
- trimEnd: noop
12
+ trimEnd: noop,
13
+ concat: noop,
14
+ substring: noop,
15
+ substr: noop,
16
+ slice: noop,
17
+ replace: noop
13
18
  }
14
19
 
15
20
  function getTransactionId () {
@@ -54,7 +59,19 @@ function getCsiFn (cb, ...protos) {
54
59
  return getFilteredCsiFn(cb, filter)
55
60
  }
56
61
 
57
- const TaintTracking = {
62
+ function csiMethodsDefaults (names, excluded) {
63
+ const impl = {}
64
+ names.forEach(name => {
65
+ if (excluded.indexOf(name) !== -1) return
66
+ impl[name] = getCsiFn(
67
+ (transactionId, res, target, ...rest) => TaintedUtils[name](transactionId, res, target, ...rest),
68
+ String.prototype[name]
69
+ )
70
+ })
71
+ return impl
72
+ }
73
+
74
+ const csiMethodsOverrides = {
58
75
  plusOperator: function (res, op1, op2) {
59
76
  try {
60
77
  if (notString(res) || (notString(op1) && notString(op2))) { return res }
@@ -72,13 +89,14 @@ const TaintTracking = {
72
89
  (transactionId, res, target) => TaintedUtils.trim(transactionId, res, target),
73
90
  String.prototype.trim,
74
91
  String.prototype.trimStart
75
- ),
76
- trimEnd: getCsiFn(
77
- (transactionId, res, target) => TaintedUtils.trimEnd(transactionId, res, target),
78
- String.prototype.trimEnd
79
92
  )
80
93
  }
81
94
 
95
+ const TaintTracking = {
96
+ ...csiMethodsDefaults(Object.keys(TaintTrackingDummy), Object.keys(csiMethodsOverrides)),
97
+ ...csiMethodsOverrides
98
+ }
99
+
82
100
  module.exports = {
83
101
  TaintTracking,
84
102
  TaintTrackingDummy
@@ -5,13 +5,16 @@ const IAST_JSON_TAG_KEY = '_dd.iast.json'
5
5
  const VULNERABILITY_HASHES_MAX_SIZE = 1000
6
6
  const VULNERABILITY_HASHES = new LRU({ max: VULNERABILITY_HASHES_MAX_SIZE })
7
7
 
8
+ let tracer
9
+
8
10
  function createVulnerability (type, evidence, spanId, location) {
9
- if (type && evidence && spanId) {
11
+ if (type && evidence) {
12
+ const _spanId = spanId || 0
10
13
  return {
11
14
  type,
12
15
  evidence,
13
16
  location: {
14
- spanId,
17
+ spanId: _spanId,
15
18
  ...location
16
19
  },
17
20
  hash: createHash(type, location)
@@ -37,10 +40,14 @@ function createHash (type, location) {
37
40
  }
38
41
 
39
42
  function addVulnerability (iastContext, vulnerability) {
40
- if (iastContext && vulnerability && vulnerability.evidence && vulnerability.type &&
41
- vulnerability.location && vulnerability.location.spanId) {
42
- iastContext[VULNERABILITIES_KEY] = iastContext[VULNERABILITIES_KEY] || []
43
- iastContext[VULNERABILITIES_KEY].push(vulnerability)
43
+ if (vulnerability && vulnerability.evidence && vulnerability.type &&
44
+ vulnerability.location) {
45
+ if (iastContext && iastContext.rootSpan) {
46
+ iastContext[VULNERABILITIES_KEY] = iastContext[VULNERABILITIES_KEY] || []
47
+ iastContext[VULNERABILITIES_KEY].push(vulnerability)
48
+ } else {
49
+ sendVulnerabilities([vulnerability])
50
+ }
44
51
  }
45
52
  }
46
53
 
@@ -101,43 +108,53 @@ function jsonVulnerabilityFromVulnerability (vulnerability, sourcesIndexes) {
101
108
  return jsonVulnerability
102
109
  }
103
110
 
104
- function sendVulnerabilities (iastContext) {
105
- if (iastContext && iastContext.rootSpan && iastContext[VULNERABILITIES_KEY] &&
106
- iastContext[VULNERABILITIES_KEY].length && iastContext.rootSpan.addTags) {
107
- const span = iastContext.rootSpan
108
- const allVulnerabilities = iastContext[VULNERABILITIES_KEY]
109
- const jsonToSend = {
110
- sources: [],
111
- vulnerabilities: []
111
+ function sendVulnerabilities (vulnerabilities, rootSpan) {
112
+ if (vulnerabilities && vulnerabilities.length) {
113
+ let span = rootSpan
114
+ if (!span && tracer) {
115
+ span = tracer.startSpan('vulnerability', {
116
+ type: 'vulnerability'
117
+ })
118
+ vulnerabilities.forEach((vulnerability) => {
119
+ vulnerability.location.spanId = span.context().toSpanId()
120
+ })
112
121
  }
113
122
 
114
- deduplicateVulnerabilities(allVulnerabilities).forEach((vulnerability) => {
115
- if (isValidVulnerability(vulnerability)) {
116
- const sourcesIndexes = []
117
- const vulnerabilitySources = extractSourcesFromVulnerability(vulnerability)
118
- vulnerabilitySources.forEach((source) => {
119
- let sourceIndex = jsonToSend.sources.findIndex(
120
- existingSource =>
121
- existingSource.origin === source.origin &&
122
- existingSource.name === source.name &&
123
- existingSource.value === source.value
124
- )
125
- if (sourceIndex === -1) {
126
- sourceIndex = jsonToSend.sources.length
127
- jsonToSend.sources.push(source)
128
- }
129
- sourcesIndexes.push(sourceIndex)
130
- })
131
- jsonToSend.vulnerabilities.push(jsonVulnerabilityFromVulnerability(vulnerability, sourcesIndexes))
123
+ if (span && span.addTags) {
124
+ const jsonToSend = {
125
+ sources: [],
126
+ vulnerabilities: []
127
+ }
128
+
129
+ deduplicateVulnerabilities(vulnerabilities).forEach((vulnerability) => {
130
+ if (isValidVulnerability(vulnerability)) {
131
+ const sourcesIndexes = []
132
+ const vulnerabilitySources = extractSourcesFromVulnerability(vulnerability)
133
+ vulnerabilitySources.forEach((source) => {
134
+ let sourceIndex = jsonToSend.sources.findIndex(
135
+ existingSource =>
136
+ existingSource.origin === source.origin &&
137
+ existingSource.name === source.name &&
138
+ existingSource.value === source.value
139
+ )
140
+ if (sourceIndex === -1) {
141
+ sourceIndex = jsonToSend.sources.length
142
+ jsonToSend.sources.push(source)
143
+ }
144
+ sourcesIndexes.push(sourceIndex)
145
+ })
146
+ jsonToSend.vulnerabilities.push(jsonVulnerabilityFromVulnerability(vulnerability, sourcesIndexes))
147
+ }
148
+ })
149
+
150
+ if (jsonToSend.vulnerabilities.length > 0) {
151
+ const tags = {}
152
+ // TODO: Store this outside of the span and set the tag in the exporter.
153
+ tags[IAST_JSON_TAG_KEY] = JSON.stringify(jsonToSend)
154
+ tags[MANUAL_KEEP] = 'true'
155
+ span.addTags(tags)
156
+ if (!rootSpan) span.finish()
132
157
  }
133
- })
134
-
135
- if (jsonToSend.vulnerabilities.length > 0) {
136
- const tags = {}
137
- // TODO: Store this outside of the span and set the tag in the exporter.
138
- tags[IAST_JSON_TAG_KEY] = JSON.stringify(jsonToSend)
139
- tags[MANUAL_KEEP] = 'true'
140
- span.addTags(tags)
141
158
  }
142
159
  }
143
160
  return IAST_JSON_TAG_KEY
@@ -159,9 +176,14 @@ function deduplicateVulnerabilities (vulnerabilities) {
159
176
  return deduplicated
160
177
  }
161
178
 
179
+ function setTracer (_tracer) {
180
+ tracer = _tracer
181
+ }
182
+
162
183
  module.exports = {
163
184
  createVulnerability,
164
185
  addVulnerability,
165
186
  sendVulnerabilities,
166
- clearCache
187
+ clearCache,
188
+ setTracer
167
189
  }