dd-trace 4.47.1 → 4.48.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 (84) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ext/types.d.ts +1 -0
  3. package/ext/types.js +1 -0
  4. package/index.d.ts +26 -0
  5. package/package.json +6 -7
  6. package/packages/datadog-code-origin/index.js +38 -0
  7. package/packages/datadog-core/index.js +2 -2
  8. package/packages/datadog-instrumentations/src/avsc.js +37 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
  10. package/packages/datadog-instrumentations/src/child_process.js +17 -8
  11. package/packages/datadog-instrumentations/src/express.js +37 -4
  12. package/packages/datadog-instrumentations/src/fastify.js +12 -1
  13. package/packages/datadog-instrumentations/src/fs.js +27 -7
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  15. package/packages/datadog-instrumentations/src/jest.js +2 -1
  16. package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
  17. package/packages/datadog-instrumentations/src/mysql2.js +220 -1
  18. package/packages/datadog-instrumentations/src/protobufjs.js +127 -0
  19. package/packages/datadog-instrumentations/src/winston.js +22 -0
  20. package/packages/datadog-plugin-avsc/src/index.js +9 -0
  21. package/packages/datadog-plugin-avsc/src/schema_iterator.js +169 -0
  22. package/packages/datadog-plugin-azure-functions/src/index.js +77 -0
  23. package/packages/datadog-plugin-fastify/src/code_origin.js +31 -0
  24. package/packages/datadog-plugin-fastify/src/index.js +10 -12
  25. package/packages/datadog-plugin-fastify/src/tracing.js +19 -0
  26. package/packages/datadog-plugin-protobufjs/src/index.js +14 -0
  27. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +180 -0
  28. package/packages/dd-trace/src/appsec/addresses.js +6 -1
  29. package/packages/dd-trace/src/appsec/channels.js +5 -1
  30. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +13 -1
  31. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +8 -1
  32. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  33. package/packages/dd-trace/src/appsec/iast/index.js +3 -0
  34. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +1 -0
  35. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +15 -0
  36. package/packages/dd-trace/src/appsec/index.js +58 -43
  37. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +99 -0
  38. package/packages/dd-trace/src/appsec/rasp/index.js +24 -10
  39. package/packages/dd-trace/src/appsec/rasp/lfi.js +112 -0
  40. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +24 -4
  41. package/packages/dd-trace/src/appsec/rasp/utils.js +2 -1
  42. package/packages/dd-trace/src/appsec/recommended.json +2 -4
  43. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +5 -1
  44. package/packages/dd-trace/src/appsec/remote_config/index.js +8 -0
  45. package/packages/dd-trace/src/appsec/reporter.js +12 -5
  46. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -0
  47. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +1 -1
  48. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -14
  49. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +53 -0
  50. package/packages/dd-trace/src/config.js +12 -1
  51. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +25 -17
  52. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  53. package/packages/dd-trace/src/debugger/devtools_client/index.js +56 -5
  54. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +4 -4
  55. package/packages/dd-trace/src/debugger/devtools_client/send.js +14 -1
  56. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +153 -0
  57. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +30 -0
  58. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +241 -0
  59. package/packages/dd-trace/src/debugger/devtools_client/state.js +10 -4
  60. package/packages/dd-trace/src/exporters/common/request.js +8 -34
  61. package/packages/dd-trace/src/exporters/common/url-to-http-options-polyfill.js +31 -0
  62. package/packages/dd-trace/src/payload-tagging/index.js +1 -1
  63. package/packages/dd-trace/src/payload-tagging/jsonpath-plus.js +2094 -0
  64. package/packages/dd-trace/src/plugin_manager.js +4 -2
  65. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -0
  66. package/packages/dd-trace/src/plugins/index.js +3 -0
  67. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  68. package/packages/dd-trace/src/plugins/schema.js +35 -0
  69. package/packages/dd-trace/src/plugins/util/ci.js +23 -1
  70. package/packages/dd-trace/src/plugins/util/serverless.js +7 -0
  71. package/packages/dd-trace/src/plugins/util/stacktrace.js +94 -0
  72. package/packages/dd-trace/src/plugins/util/tags.js +7 -0
  73. package/packages/dd-trace/src/plugins/util/test.js +20 -22
  74. package/packages/dd-trace/src/plugins/util/web.js +6 -4
  75. package/packages/dd-trace/src/profiling/profiler.js +24 -14
  76. package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
  77. package/packages/dd-trace/src/profiling/profilers/wall.js +94 -66
  78. package/packages/dd-trace/src/proxy.js +12 -0
  79. package/packages/dd-trace/src/service-naming/schemas/v0/index.js +2 -1
  80. package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
  81. package/packages/dd-trace/src/service-naming/schemas/v1/index.js +2 -1
  82. package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
  83. package/packages/datadog-core/src/storage/async_resource.js +0 -108
  84. package/packages/datadog-core/src/storage/index.js +0 -5
@@ -1,10 +1,11 @@
1
1
  'use strict'
2
2
 
3
3
  const web = require('../../plugins/util/web')
4
- const { setUncaughtExceptionCaptureCallbackStart } = require('../channels')
5
- const { block } = require('../blocking')
4
+ const { setUncaughtExceptionCaptureCallbackStart, expressMiddlewareError } = require('../channels')
5
+ const { block, isBlocked } = require('../blocking')
6
6
  const ssrf = require('./ssrf')
7
7
  const sqli = require('./sql_injection')
8
+ const lfi = require('./lfi')
8
9
 
9
10
  const { DatadogRaspAbortError } = require('./utils')
10
11
 
@@ -30,17 +31,13 @@ function findDatadogRaspAbortError (err, deep = 10) {
30
31
  return err
31
32
  }
32
33
 
33
- if (err.cause && deep > 0) {
34
+ if (err?.cause && deep > 0) {
34
35
  return findDatadogRaspAbortError(err.cause, deep - 1)
35
36
  }
36
37
  }
37
38
 
38
- function handleUncaughtExceptionMonitor (err) {
39
- const abortError = findDatadogRaspAbortError(err)
40
- if (!abortError) return
41
-
42
- const { req, res, blockingAction } = abortError
43
- block(req, res, web.root(req), null, blockingAction)
39
+ function handleUncaughtExceptionMonitor (error) {
40
+ if (!blockOnDatadogRaspAbortError({ error })) return
44
41
 
45
42
  if (!process.hasUncaughtExceptionCaptureCallback()) {
46
43
  const cleanUp = removeAllListeners(process, 'uncaughtException')
@@ -82,22 +79,39 @@ function handleUncaughtExceptionMonitor (err) {
82
79
  }
83
80
  }
84
81
 
82
+ function blockOnDatadogRaspAbortError ({ error }) {
83
+ const abortError = findDatadogRaspAbortError(error)
84
+ if (!abortError) return false
85
+
86
+ const { req, res, blockingAction } = abortError
87
+ if (!isBlocked(res)) {
88
+ block(req, res, web.root(req), null, blockingAction)
89
+ }
90
+
91
+ return true
92
+ }
93
+
85
94
  function enable (config) {
86
95
  ssrf.enable(config)
87
96
  sqli.enable(config)
97
+ lfi.enable(config)
88
98
 
89
99
  process.on('uncaughtExceptionMonitor', handleUncaughtExceptionMonitor)
100
+ expressMiddlewareError.subscribe(blockOnDatadogRaspAbortError)
90
101
  }
91
102
 
92
103
  function disable () {
93
104
  ssrf.disable()
94
105
  sqli.disable()
106
+ lfi.disable()
95
107
 
96
108
  process.off('uncaughtExceptionMonitor', handleUncaughtExceptionMonitor)
109
+ if (expressMiddlewareError.hasSubscribers) expressMiddlewareError.unsubscribe(blockOnDatadogRaspAbortError)
97
110
  }
98
111
 
99
112
  module.exports = {
100
113
  enable,
101
114
  disable,
102
- handleUncaughtExceptionMonitor // exported only for testing purpose
115
+ handleUncaughtExceptionMonitor, // exported only for testing purpose
116
+ blockOnDatadogRaspAbortError // exported only for testing purpose
103
117
  }
@@ -0,0 +1,112 @@
1
+ 'use strict'
2
+
3
+ const { fsOperationStart, incomingHttpRequestStart } = require('../channels')
4
+ const { storage } = require('../../../../datadog-core')
5
+ const { enable: enableFsPlugin, disable: disableFsPlugin, RASP_MODULE } = require('./fs-plugin')
6
+ const { FS_OPERATION_PATH } = require('../addresses')
7
+ const waf = require('../waf')
8
+ const { RULE_TYPES, handleResult } = require('./utils')
9
+ const { isAbsolute } = require('path')
10
+
11
+ let config
12
+ let enabled
13
+ let analyzeSubscribed
14
+
15
+ function enable (_config) {
16
+ config = _config
17
+
18
+ if (enabled) return
19
+
20
+ enabled = true
21
+
22
+ incomingHttpRequestStart.subscribe(onFirstReceivedRequest)
23
+ }
24
+
25
+ function disable () {
26
+ if (fsOperationStart.hasSubscribers) fsOperationStart.unsubscribe(analyzeLfi)
27
+ if (incomingHttpRequestStart.hasSubscribers) incomingHttpRequestStart.unsubscribe(onFirstReceivedRequest)
28
+
29
+ disableFsPlugin(RASP_MODULE)
30
+
31
+ enabled = false
32
+ analyzeSubscribed = false
33
+ }
34
+
35
+ function onFirstReceivedRequest () {
36
+ // nodejs unsubscribe during publish bug: https://github.com/nodejs/node/pull/55116
37
+ process.nextTick(() => {
38
+ incomingHttpRequestStart.unsubscribe(onFirstReceivedRequest)
39
+ })
40
+
41
+ enableFsPlugin(RASP_MODULE)
42
+
43
+ if (!analyzeSubscribed) {
44
+ fsOperationStart.subscribe(analyzeLfi)
45
+ analyzeSubscribed = true
46
+ }
47
+ }
48
+
49
+ function analyzeLfi (ctx) {
50
+ const store = storage.getStore()
51
+ if (!store) return
52
+
53
+ const { req, fs, res } = store
54
+ if (!req || !fs) return
55
+
56
+ getPaths(ctx, fs).forEach(path => {
57
+ const persistent = {
58
+ [FS_OPERATION_PATH]: path
59
+ }
60
+
61
+ const result = waf.run({ persistent }, req, RULE_TYPES.LFI)
62
+ handleResult(result, req, res, ctx.abortController, config)
63
+ })
64
+ }
65
+
66
+ function getPaths (ctx, fs) {
67
+ // these properties could have String, Buffer, URL, Integer or FileHandle types
68
+ const pathArguments = [
69
+ ctx.dest,
70
+ ctx.existingPath,
71
+ ctx.file,
72
+ ctx.newPath,
73
+ ctx.oldPath,
74
+ ctx.path,
75
+ ctx.prefix,
76
+ ctx.src,
77
+ ctx.target
78
+ ]
79
+
80
+ return pathArguments
81
+ .map(path => pathToStr(path))
82
+ .filter(path => shouldAnalyze(path, fs))
83
+ }
84
+
85
+ function pathToStr (path) {
86
+ if (!path) return
87
+
88
+ if (typeof path === 'string' ||
89
+ path instanceof String ||
90
+ path instanceof Buffer ||
91
+ path instanceof URL) {
92
+ return path.toString()
93
+ }
94
+ }
95
+
96
+ function shouldAnalyze (path, fs) {
97
+ if (!path) return
98
+
99
+ const notExcludedRootOp = !fs.opExcluded && fs.root
100
+ return notExcludedRootOp && (isAbsolute(path) || path.includes('../') || shouldAnalyzeURLFile(path, fs))
101
+ }
102
+
103
+ function shouldAnalyzeURLFile (path, fs) {
104
+ if (path.startsWith('file://')) {
105
+ return shouldAnalyze(path.substring(7), fs)
106
+ }
107
+ }
108
+
109
+ module.exports = {
110
+ enable,
111
+ disable
112
+ }
@@ -1,12 +1,18 @@
1
1
  'use strict'
2
2
 
3
- const { pgQueryStart, pgPoolQueryStart, wafRunFinished } = require('../channels')
3
+ const {
4
+ pgQueryStart,
5
+ pgPoolQueryStart,
6
+ wafRunFinished,
7
+ mysql2OuterQueryStart
8
+ } = require('../channels')
4
9
  const { storage } = require('../../../../datadog-core')
5
10
  const addresses = require('../addresses')
6
11
  const waf = require('../waf')
7
12
  const { RULE_TYPES, handleResult } = require('./utils')
8
13
 
9
14
  const DB_SYSTEM_POSTGRES = 'postgresql'
15
+ const DB_SYSTEM_MYSQL = 'mysql'
10
16
  const reqQueryMap = new WeakMap() // WeakMap<Request, Set<querytext>>
11
17
 
12
18
  let config
@@ -17,18 +23,32 @@ function enable (_config) {
17
23
  pgQueryStart.subscribe(analyzePgSqlInjection)
18
24
  pgPoolQueryStart.subscribe(analyzePgSqlInjection)
19
25
  wafRunFinished.subscribe(clearQuerySet)
26
+
27
+ mysql2OuterQueryStart.subscribe(analyzeMysql2SqlInjection)
20
28
  }
21
29
 
22
30
  function disable () {
23
31
  if (pgQueryStart.hasSubscribers) pgQueryStart.unsubscribe(analyzePgSqlInjection)
24
32
  if (pgPoolQueryStart.hasSubscribers) pgPoolQueryStart.unsubscribe(analyzePgSqlInjection)
25
33
  if (wafRunFinished.hasSubscribers) wafRunFinished.unsubscribe(clearQuerySet)
34
+ if (mysql2OuterQueryStart.hasSubscribers) mysql2OuterQueryStart.unsubscribe(analyzeMysql2SqlInjection)
35
+ }
36
+
37
+ function analyzeMysql2SqlInjection (ctx) {
38
+ const query = ctx.sql
39
+ if (!query) return
40
+
41
+ analyzeSqlInjection(query, DB_SYSTEM_MYSQL, ctx.abortController)
26
42
  }
27
43
 
28
44
  function analyzePgSqlInjection (ctx) {
29
45
  const query = ctx.query?.text
30
46
  if (!query) return
31
47
 
48
+ analyzeSqlInjection(query, DB_SYSTEM_POSTGRES, ctx.abortController)
49
+ }
50
+
51
+ function analyzeSqlInjection (query, dbSystem, abortController) {
32
52
  const store = storage.getStore()
33
53
  if (!store) return
34
54
 
@@ -39,7 +59,7 @@ function analyzePgSqlInjection (ctx) {
39
59
  let executedQueries = reqQueryMap.get(req)
40
60
  if (executedQueries?.has(query)) return
41
61
 
42
- // Do not waste time executing same query twice
62
+ // Do not waste time checking same query twice
43
63
  // This also will prevent double calls in pg.Pool internal queries
44
64
  if (!executedQueries) {
45
65
  executedQueries = new Set()
@@ -49,12 +69,12 @@ function analyzePgSqlInjection (ctx) {
49
69
 
50
70
  const persistent = {
51
71
  [addresses.DB_STATEMENT]: query,
52
- [addresses.DB_SYSTEM]: DB_SYSTEM_POSTGRES
72
+ [addresses.DB_SYSTEM]: dbSystem
53
73
  }
54
74
 
55
75
  const result = waf.run({ persistent }, req, RULE_TYPES.SQL_INJECTION)
56
76
 
57
- handleResult(result, req, res, ctx.abortController, config)
77
+ handleResult(result, req, res, abortController, config)
58
78
  }
59
79
 
60
80
  function hasInputAddress (payload) {
@@ -13,7 +13,8 @@ if (abortOnUncaughtException) {
13
13
 
14
14
  const RULE_TYPES = {
15
15
  SSRF: 'ssrf',
16
- SQL_INJECTION: 'sql_injection'
16
+ SQL_INJECTION: 'sql_injection',
17
+ LFI: 'lfi'
17
18
  }
18
19
 
19
20
  class DatadogRaspAbortError extends Error {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.13.0"
4
+ "rules_version": "1.13.1"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -6239,7 +6239,6 @@
6239
6239
  {
6240
6240
  "id": "rasp-930-100",
6241
6241
  "name": "Local file inclusion exploit",
6242
- "enabled": false,
6243
6242
  "tags": {
6244
6243
  "type": "lfi",
6245
6244
  "category": "vulnerability_trigger",
@@ -6287,8 +6286,7 @@
6287
6286
  },
6288
6287
  {
6289
6288
  "id": "rasp-932-100",
6290
- "name": "Shell injection exploit",
6291
- "enabled": false,
6289
+ "name": "Command injection exploit",
6292
6290
  "tags": {
6293
6291
  "type": "command_injection",
6294
6292
  "category": "vulnerability_trigger",
@@ -18,6 +18,10 @@ module.exports = {
18
18
  APM_TRACING_CUSTOM_TAGS: 1n << 15n,
19
19
  APM_TRACING_ENABLED: 1n << 19n,
20
20
  ASM_RASP_SQLI: 1n << 21n,
21
+ ASM_RASP_LFI: 1n << 22n,
21
22
  ASM_RASP_SSRF: 1n << 23n,
22
- APM_TRACING_SAMPLE_RULES: 1n << 29n
23
+ APM_TRACING_SAMPLE_RULES: 1n << 29n,
24
+ ASM_ENDPOINT_FINGERPRINT: 1n << 32n,
25
+ ASM_NETWORK_FINGERPRINT: 1n << 34n,
26
+ ASM_HEADER_FINGERPRINT: 1n << 35n
23
27
  }
@@ -75,10 +75,14 @@ function enableWafUpdate (appsecConfig) {
75
75
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_RULES, true)
76
76
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, true)
77
77
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, true)
78
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_ENDPOINT_FINGERPRINT, true)
79
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, true)
80
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, true)
78
81
 
79
82
  if (appsecConfig.rasp?.enabled) {
80
83
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, true)
81
84
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SSRF, true)
85
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_LFI, true)
82
86
  }
83
87
 
84
88
  // TODO: delete noop handlers and kPreUpdate and replace with batched handlers
@@ -103,9 +107,13 @@ function disableWafUpdate () {
103
107
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_RULES, false)
104
108
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, false)
105
109
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, false)
110
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_ENDPOINT_FINGERPRINT, false)
111
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, false)
112
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, false)
106
113
 
107
114
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, false)
108
115
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SSRF, false)
116
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_LFI, false)
109
117
 
110
118
  rc.removeProductHandler('ASM_DATA')
111
119
  rc.removeProductHandler('ASM_DD')
@@ -153,7 +153,11 @@ function reportAttack (attackData) {
153
153
  rootSpan.addTags(newTags)
154
154
  }
155
155
 
156
- function reportSchemas (derivatives) {
156
+ function isFingerprintDerivative (derivative) {
157
+ return derivative.startsWith('_dd.appsec.fp')
158
+ }
159
+
160
+ function reportDerivatives (derivatives) {
157
161
  if (!derivatives) return
158
162
 
159
163
  const req = storage.getStore()?.req
@@ -162,9 +166,12 @@ function reportSchemas (derivatives) {
162
166
  if (!rootSpan) return
163
167
 
164
168
  const tags = {}
165
- for (const [address, value] of Object.entries(derivatives)) {
166
- const gzippedValue = zlib.gzipSync(JSON.stringify(value))
167
- tags[address] = gzippedValue.toString('base64')
169
+ for (let [tag, value] of Object.entries(derivatives)) {
170
+ if (!isFingerprintDerivative(tag)) {
171
+ const gzippedValue = zlib.gzipSync(JSON.stringify(value))
172
+ value = gzippedValue.toString('base64')
173
+ }
174
+ tags[tag] = value
168
175
  }
169
176
 
170
177
  rootSpan.addTags(tags)
@@ -248,7 +255,7 @@ module.exports = {
248
255
  reportMetrics,
249
256
  reportAttack,
250
257
  reportWafUpdate: incrementWafUpdatesMetric,
251
- reportSchemas,
258
+ reportDerivatives,
252
259
  finishRequest,
253
260
  setRateLimit,
254
261
  mapHeaderAndTags
@@ -5,6 +5,7 @@ const { getRootSpan } = require('./utils')
5
5
  const { MANUAL_KEEP } = require('../../../../../ext/tags')
6
6
  const { setUserTags } = require('./set_user')
7
7
  const standalone = require('../standalone')
8
+ const waf = require('../waf')
8
9
 
9
10
  function trackUserLoginSuccessEvent (tracer, user, metadata) {
10
11
  // TODO: better user check here and in _setUser() ?
@@ -76,6 +77,10 @@ function trackEvent (eventName, fields, sdkMethodName, rootSpan, mode) {
76
77
  rootSpan.addTags(tags)
77
78
 
78
79
  standalone.sample(rootSpan)
80
+
81
+ if (['users.login.success', 'users.login.failure'].includes(eventName)) {
82
+ waf.run({ persistent: { [`server.business_logic.${eventName}`]: null } })
83
+ }
79
84
  }
80
85
 
81
86
  module.exports = {
@@ -93,7 +93,7 @@ class WAFContextWrapper {
93
93
  Reporter.reportAttack(JSON.stringify(result.events))
94
94
  }
95
95
 
96
- Reporter.reportSchemas(result.derivatives)
96
+ Reporter.reportDerivatives(result.derivatives)
97
97
 
98
98
  if (wafRunFinished.hasSubscribers) {
99
99
  wafRunFinished.publish({ payload })
@@ -12,19 +12,7 @@ const {
12
12
  TELEMETRY_KNOWN_TESTS_RESPONSE_BYTES
13
13
  } = require('../../ci-visibility/telemetry')
14
14
 
15
- function getNumTests (knownTests) {
16
- let totalNumTests = 0
17
-
18
- for (const testModule of Object.values(knownTests)) {
19
- for (const testSuite of Object.values(testModule)) {
20
- for (const testList of Object.values(testSuite)) {
21
- totalNumTests += testList.length
22
- }
23
- }
24
- }
25
-
26
- return totalNumTests
27
- }
15
+ const { getNumFromKnownTests } = require('../../plugins/util/test')
28
16
 
29
17
  function getKnownTests ({
30
18
  url,
@@ -102,7 +90,7 @@ function getKnownTests ({
102
90
  try {
103
91
  const { data: { attributes: { tests: knownTests } } } = JSON.parse(res)
104
92
 
105
- const numTests = getNumTests(knownTests)
93
+ const numTests = getNumFromKnownTests(knownTests)
106
94
 
107
95
  incrementCountMetric(TELEMETRY_KNOWN_TESTS_RESPONSE_TESTS, {}, numTests)
108
96
  distributionMetric(TELEMETRY_KNOWN_TESTS_RESPONSE_BYTES, {}, res.length)
@@ -0,0 +1,53 @@
1
+ const Plugin = require('../../plugins/plugin')
2
+ const log = require('../../log')
3
+
4
+ function getWinstonLogSubmissionParameters (config) {
5
+ const { site, service } = config
6
+
7
+ const defaultParameters = {
8
+ host: `http-intake.logs.${site}`,
9
+ path: `/api/v2/logs?ddsource=winston&service=${service}`,
10
+ ssl: true,
11
+ headers: {
12
+ 'DD-API-KEY': process.env.DD_API_KEY
13
+ }
14
+ }
15
+
16
+ if (!process.env.DD_AGENTLESS_LOG_SUBMISSION_URL) {
17
+ return defaultParameters
18
+ }
19
+
20
+ try {
21
+ const url = new URL(process.env.DD_AGENTLESS_LOG_SUBMISSION_URL)
22
+ return {
23
+ host: url.hostname,
24
+ port: url.port,
25
+ ssl: url.protocol === 'https:',
26
+ path: defaultParameters.path,
27
+ headers: defaultParameters.headers
28
+ }
29
+ } catch (e) {
30
+ log.error('Could not parse DD_AGENTLESS_LOG_SUBMISSION_URL')
31
+ return defaultParameters
32
+ }
33
+ }
34
+
35
+ class LogSubmissionPlugin extends Plugin {
36
+ static get id () {
37
+ return 'log-submission'
38
+ }
39
+
40
+ constructor (...args) {
41
+ super(...args)
42
+
43
+ this.addSub('ci:log-submission:winston:configure', (httpClass) => {
44
+ this.HttpClass = httpClass
45
+ })
46
+
47
+ this.addSub('ci:log-submission:winston:add-transport', (logger) => {
48
+ logger.add(new this.HttpClass(getWinstonLogSubmissionParameters(this.config)))
49
+ })
50
+ }
51
+ }
52
+
53
+ module.exports = LogSubmissionPlugin
@@ -464,6 +464,7 @@ class Config {
464
464
  this._setValue(defaults, 'appsec.wafTimeout', 5e3) // µs
465
465
  this._setValue(defaults, 'clientIpEnabled', false)
466
466
  this._setValue(defaults, 'clientIpHeader', null)
467
+ this._setValue(defaults, 'codeOriginForSpans.enabled', false)
467
468
  this._setValue(defaults, 'dbmPropagationMode', 'disabled')
468
469
  this._setValue(defaults, 'dogstatsd.hostname', '127.0.0.1')
469
470
  this._setValue(defaults, 'dogstatsd.port', '8125')
@@ -478,6 +479,7 @@ class Config {
478
479
  this._setValue(defaults, 'gitMetadataEnabled', true)
479
480
  this._setValue(defaults, 'headerTags', [])
480
481
  this._setValue(defaults, 'hostname', '127.0.0.1')
482
+ this._setValue(defaults, 'iast.cookieFilterPattern', '.{32,}')
481
483
  this._setValue(defaults, 'iast.deduplicationEnabled', true)
482
484
  this._setValue(defaults, 'iast.enabled', false)
483
485
  this._setValue(defaults, 'iast.maxConcurrentRequests', 2)
@@ -498,6 +500,7 @@ class Config {
498
500
  this._setValue(defaults, 'isIntelligentTestRunnerEnabled', false)
499
501
  this._setValue(defaults, 'isManualApiEnabled', false)
500
502
  this._setValue(defaults, 'ciVisibilityTestSessionName', '')
503
+ this._setValue(defaults, 'ciVisAgentlessLogSubmissionEnabled', false)
501
504
  this._setValue(defaults, 'logInjection', false)
502
505
  this._setValue(defaults, 'lookup', undefined)
503
506
  this._setValue(defaults, 'memcachedCommandEnabled', false)
@@ -571,6 +574,7 @@ class Config {
571
574
  DD_APPSEC_RASP_ENABLED,
572
575
  DD_APPSEC_TRACE_RATE_LIMIT,
573
576
  DD_APPSEC_WAF_TIMEOUT,
577
+ DD_CODE_ORIGIN_FOR_SPANS_ENABLED,
574
578
  DD_DATA_STREAMS_ENABLED,
575
579
  DD_DBM_PROPAGATION_MODE,
576
580
  DD_DOGSTATSD_HOSTNAME,
@@ -581,6 +585,7 @@ class Config {
581
585
  DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
582
586
  DD_EXPERIMENTAL_PROFILING_ENABLED,
583
587
  JEST_WORKER_ID,
588
+ DD_IAST_COOKIE_FILTER_PATTERN,
584
589
  DD_IAST_DEDUPLICATION_ENABLED,
585
590
  DD_IAST_ENABLED,
586
591
  DD_IAST_MAX_CONCURRENT_REQUESTS,
@@ -701,6 +706,7 @@ class Config {
701
706
  this._envUnprocessed['appsec.wafTimeout'] = DD_APPSEC_WAF_TIMEOUT
702
707
  this._setBoolean(env, 'clientIpEnabled', DD_TRACE_CLIENT_IP_ENABLED)
703
708
  this._setString(env, 'clientIpHeader', DD_TRACE_CLIENT_IP_HEADER)
709
+ this._setBoolean(env, 'codeOriginForSpans.enabled', DD_CODE_ORIGIN_FOR_SPANS_ENABLED)
704
710
  this._setString(env, 'dbmPropagationMode', DD_DBM_PROPAGATION_MODE)
705
711
  this._setString(env, 'dogstatsd.hostname', DD_DOGSTATSD_HOSTNAME)
706
712
  this._setString(env, 'dogstatsd.port', DD_DOGSTATSD_PORT)
@@ -716,6 +722,7 @@ class Config {
716
722
  this._setBoolean(env, 'gitMetadataEnabled', DD_TRACE_GIT_METADATA_ENABLED)
717
723
  this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
718
724
  this._setString(env, 'hostname', coalesce(DD_AGENT_HOST, DD_TRACE_AGENT_HOSTNAME))
725
+ this._setString(env, 'iast.cookieFilterPattern', DD_IAST_COOKIE_FILTER_PATTERN)
719
726
  this._setBoolean(env, 'iast.deduplicationEnabled', DD_IAST_DEDUPLICATION_ENABLED)
720
727
  this._setBoolean(env, 'iast.enabled', DD_IAST_ENABLED)
721
728
  this._setValue(env, 'iast.maxConcurrentRequests', maybeInt(DD_IAST_MAX_CONCURRENT_REQUESTS))
@@ -867,6 +874,7 @@ class Config {
867
874
  this._optsUnprocessed['appsec.wafTimeout'] = options.appsec.wafTimeout
868
875
  this._setBoolean(opts, 'clientIpEnabled', options.clientIpEnabled)
869
876
  this._setString(opts, 'clientIpHeader', options.clientIpHeader)
877
+ this._setBoolean(opts, 'codeOriginForSpans.enabled', options.codeOriginForSpans?.enabled)
870
878
  this._setString(opts, 'dbmPropagationMode', options.dbmPropagationMode)
871
879
  if (options.dogstatsd) {
872
880
  this._setString(opts, 'dogstatsd.hostname', options.dogstatsd.hostname)
@@ -884,6 +892,7 @@ class Config {
884
892
  this._optsUnprocessed.flushMinSpans = options.flushMinSpans
885
893
  this._setArray(opts, 'headerTags', options.headerTags)
886
894
  this._setString(opts, 'hostname', options.hostname)
895
+ this._setString(opts, 'iast.cookieFilterPattern', options.iast?.cookieFilterPattern)
887
896
  this._setBoolean(opts, 'iast.deduplicationEnabled', options.iast && options.iast.deduplicationEnabled)
888
897
  this._setBoolean(opts, 'iast.enabled',
889
898
  options.iast && (options.iast === true || options.iast.enabled === true))
@@ -1035,7 +1044,8 @@ class Config {
1035
1044
  DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED,
1036
1045
  DD_CIVISIBILITY_FLAKY_RETRY_ENABLED,
1037
1046
  DD_CIVISIBILITY_FLAKY_RETRY_COUNT,
1038
- DD_TEST_SESSION_NAME
1047
+ DD_TEST_SESSION_NAME,
1048
+ DD_AGENTLESS_LOG_SUBMISSION_ENABLED
1039
1049
  } = process.env
1040
1050
 
1041
1051
  if (DD_CIVISIBILITY_AGENTLESS_URL) {
@@ -1052,6 +1062,7 @@ class Config {
1052
1062
  this._setBoolean(calc, 'isIntelligentTestRunnerEnabled', isTrue(this._isCiVisibilityItrEnabled()))
1053
1063
  this._setBoolean(calc, 'isManualApiEnabled', !isFalse(this._isCiVisibilityManualApiEnabled()))
1054
1064
  this._setString(calc, 'ciVisibilityTestSessionName', DD_TEST_SESSION_NAME)
1065
+ this._setBoolean(calc, 'ciVisAgentlessLogSubmissionEnabled', isTrue(DD_AGENTLESS_LOG_SUBMISSION_ENABLED))
1055
1066
  }
1056
1067
  this._setString(calc, 'dogstatsd.hostname', this._getHostname())
1057
1068
  this._setBoolean(calc, 'isGitUploadEnabled',
@@ -4,13 +4,36 @@ const { Schema } = require('./schema')
4
4
 
5
5
  const maxDepth = 10
6
6
  const maxProperties = 1000
7
- const CACHE = new LRUCache({ max: 32 })
7
+ const CACHE = new LRUCache({ max: 256 })
8
8
 
9
9
  class SchemaBuilder {
10
10
  constructor (iterator) {
11
11
  this.schema = new OpenApiSchema()
12
12
  this.iterator = iterator
13
- this.proerties = 0
13
+ this.properties = 0
14
+ }
15
+
16
+ static getCache () {
17
+ return CACHE
18
+ }
19
+
20
+ static getSchemaDefinition (schema) {
21
+ const noNones = convertToJsonCompatible(schema)
22
+ const definition = jsonStringify(noNones)
23
+ const id = fnv64(Buffer.from(definition, 'utf-8')).toString()
24
+ return new Schema(definition, id)
25
+ }
26
+
27
+ static getSchema (schemaName, iterator, builder) {
28
+ if (!CACHE.has(schemaName)) {
29
+ CACHE.set(schemaName, (builder ?? new SchemaBuilder(iterator)).build())
30
+ }
31
+ return CACHE.get(schemaName)
32
+ }
33
+
34
+ build () {
35
+ this.iterator.iterateOverSchema(this)
36
+ return this.schema
14
37
  }
15
38
 
16
39
  addProperty (schemaName, fieldName, isArray, type, description, ref, format, enumValues) {
@@ -26,14 +49,6 @@ class SchemaBuilder {
26
49
  return true
27
50
  }
28
51
 
29
- build () {
30
- this.iterator.iterateOverSchema(this)
31
- const noNones = convertToJsonCompatible(this.schema)
32
- const definition = jsonStringify(noNones)
33
- const id = fnv64(Buffer.from(definition, 'utf-8')).toString()
34
- return new Schema(definition, id)
35
- }
36
-
37
52
  shouldExtractSchema (schemaName, depth) {
38
53
  if (depth > maxDepth) {
39
54
  return false
@@ -44,13 +59,6 @@ class SchemaBuilder {
44
59
  this.schema.components.schemas[schemaName] = new OpenApiSchema.SCHEMA()
45
60
  return true
46
61
  }
47
-
48
- static getSchema (schemaName, iterator) {
49
- if (!CACHE.has(schemaName)) {
50
- CACHE.set(schemaName, new SchemaBuilder(iterator).build())
51
- }
52
- return CACHE.get(schemaName)
53
- }
54
62
  }
55
63
 
56
64
  class OpenApiSchema {
@@ -7,6 +7,8 @@ const log = require('../../log')
7
7
  const config = module.exports = {
8
8
  runtimeId: parentConfig.tags['runtime-id'],
9
9
  service: parentConfig.service,
10
+ commitSHA: parentConfig.commitSHA,
11
+ repositoryUrl: parentConfig.repositoryUrl,
10
12
  parentThreadId
11
13
  }
12
14