dd-trace 6.7.0 → 6.9.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 (272) hide show
  1. package/ci/diagnose.js +27 -25
  2. package/ci/init.js +6 -6
  3. package/ci/runbook.md +114 -20
  4. package/ci/test-optimization-validation/approval-artifacts.js +36 -3
  5. package/ci/test-optimization-validation/approval.js +78 -22
  6. package/ci/test-optimization-validation/blocker-category.js +24 -0
  7. package/ci/test-optimization-validation/ci-discovery.js +23 -17
  8. package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
  9. package/ci/test-optimization-validation/ci-remediation.js +1 -1
  10. package/ci/test-optimization-validation/cli.js +280 -52
  11. package/ci/test-optimization-validation/command-blocker.js +159 -20
  12. package/ci/test-optimization-validation/command-output-policy.js +14 -8
  13. package/ci/test-optimization-validation/command-runner.js +9 -7
  14. package/ci/test-optimization-validation/environment.js +4 -2
  15. package/ci/test-optimization-validation/executable.js +15 -13
  16. package/ci/test-optimization-validation/execution-lock.js +70 -0
  17. package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
  18. package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
  19. package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
  20. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  21. package/ci/test-optimization-validation/generated-files.js +47 -37
  22. package/ci/test-optimization-validation/generated-test-contract.js +9 -7
  23. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  24. package/ci/test-optimization-validation/literal-glob.js +52 -0
  25. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  26. package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
  27. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  28. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  29. package/ci/test-optimization-validation/offline-output.js +6 -6
  30. package/ci/test-optimization-validation/package-check.js +94 -0
  31. package/ci/test-optimization-validation/plan-writer.js +183 -10
  32. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  33. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  34. package/ci/test-optimization-validation/redaction.js +18 -27
  35. package/ci/test-optimization-validation/report-writer.js +182 -48
  36. package/ci/test-optimization-validation/result-semantics.js +20 -3
  37. package/ci/test-optimization-validation/runner-command.js +41 -21
  38. package/ci/test-optimization-validation/runner-contract.js +79 -43
  39. package/ci/test-optimization-validation/safe-files.js +4 -4
  40. package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
  41. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  42. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  43. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  44. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  45. package/ci/test-optimization-validation/test-output.js +2 -1
  46. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  47. package/ci/vitest-no-worker-init-setup.mjs +377 -84
  48. package/index.d.ts +175 -14
  49. package/init.js +1 -17
  50. package/initialize.mjs +11 -0
  51. package/loader-hook.mjs +6 -4
  52. package/package.json +12 -4
  53. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  54. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  55. package/packages/datadog-esbuild/index.js +4 -2
  56. package/packages/datadog-esbuild/src/utils.js +17 -2
  57. package/packages/datadog-instrumentations/src/ai.js +61 -34
  58. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
  60. package/packages/datadog-instrumentations/src/cucumber.js +131 -51
  61. package/packages/datadog-instrumentations/src/dns.js +21 -2
  62. package/packages/datadog-instrumentations/src/electron.js +1 -0
  63. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  64. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  65. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  66. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  68. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  69. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
  76. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  77. package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
  78. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  79. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  80. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  81. package/packages/datadog-instrumentations/src/jest.js +986 -246
  82. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  83. package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
  84. package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
  85. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
  86. package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
  87. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  88. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  89. package/packages/datadog-instrumentations/src/next.js +155 -23
  90. package/packages/datadog-instrumentations/src/openai.js +14 -0
  91. package/packages/datadog-instrumentations/src/pg.js +180 -6
  92. package/packages/datadog-instrumentations/src/playwright.js +176 -81
  93. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  94. package/packages/datadog-instrumentations/src/promise.js +3 -3
  95. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  96. package/packages/datadog-instrumentations/src/router.js +195 -19
  97. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
  98. package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
  99. package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
  100. package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
  101. package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
  102. package/packages/datadog-instrumentations/src/when.js +3 -3
  103. package/packages/datadog-instrumentations/src/ws.js +5 -1
  104. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  105. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  106. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  107. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  108. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  109. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  110. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  111. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  112. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  113. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  114. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
  115. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  116. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
  117. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  118. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  119. package/packages/datadog-plugin-electron/src/net.js +10 -4
  120. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  121. package/packages/datadog-plugin-fs/src/index.js +0 -4
  122. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  123. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  124. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  125. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +3 -2
  127. package/packages/datadog-plugin-http2/src/client.js +1 -1
  128. package/packages/datadog-plugin-jest/src/index.js +3 -21
  129. package/packages/datadog-plugin-jest/src/util.js +4 -1
  130. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
  131. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  132. package/packages/datadog-plugin-mocha/src/index.js +342 -6
  133. package/packages/datadog-plugin-next/src/index.js +57 -9
  134. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  135. package/packages/datadog-plugin-pg/src/index.js +65 -1
  136. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  137. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  138. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  139. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  140. package/packages/datadog-plugin-undici/src/index.js +2 -1
  141. package/packages/datadog-plugin-vitest/src/index.js +179 -18
  142. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  143. package/packages/datadog-webpack/index.js +2 -2
  144. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  145. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  146. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  147. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  148. package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
  149. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  150. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  151. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  152. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  157. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
  158. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  159. package/packages/dd-trace/src/appsec/index.js +48 -476
  160. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  162. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  163. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  164. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  165. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
  166. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  169. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  170. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  171. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  172. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  173. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  174. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
  175. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  176. package/packages/dd-trace/src/config/defaults.js +14 -6
  177. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  178. package/packages/dd-trace/src/config/helper.js +2 -0
  179. package/packages/dd-trace/src/config/index.js +31 -5
  180. package/packages/dd-trace/src/config/parsers.js +19 -1
  181. package/packages/dd-trace/src/config/remote_config.js +1 -1
  182. package/packages/dd-trace/src/config/supported-configurations.json +13 -6
  183. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  184. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  185. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  186. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  187. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  188. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  189. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  190. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  191. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  192. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  193. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  194. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  195. package/packages/dd-trace/src/flare/index.js +2 -2
  196. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  197. package/packages/dd-trace/src/guardrails/log.js +1 -10
  198. package/packages/dd-trace/src/id.js +1 -1
  199. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  200. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  201. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  202. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  203. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  204. package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
  205. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  206. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  207. package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
  208. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  209. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  210. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  211. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  212. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  213. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  214. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  215. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  216. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  217. package/packages/dd-trace/src/llmobs/sdk.js +152 -78
  218. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  219. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  220. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  221. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  222. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  223. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  224. package/packages/dd-trace/src/log/channels.js +1 -9
  225. package/packages/dd-trace/src/log/levels.js +12 -0
  226. package/packages/dd-trace/src/noop/proxy.js +2 -2
  227. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  228. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  229. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  230. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  231. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  232. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  233. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  234. package/packages/dd-trace/src/opentracing/span.js +1 -1
  235. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  236. package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
  237. package/packages/dd-trace/src/plugins/index.js +2 -0
  238. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  239. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  240. package/packages/dd-trace/src/plugins/util/ci.js +13 -6
  241. package/packages/dd-trace/src/plugins/util/git.js +7 -5
  242. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
  243. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  244. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  245. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  246. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  247. package/packages/dd-trace/src/plugins/util/test.js +356 -86
  248. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  249. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  250. package/packages/dd-trace/src/plugins/util/web.js +24 -2
  251. package/packages/dd-trace/src/priority_sampler.js +6 -3
  252. package/packages/dd-trace/src/profiler.js +1 -1
  253. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  254. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  255. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  256. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  257. package/packages/dd-trace/src/proxy.js +1 -0
  258. package/packages/dd-trace/src/ritm.js +10 -20
  259. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  260. package/packages/dd-trace/src/sampling_rule.js +4 -2
  261. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  262. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  263. package/packages/dd-trace/src/startup-log.js +3 -0
  264. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  265. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  266. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  267. package/packages/dd-trace/src/util.js +16 -0
  268. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  269. package/vendor/dist/pprof-format/index.js +1 -1
  270. package/vendor/dist/source-map/index.js +1 -1
  271. package/version.js +10 -8
  272. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -21,7 +21,7 @@ let stackTraceMaxDepth
21
21
  let maxStackTraces
22
22
 
23
23
  function canAddVulnerability (vulnerability) {
24
- const hasRequiredFields = vulnerability?.evidence && vulnerability?.type && vulnerability?.location
24
+ const hasRequiredFields = vulnerability?.evidence && vulnerability.type && vulnerability.location
25
25
  if (!hasRequiredFields) return false
26
26
 
27
27
  const isDuplicated = deduplicationEnabled && isDuplicatedVulnerability(vulnerability)
@@ -64,7 +64,7 @@ function addVulnerability (iastContext, vulnerability, callSiteFrames) {
64
64
  }
65
65
 
66
66
  if (iastContext?.rootSpan) {
67
- iastContext[VULNERABILITIES_KEY] = iastContext[VULNERABILITIES_KEY] || []
67
+ iastContext[VULNERABILITIES_KEY] ||= []
68
68
  iastContext[VULNERABILITIES_KEY].push(vulnerability)
69
69
  } else {
70
70
  sendVulnerabilities([vulnerability], span)
@@ -1,11 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const log = require('../log')
4
- const web = require('../plugins/util/web')
5
- const { extractIp } = require('../plugins/util/ip_extractor')
6
- const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
7
4
  const { IS_SERVERLESS } = require('../serverless')
8
- const { isEmpty } = require('../util')
9
5
  const RuleManager = require('./rule_manager')
10
6
  const appsecRemoteConfig = require('./remote_config')
11
7
  const {
@@ -37,24 +33,52 @@ const {
37
33
  stripePaymentIntentCreate,
38
34
  stripeConstructEvent,
39
35
  } = require('./channels')
40
- const waf = require('./waf')
41
- const addresses = require('./addresses')
42
36
  const Reporter = require('./reporter')
43
37
  const appsecTelemetry = require('./telemetry')
44
38
  const apiSecurity = require('./api_security')
45
- const { isBlocked, block, callBlockDelegation, setTemplates, getBlockingAction } = require('./blocking')
46
- const { getActiveRequest } = require('./store')
39
+ const { setTemplates } = require('./blocking')
47
40
  const UserTracking = require('./user_tracking')
48
41
  const graphql = require('./graphql')
49
42
  const lambda = require('./lambda')
50
43
  const rasp = require('./rasp')
51
-
52
- const responseAnalyzedSet = new WeakSet()
53
- const storedResponseHeaders = new WeakMap()
54
- const storedBodies = new WeakMap()
44
+ const httpRequest = require('./handlers/http-request')
45
+ const httpResponse = require('./handlers/http-response')
46
+ const auth = require('./handlers/auth')
47
+ const payments = require('./handlers/payments')
55
48
 
56
49
  let isEnabled = false
57
- let config
50
+
51
+ // Single source of truth for what enable() subscribes and disable() unsubscribes,
52
+ // so the two can't drift apart.
53
+ const channelHandlers = [
54
+ [bodyParser, httpRequest.onRequestBodyParsed],
55
+ [multerParser, httpRequest.onRequestBodyParsed],
56
+ [cookieParser, httpRequest.onRequestCookieParser],
57
+ [incomingHttpRequestStart, httpRequest.incomingHttpStartTranslator],
58
+ [incomingHttpRequestEnd, httpRequest.incomingHttpEndTranslator],
59
+ [passportVerify, auth.onPassportVerify],
60
+ [passportUser, auth.onPassportDeserializeUser],
61
+ [expressSession, auth.onExpressSession],
62
+ [queryParser, httpRequest.onRequestQueryParsed],
63
+ [nextBodyParsed, httpRequest.onRequestBodyParsed],
64
+ [nextQueryParsed, httpRequest.onRequestQueryParsed],
65
+ [expressProcessParams, httpRequest.onRequestProcessParams],
66
+ [fastifyBodyParser, httpRequest.onRequestBodyParsed],
67
+ [fastifyQueryParams, httpRequest.onRequestQueryParsed],
68
+ [fastifyCookieParser, httpRequest.onRequestCookieParser],
69
+ [fastifyPathParams, httpRequest.onRequestProcessParams],
70
+ [routerParam, httpRequest.onRequestProcessParams],
71
+ [responseBody, httpResponse.onResponseBody],
72
+ [fastifyResponseChannel, httpResponse.onResponseBody],
73
+ [responseWriteHead, httpResponse.onResponseWriteHead],
74
+ [responseSetHeader, httpResponse.onResponseOperation],
75
+ [informationalResponse, httpResponse.onResponseOperation],
76
+ [stripeCheckoutSessionCreate, payments.onStripeCheckoutSessionCreate],
77
+ [stripePaymentIntentCreate, payments.onStripePaymentIntentCreate],
78
+ [stripeConstructEvent, payments.onStripeConstructEvent],
79
+ [lambdaStartInvocation, lambda.onLambdaStartInvocation],
80
+ [lambdaEndInvocation, lambda.onLambdaEndInvocation],
81
+ ]
58
82
 
59
83
  function enable (_config) {
60
84
  if (isEnabled) return
@@ -79,36 +103,13 @@ function enable (_config) {
79
103
 
80
104
  UserTracking.setCollectionMode(_config.appsec.eventTracking.mode, false)
81
105
 
82
- bodyParser.subscribe(onRequestBodyParsed)
83
- multerParser.subscribe(onRequestBodyParsed)
84
- cookieParser.subscribe(onRequestCookieParser)
85
- incomingHttpRequestStart.subscribe(incomingHttpStartTranslator)
86
- incomingHttpRequestEnd.subscribe(incomingHttpEndTranslator)
87
- passportVerify.subscribe(onPassportVerify) // possible optimization: only subscribe if collection mode is enabled
88
- passportUser.subscribe(onPassportDeserializeUser)
89
- expressSession.subscribe(onExpressSession)
90
- queryParser.subscribe(onRequestQueryParsed)
91
- nextBodyParsed.subscribe(onRequestBodyParsed)
92
- nextQueryParsed.subscribe(onRequestQueryParsed)
93
- expressProcessParams.subscribe(onRequestProcessParams)
94
- fastifyBodyParser.subscribe(onRequestBodyParsed)
95
- fastifyQueryParams.subscribe(onRequestQueryParsed)
96
- fastifyCookieParser.subscribe(onRequestCookieParser)
97
- fastifyPathParams.subscribe(onRequestProcessParams)
98
- routerParam.subscribe(onRequestProcessParams)
99
- responseBody.subscribe(onResponseBody)
100
- fastifyResponseChannel.subscribe(onResponseBody)
101
- responseWriteHead.subscribe(onResponseWriteHead)
102
- responseSetHeader.subscribe(onResponseOperation)
103
- informationalResponse.subscribe(onResponseOperation)
104
- stripeCheckoutSessionCreate.subscribe(onStripeCheckoutSessionCreate)
105
- stripePaymentIntentCreate.subscribe(onStripePaymentIntentCreate)
106
- stripeConstructEvent.subscribe(onStripeConstructEvent)
107
- lambdaStartInvocation.subscribe(lambda.onLambdaStartInvocation)
108
- lambdaEndInvocation.subscribe(lambda.onLambdaEndInvocation)
106
+ httpRequest.setConfig(_config)
107
+
108
+ for (const [channel, handler] of channelHandlers) {
109
+ channel.subscribe(handler)
110
+ }
109
111
 
110
112
  isEnabled = true
111
- config = _config
112
113
  } catch (err) {
113
114
  if (IS_SERVERLESS) {
114
115
  log.debug('[ASM] Serverless mode: suppressing error log, calling disable()')
@@ -120,403 +121,8 @@ function enable (_config) {
120
121
  }
121
122
  }
122
123
 
123
- const analyzedBodies = new WeakSet()
124
-
125
- function onRequestBodyParsed ({ req, res, body, abortController }) {
126
- if (body === undefined || body === null) return
127
-
128
- if (!req) {
129
- req = getActiveRequest()
130
- }
131
-
132
- const rootSpan = web.root(req)
133
- if (!rootSpan) return
134
-
135
- if (!req.body) {
136
- // do not store body if it is in req.body
137
- storedBodies.set(req, body)
138
- }
139
-
140
- if (typeof body === 'object') {
141
- if (isEmpty(body)) return
142
- analyzedBodies.add(body)
143
- }
144
-
145
- const results = waf.run({
146
- persistent: {
147
- [addresses.HTTP_INCOMING_BODY]: body,
148
- },
149
- }, req)
150
-
151
- handleResults(results?.actions, req, res, rootSpan, abortController)
152
- }
153
-
154
- const analyzedCookies = new WeakSet()
155
-
156
- function onRequestCookieParser ({ req, res, abortController, cookies }) {
157
- if (!cookies || typeof cookies !== 'object') return
158
-
159
- const rootSpan = web.root(req)
160
- if (!rootSpan) return
161
-
162
- if (isEmpty(cookies)) return
163
- analyzedCookies.add(cookies)
164
-
165
- const results = waf.run({
166
- persistent: {
167
- [addresses.HTTP_INCOMING_COOKIES]: cookies,
168
- },
169
- }, req)
170
-
171
- handleResults(results?.actions, req, res, rootSpan, abortController)
172
- }
173
-
174
- function incomingHttpStartTranslator ({ req, res, abortController }) {
175
- const rootSpan = web.root(req)
176
- if (!rootSpan) return
177
-
178
- const clientIp = extractIp(config, req)
179
-
180
- rootSpan.addTags({
181
- '_dd.appsec.enabled': 1,
182
- '_dd.runtime_family': 'nodejs',
183
- [HTTP_CLIENT_IP]: clientIp,
184
- })
185
-
186
- if (config.inferredProxyServicesEnabled) {
187
- const context = web.getContext(req)
188
- if (context?.inferredProxySpan) {
189
- context.inferredProxySpan.setTag('_dd.appsec.enabled', 1)
190
- }
191
- }
192
-
193
- const persistent = {
194
- [addresses.HTTP_INCOMING_URL]: req.url,
195
- [addresses.HTTP_INCOMING_HEADERS]: copyHeadersOmitting(req.headers, 'cookie'),
196
- [addresses.HTTP_INCOMING_METHOD]: req.method,
197
- }
198
-
199
- if (clientIp) {
200
- persistent[addresses.HTTP_CLIENT_IP] = clientIp
201
- }
202
-
203
- const results = waf.run({ persistent }, req)
204
-
205
- handleResults(results?.actions, req, res, rootSpan, abortController)
206
- }
207
-
208
- function incomingHttpEndTranslator ({ req, res }) {
209
- const persistent = {}
210
-
211
- // we need to keep this to support other body parsers
212
- if (req.body !== undefined && req.body !== null) {
213
- if (typeof req.body === 'object') {
214
- if (!isEmpty(req.body) && !analyzedBodies.has(req.body)) {
215
- persistent[addresses.HTTP_INCOMING_BODY] = req.body
216
- }
217
- } else {
218
- persistent[addresses.HTTP_INCOMING_BODY] = req.body
219
- }
220
- }
221
-
222
- // we need to keep this to support other cookie parsers
223
- if (
224
- req.cookies !== null &&
225
- typeof req.cookies === 'object' &&
226
- !isEmpty(req.cookies) &&
227
- !analyzedCookies.has(req.cookies)
228
- ) {
229
- persistent[addresses.HTTP_INCOMING_COOKIES] = req.cookies
230
- }
231
-
232
- // we need to keep this to support nextjs
233
- const query = req.query
234
- if (
235
- query !== null &&
236
- typeof query === 'object' &&
237
- !isEmpty(query)
238
- ) {
239
- persistent[addresses.HTTP_INCOMING_QUERY] = query
240
- }
241
-
242
- // This hook runs before span finish, so ensure route/endpoint tags are available before API Security sampling runs.
243
- web.setRouteOrEndpointTag(req)
244
-
245
- const apiSecSamplingDecision = apiSecurity.sampleRequest(req, res, true)
246
- if (apiSecSamplingDecision === apiSecurity.SamplingDecision.SAMPLE) {
247
- persistent[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
248
- }
249
-
250
- let wafResult
251
- if (!isEmpty(persistent)) {
252
- wafResult = waf.run({ persistent }, req)
253
- }
254
-
255
- apiSecurity.reportRequest(req, apiSecSamplingDecision, wafResult)
256
-
257
- waf.disposeContext(req)
258
-
259
- const storedHeaders = storedResponseHeaders.get(req) || {}
260
-
261
- const body = req.body || storedBodies.get(req)
262
- Reporter.finishRequest(req, res, storedHeaders, body)
263
-
264
- if (storedHeaders) {
265
- storedResponseHeaders.delete(req)
266
- }
267
- storedBodies.delete(req)
268
- }
269
-
270
- function onPassportVerify ({ framework, login, user, success, abortController }) {
271
- const req = getActiveRequest()
272
- const rootSpan = req && web.root(req)
273
-
274
- if (!rootSpan) {
275
- log.warn('[ASM] No rootSpan found in onPassportVerify')
276
- return
277
- }
278
-
279
- const results = UserTracking.trackLogin(framework, login, user, success, rootSpan)
280
-
281
- handleResults(results?.actions, req, web.getContext(req)?.res, rootSpan, abortController)
282
- }
283
-
284
- function onPassportDeserializeUser ({ user, abortController }) {
285
- const req = getActiveRequest()
286
- const rootSpan = req && web.root(req)
287
-
288
- if (!rootSpan) {
289
- log.warn('[ASM] No rootSpan found in onPassportDeserializeUser')
290
- return
291
- }
292
-
293
- const results = UserTracking.trackUser(user, rootSpan)
294
-
295
- handleResults(results?.actions, req, web.getContext(req)?.res, rootSpan, abortController)
296
- }
297
-
298
- function onExpressSession ({ req, res, sessionId, abortController }) {
299
- const rootSpan = web.root(req)
300
- if (!rootSpan) {
301
- log.warn('[ASM] No rootSpan found in onExpressSession')
302
- return
303
- }
304
-
305
- const isSdkCalled = rootSpan.context().getTag('usr.session_id')
306
- if (isSdkCalled) return
307
-
308
- const results = waf.run({
309
- persistent: {
310
- [addresses.USER_SESSION_ID]: sessionId,
311
- },
312
- }, req)
313
-
314
- handleResults(results?.actions, req, res, rootSpan, abortController)
315
- }
316
-
317
- function onRequestQueryParsed ({ req, res, query, abortController }) {
318
- if (!query || typeof query !== 'object') return
319
-
320
- if (!req) {
321
- req = getActiveRequest()
322
- }
323
-
324
- const rootSpan = web.root(req)
325
- if (!rootSpan) return
326
-
327
- if (isEmpty(query)) return
328
-
329
- const results = waf.run({
330
- persistent: {
331
- [addresses.HTTP_INCOMING_QUERY]: query,
332
- },
333
- }, req)
334
-
335
- handleResults(results?.actions, req, res, rootSpan, abortController)
336
- }
337
-
338
- function onRequestProcessParams ({ req, res, abortController, params }) {
339
- const rootSpan = web.root(req)
340
- if (!rootSpan) return
341
-
342
- if (!params || typeof params !== 'object' || isEmpty(params)) return
343
-
344
- const results = waf.run({
345
- persistent: {
346
- [addresses.HTTP_INCOMING_PARAMS]: params,
347
- },
348
- }, req)
349
-
350
- handleResults(results?.actions, req, res, rootSpan, abortController)
351
- }
352
-
353
- function onResponseBody ({ req, res, body }) {
354
- if (!body || typeof body !== 'object') return
355
- if (apiSecurity.sampleRequest(req, res) !== apiSecurity.SamplingDecision.SAMPLE) return
356
-
357
- // we don't support blocking at this point, so no results needed
358
- waf.run({
359
- persistent: {
360
- [addresses.HTTP_INCOMING_RESPONSE_BODY]: body,
361
- },
362
- }, req)
363
- }
364
-
365
- function onResponseWriteHead ({ req, res, abortController, statusCode, responseHeaders }) {
366
- // Normalize header names to lowercase so downstream consumers see the same shape
367
- // regardless of how the caller wrote them.
368
- const normalizedResponseHeaders = {}
369
- for (const [key, value] of Object.entries(responseHeaders)) {
370
- normalizedResponseHeaders[key.toLowerCase()] = value
371
- }
372
-
373
- if (!isEmpty(normalizedResponseHeaders)) {
374
- storedResponseHeaders.set(req, normalizedResponseHeaders)
375
- }
376
-
377
- // TODO: do not call waf if inside block()
378
- // if (isBlocking()) {
379
- // return
380
- // }
381
-
382
- // avoid "write after end" error
383
- if (isBlocked(res) || callBlockDelegation(res)) {
384
- abortController?.abort()
385
- return
386
- }
387
-
388
- // avoid double waf call
389
- if (responseAnalyzedSet.has(res)) {
390
- return
391
- }
392
-
393
- const rootSpan = web.root(req)
394
- if (!rootSpan) return
395
-
396
- const results = waf.run({
397
- persistent: {
398
- [addresses.HTTP_INCOMING_RESPONSE_CODE]: String(statusCode),
399
- [addresses.HTTP_INCOMING_RESPONSE_HEADERS]: copyHeadersOmitting(normalizedResponseHeaders, 'set-cookie'),
400
- },
401
- }, req)
402
-
403
- responseAnalyzedSet.add(res)
404
-
405
- handleResults(results?.actions, req, res, rootSpan, abortController)
406
- }
407
-
408
- function onResponseOperation ({ res, abortController }) {
409
- if (isBlocked(res)) {
410
- abortController?.abort()
411
- }
412
- }
413
-
414
- function onStripeCheckoutSessionCreate (payload) {
415
- if (payload?.mode !== 'payment') return
416
-
417
- waf.run({
418
- persistent: {
419
- [addresses.PAYMENT_CREATION]: {
420
- integration: 'stripe',
421
- id: payload.id,
422
- amount_total: payload.amount_total,
423
- client_reference_id: payload.client_reference_id,
424
- currency: payload.currency,
425
- 'discounts.coupon': payload.discounts?.[0]?.coupon,
426
- 'discounts.promotion_code': payload.discounts?.[0]?.promotion_code,
427
- livemode: payload.livemode,
428
- 'total_details.amount_discount': payload.total_details?.amount_discount,
429
- 'total_details.amount_shipping': payload.total_details?.amount_shipping,
430
- },
431
- },
432
- })
433
- }
434
-
435
- function onStripePaymentIntentCreate (payload) {
436
- if (payload === null || typeof payload !== 'object') return
437
-
438
- waf.run({
439
- persistent: {
440
- [addresses.PAYMENT_CREATION]: {
441
- integration: 'stripe',
442
- id: payload.id,
443
- amount: payload.amount,
444
- currency: payload.currency,
445
- livemode: payload.livemode,
446
- payment_method: payload.payment_method,
447
- },
448
- },
449
- })
450
- }
451
-
452
- function onStripeConstructEvent (payload) {
453
- const object = payload?.data?.object
454
- if (object === null || typeof object !== 'object') return
455
-
456
- let persistent
457
-
458
- switch (payload.type) {
459
- case 'payment_intent.succeeded':
460
- persistent = {
461
- [addresses.PAYMENT_SUCCESS]: {
462
- integration: 'stripe',
463
- id: object.id,
464
- amount: object.amount,
465
- currency: object.currency,
466
- livemode: object.livemode,
467
- payment_method: object.payment_method,
468
- },
469
- }
470
- break
471
-
472
- case 'payment_intent.payment_failed':
473
- persistent = {
474
- [addresses.PAYMENT_FAILURE]: {
475
- integration: 'stripe',
476
- id: object.id,
477
- amount: object.amount,
478
- currency: object.currency,
479
- 'last_payment_error.code': object.last_payment_error?.code,
480
- 'last_payment_error.decline_code': object.last_payment_error?.decline_code,
481
- 'last_payment_error.payment_method.id': object.last_payment_error?.payment_method?.id,
482
- 'last_payment_error.payment_method.type': object.last_payment_error?.payment_method?.type,
483
- livemode: object.livemode,
484
- },
485
- }
486
- break
487
-
488
- case 'payment_intent.canceled':
489
- persistent = {
490
- [addresses.PAYMENT_CANCELLATION]: {
491
- integration: 'stripe',
492
- id: object.id,
493
- amount: object.amount,
494
- cancellation_reason: object.cancellation_reason,
495
- currency: object.currency,
496
- livemode: object.livemode,
497
- },
498
- }
499
- break
500
-
501
- default:
502
- return
503
- }
504
-
505
- waf.run({ persistent })
506
- }
507
-
508
- function handleResults (actions, req, res, rootSpan, abortController) {
509
- if (!actions || !req || !res || !rootSpan || !abortController) return
510
-
511
- const blockingAction = getBlockingAction(actions)
512
- if (blockingAction) {
513
- block(req, res, rootSpan, abortController, blockingAction)
514
- }
515
- }
516
-
517
124
  function disable () {
518
125
  isEnabled = false
519
- config = null
520
126
 
521
127
  RuleManager.clearAllRules()
522
128
 
@@ -528,51 +134,17 @@ function disable () {
528
134
 
529
135
  apiSecurity.disable()
530
136
 
531
- // Channel#unsubscribe() is undefined for non active channels
532
- if (bodyParser.hasSubscribers) bodyParser.unsubscribe(onRequestBodyParsed)
533
- if (multerParser.hasSubscribers) multerParser.unsubscribe(onRequestBodyParsed)
534
- if (cookieParser.hasSubscribers) cookieParser.unsubscribe(onRequestCookieParser)
535
- if (incomingHttpRequestStart.hasSubscribers) incomingHttpRequestStart.unsubscribe(incomingHttpStartTranslator)
536
- if (incomingHttpRequestEnd.hasSubscribers) incomingHttpRequestEnd.unsubscribe(incomingHttpEndTranslator)
537
- if (passportVerify.hasSubscribers) passportVerify.unsubscribe(onPassportVerify)
538
- if (passportUser.hasSubscribers) passportUser.unsubscribe(onPassportDeserializeUser)
539
- if (expressSession.hasSubscribers) expressSession.unsubscribe(onExpressSession)
540
- if (queryParser.hasSubscribers) queryParser.unsubscribe(onRequestQueryParsed)
541
- if (nextBodyParsed.hasSubscribers) nextBodyParsed.unsubscribe(onRequestBodyParsed)
542
- if (nextQueryParsed.hasSubscribers) nextQueryParsed.unsubscribe(onRequestQueryParsed)
543
- if (expressProcessParams.hasSubscribers) expressProcessParams.unsubscribe(onRequestProcessParams)
544
- if (fastifyBodyParser.hasSubscribers) fastifyBodyParser.unsubscribe(onRequestBodyParsed)
545
- if (fastifyQueryParams.hasSubscribers) fastifyQueryParams.unsubscribe(onRequestQueryParsed)
546
- if (fastifyCookieParser.hasSubscribers) fastifyCookieParser.unsubscribe(onRequestCookieParser)
547
- if (fastifyPathParams.hasSubscribers) fastifyPathParams.unsubscribe(onRequestProcessParams)
548
- if (routerParam.hasSubscribers) routerParam.unsubscribe(onRequestProcessParams)
549
- if (responseBody.hasSubscribers) responseBody.unsubscribe(onResponseBody)
550
- if (fastifyResponseChannel.hasSubscribers) fastifyResponseChannel.unsubscribe(onResponseBody)
551
- if (responseWriteHead.hasSubscribers) responseWriteHead.unsubscribe(onResponseWriteHead)
552
- if (responseSetHeader.hasSubscribers) responseSetHeader.unsubscribe(onResponseOperation)
553
- if (informationalResponse.hasSubscribers) informationalResponse.unsubscribe(onResponseOperation)
554
- if (stripeCheckoutSessionCreate.hasSubscribers) stripeCheckoutSessionCreate.unsubscribe(onStripeCheckoutSessionCreate)
555
- if (stripePaymentIntentCreate.hasSubscribers) stripePaymentIntentCreate.unsubscribe(onStripePaymentIntentCreate)
556
- if (stripeConstructEvent.hasSubscribers) stripeConstructEvent.unsubscribe(onStripeConstructEvent)
557
- if (lambdaStartInvocation.hasSubscribers) lambdaStartInvocation.unsubscribe(lambda.onLambdaStartInvocation)
558
- if (lambdaEndInvocation.hasSubscribers) lambdaEndInvocation.unsubscribe(lambda.onLambdaEndInvocation)
559
- }
137
+ httpRequest.setConfig(undefined)
560
138
 
561
- /**
562
- * @param {Record<string, unknown>} src
563
- * @param {string} omit
564
- */
565
- function copyHeadersOmitting (src, omit) {
566
- const filtered = {}
567
- for (const key of Object.keys(src)) {
568
- if (key !== omit) filtered[key] = src[key]
139
+ // Channel#unsubscribe() is undefined for non active channels
140
+ for (const [channel, handler] of channelHandlers) {
141
+ if (channel.hasSubscribers) channel.unsubscribe(handler)
569
142
  }
570
- return filtered
571
143
  }
572
144
 
573
145
  module.exports = {
574
146
  enable,
575
147
  disable,
576
- incomingHttpStartTranslator,
577
- incomingHttpEndTranslator,
148
+ incomingHttpStartTranslator: httpRequest.incomingHttpStartTranslator,
149
+ incomingHttpEndTranslator: httpRequest.incomingHttpEndTranslator,
578
150
  }
@@ -11,6 +11,10 @@ const { getRootSpan } = require('./utils')
11
11
 
12
12
  /**
13
13
  * @deprecated in favor of trackUserLoginSuccessV2
14
+ * @param {import('../../tracer')} tracer
15
+ * @param {import('../../../../../index').User} user
16
+ * @param {Record<string, string>} [metadata]
17
+ * @returns {void}
14
18
  */
15
19
  function trackUserLoginSuccessEvent (tracer, user, metadata) {
16
20
  // TODO: better user check here and in _setUser() ?
@@ -40,6 +44,11 @@ function trackUserLoginSuccessEvent (tracer, user, metadata) {
40
44
 
41
45
  /**
42
46
  * @deprecated in favor of trackUserLoginFailureV2
47
+ * @param {import('../../tracer')} tracer
48
+ * @param {string} userId
49
+ * @param {boolean} exists
50
+ * @param {Record<string, string>} [metadata]
51
+ * @returns {void}
43
52
  */
44
53
  function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
45
54
  if (!userId || typeof userId !== 'string') {
@@ -160,7 +169,7 @@ function flattenFields (fields, depth = 0) {
160
169
 
161
170
  if (value && typeof value === 'object') {
162
171
  const { result: flatValue, truncated: inheritTruncated } = flattenFields(value, depth + 1)
163
- truncated = truncated || inheritTruncated
172
+ truncated ||= inheritTruncated
164
173
 
165
174
  if (flatValue) {
166
175
  for (const flatKey of Object.keys(flatValue)) {
@@ -39,7 +39,7 @@ class WAFManager {
39
39
  const { obfuscatorKeyRegex, obfuscatorValueRegex } = this.config
40
40
  return new DDWAF(rules, WAFManager.defaultWafConfigPath, { obfuscatorKeyRegex, obfuscatorValueRegex })
41
41
  } catch (err) {
42
- this.ddwafVersion = this.ddwafVersion || 'unknown'
42
+ this.ddwafVersion ||= 'unknown'
43
43
  Reporter.reportWafInit(this.ddwafVersion, 'unknown')
44
44
 
45
45
  log.error('[ASM] AppSec could not load native package. In-app WAF features will not be available.', err)