dd-trace 4.51.1 → 4.53.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 (172) hide show
  1. package/LICENSE-3rdparty.csv +8 -2
  2. package/ci/init.js +16 -0
  3. package/index.d.ts +31 -13
  4. package/init.js +4 -66
  5. package/initialize.mjs +13 -10
  6. package/loader-hook.mjs +4 -0
  7. package/package.json +16 -11
  8. package/packages/datadog-core/src/storage.js +39 -2
  9. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  10. package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
  11. package/packages/datadog-instrumentations/src/cucumber.js +29 -3
  12. package/packages/datadog-instrumentations/src/express.js +38 -4
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +3 -3
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -1
  15. package/packages/datadog-instrumentations/src/helpers/register.js +3 -4
  16. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  17. package/packages/datadog-instrumentations/src/jest.js +27 -8
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  19. package/packages/datadog-instrumentations/src/mysql2.js +13 -8
  20. package/packages/datadog-instrumentations/src/next.js +7 -4
  21. package/packages/datadog-instrumentations/src/passport-http.js +2 -14
  22. package/packages/datadog-instrumentations/src/passport-local.js +2 -14
  23. package/packages/datadog-instrumentations/src/passport-utils.js +43 -19
  24. package/packages/datadog-instrumentations/src/pg.js +6 -6
  25. package/packages/datadog-instrumentations/src/playwright.js +17 -4
  26. package/packages/datadog-instrumentations/src/router.js +97 -1
  27. package/packages/datadog-instrumentations/src/sequelize.js +9 -4
  28. package/packages/datadog-instrumentations/src/url.js +4 -0
  29. package/packages/datadog-instrumentations/src/vitest.js +27 -2
  30. package/packages/datadog-plugin-avsc/src/schema_iterator.js +8 -3
  31. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +154 -0
  32. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  33. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  34. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  36. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  37. package/packages/datadog-plugin-aws-sdk/src/util.js +92 -0
  38. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  39. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
  40. package/packages/datadog-plugin-cucumber/src/index.js +39 -4
  41. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +3 -3
  42. package/packages/datadog-plugin-grpc/src/client.js +2 -2
  43. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  44. package/packages/datadog-plugin-jest/src/index.js +39 -4
  45. package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +1 -1
  46. package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +1 -1
  47. package/packages/datadog-plugin-mocha/src/index.js +36 -2
  48. package/packages/datadog-plugin-oracledb/src/index.js +1 -1
  49. package/packages/datadog-plugin-vitest/src/index.js +34 -2
  50. package/packages/datadog-shimmer/src/shimmer.js +8 -4
  51. package/packages/dd-trace/src/appsec/addresses.js +3 -0
  52. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  53. package/packages/dd-trace/src/appsec/blocked_templates.js +1 -1
  54. package/packages/dd-trace/src/appsec/blocking.js +1 -1
  55. package/packages/dd-trace/src/appsec/channels.js +1 -0
  56. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +4 -0
  57. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +2 -2
  58. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  59. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +1 -1
  60. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +1 -1
  61. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +10 -3
  62. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +4 -0
  63. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +4 -0
  64. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +8 -21
  65. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
  66. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +2 -2
  67. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +64 -3
  68. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -8
  69. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +7 -11
  71. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +2 -3
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +2 -2
  73. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +2 -2
  74. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +2 -2
  75. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
  76. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -3
  77. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
  78. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  79. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +32 -37
  80. package/packages/dd-trace/src/appsec/index.js +18 -13
  81. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +2 -2
  82. package/packages/dd-trace/src/appsec/rasp/utils.js +1 -1
  83. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
  84. package/packages/dd-trace/src/appsec/remote_config/index.js +25 -1
  85. package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
  86. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  87. package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
  88. package/packages/dd-trace/src/appsec/sdk/track_event.js +37 -24
  89. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -4
  90. package/packages/dd-trace/src/appsec/telemetry.js +10 -0
  91. package/packages/dd-trace/src/appsec/user_tracking.js +168 -0
  92. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  93. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -3
  94. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  95. package/packages/dd-trace/src/azure_metadata.js +4 -4
  96. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -4
  97. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +39 -3
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  100. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -1
  101. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  102. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -9
  103. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
  104. package/packages/dd-trace/src/config.js +24 -32
  105. package/packages/dd-trace/src/constants.js +1 -0
  106. package/packages/dd-trace/src/crashtracking/crashtracker.js +3 -2
  107. package/packages/dd-trace/src/datastreams/processor.js +4 -6
  108. package/packages/dd-trace/src/datastreams/writer.js +6 -5
  109. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +80 -0
  110. package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
  111. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +6 -0
  112. package/packages/dd-trace/src/debugger/devtools_client/index.js +63 -8
  113. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +10 -67
  114. package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -1
  115. package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -1
  116. package/packages/dd-trace/src/debugger/devtools_client/status.js +4 -4
  117. package/packages/dd-trace/src/debugger/index.js +14 -10
  118. package/packages/dd-trace/src/dogstatsd.js +2 -2
  119. package/packages/dd-trace/src/encode/0.4.js +23 -78
  120. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +0 -32
  121. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -2
  122. package/packages/dd-trace/src/encode/span-stats.js +0 -30
  123. package/packages/dd-trace/src/exporters/agent/writer.js +3 -3
  124. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  125. package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -1
  126. package/packages/dd-trace/src/flare/index.js +1 -1
  127. package/packages/dd-trace/src/guardrails/index.js +64 -0
  128. package/packages/dd-trace/src/guardrails/log.js +32 -0
  129. package/packages/dd-trace/src/guardrails/telemetry.js +78 -0
  130. package/packages/dd-trace/src/guardrails/util.js +10 -0
  131. package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
  132. package/packages/dd-trace/src/llmobs/storage.js +2 -3
  133. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  134. package/packages/dd-trace/src/{encode → msgpack}/chunk.js +8 -5
  135. package/packages/dd-trace/src/msgpack/encoder.js +309 -0
  136. package/packages/dd-trace/src/msgpack/index.js +6 -0
  137. package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
  138. package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -9
  139. package/packages/dd-trace/src/opentracing/span.js +1 -1
  140. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  141. package/packages/dd-trace/src/plugin_manager.js +4 -2
  142. package/packages/dd-trace/src/plugins/ci_plugin.js +47 -4
  143. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  144. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  145. package/packages/dd-trace/src/plugins/util/git.js +7 -7
  146. package/packages/dd-trace/src/plugins/util/test.js +36 -3
  147. package/packages/dd-trace/src/plugins/util/web.js +2 -2
  148. package/packages/dd-trace/src/profiling/config.js +3 -0
  149. package/packages/dd-trace/src/profiling/exporters/agent.js +9 -68
  150. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +76 -0
  151. package/packages/dd-trace/src/profiling/exporters/file.js +8 -4
  152. package/packages/dd-trace/src/profiling/profiler.js +62 -10
  153. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +22 -12
  154. package/packages/dd-trace/src/profiling/profilers/events.js +47 -8
  155. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -17
  156. package/packages/dd-trace/src/profiling/webspan-utils.js +23 -0
  157. package/packages/dd-trace/src/proxy.js +7 -2
  158. package/packages/dd-trace/src/runtime_metrics.js +107 -4
  159. package/packages/dd-trace/src/serverless.js +1 -1
  160. package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +1 -1
  161. package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +1 -1
  162. package/packages/dd-trace/src/span_processor.js +10 -10
  163. package/packages/dd-trace/src/tagger.js +1 -1
  164. package/packages/dd-trace/src/telemetry/index.js +1 -0
  165. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  166. package/packages/dd-trace/src/telemetry/logs/log-collector.js +10 -2
  167. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  168. package/packages/dd-trace/src/util.js +5 -16
  169. package/packages/datadog-instrumentations/src/qs.js +0 -24
  170. package/packages/dd-trace/src/appsec/iast/iast-log.js +0 -86
  171. package/packages/dd-trace/src/appsec/passport.js +0 -110
  172. package/packages/dd-trace/src/telemetry/init-telemetry.js +0 -75
@@ -15,7 +15,7 @@ function isUserBlocked (user) {
15
15
 
16
16
  function checkUserAndSetUser (tracer, user) {
17
17
  if (!user || !user.id) {
18
- log.warn('Invalid user provided to isUserBlocked')
18
+ log.warn('[ASM] Invalid user provided to isUserBlocked')
19
19
  return false
20
20
  }
21
21
 
@@ -25,7 +25,7 @@ function checkUserAndSetUser (tracer, user) {
25
25
  setUserTags(user, rootSpan)
26
26
  }
27
27
  } else {
28
- log.warn('Root span not available in isUserBlocked')
28
+ log.warn('[ASM] Root span not available in isUserBlocked')
29
29
  }
30
30
 
31
31
  return isUserBlocked(user)
@@ -41,13 +41,13 @@ function blockRequest (tracer, req, res) {
41
41
  }
42
42
 
43
43
  if (!req || !res) {
44
- log.warn('Requests or response object not available in blockRequest')
44
+ log.warn('[ASM] Requests or response object not available in blockRequest')
45
45
  return false
46
46
  }
47
47
 
48
48
  const rootSpan = getRootSpan(tracer)
49
49
  if (!rootSpan) {
50
- log.warn('Root span not available in blockRequest')
50
+ log.warn('[ASM] Root span not available in blockRequest')
51
51
  return false
52
52
  }
53
53
 
@@ -172,6 +172,15 @@ function addRaspRequestMetrics (store, { duration, durationExt }) {
172
172
  store[DD_TELEMETRY_REQUEST_METRICS].raspEvalCount++
173
173
  }
174
174
 
175
+ function incrementMissingUserLoginMetric (framework, eventType) {
176
+ if (!enabled) return
177
+
178
+ appsecMetrics.count('instrum.user_auth.missing_user_login', {
179
+ framework,
180
+ event_type: eventType
181
+ }).inc()
182
+ }
183
+
175
184
  function getRequestMetrics (req) {
176
185
  if (req) {
177
186
  const store = getStore(req)
@@ -188,6 +197,7 @@ module.exports = {
188
197
  incrementWafInitMetric,
189
198
  incrementWafUpdatesMetric,
190
199
  incrementWafRequestsMetric,
200
+ incrementMissingUserLoginMetric,
191
201
 
192
202
  getRequestMetrics
193
203
  }
@@ -0,0 +1,168 @@
1
+ 'use strict'
2
+
3
+ const crypto = require('crypto')
4
+ const log = require('../log')
5
+ const telemetry = require('./telemetry')
6
+ const addresses = require('./addresses')
7
+ const { keepTrace } = require('../priority_sampler')
8
+ const { SAMPLING_MECHANISM_APPSEC } = require('../constants')
9
+ const standalone = require('./standalone')
10
+ const waf = require('./waf')
11
+
12
+ // the RFC doesn't include '_id', but it's common in MongoDB
13
+ const USER_ID_FIELDS = ['id', '_id', 'email', 'username', 'login', 'user']
14
+
15
+ let collectionMode
16
+
17
+ function setCollectionMode (mode, overwrite = true) {
18
+ // don't overwrite if already set, only used in appsec/index.js to not overwrite RC values
19
+ if (!overwrite && collectionMode) return
20
+
21
+ /* eslint-disable no-fallthrough */
22
+ switch (mode) {
23
+ case 'safe':
24
+ log.warn('[ASM] Using deprecated value "safe" in config.appsec.eventTracking.mode')
25
+ case 'anon':
26
+ case 'anonymization':
27
+ collectionMode = 'anonymization'
28
+ break
29
+
30
+ case 'extended':
31
+ log.warn('[ASM] Using deprecated value "extended" in config.appsec.eventTracking.mode')
32
+ case 'ident':
33
+ case 'identification':
34
+ collectionMode = 'identification'
35
+ break
36
+
37
+ default:
38
+ collectionMode = 'disabled'
39
+ }
40
+ /* eslint-enable no-fallthrough */
41
+ }
42
+
43
+ function obfuscateIfNeeded (str) {
44
+ if (collectionMode === 'anonymization') {
45
+ // get first 16 bytes of sha256 hash in lowercase hex
46
+ return 'anon_' + crypto.createHash('sha256').update(str).digest().toString('hex', 0, 16).toLowerCase()
47
+ } else {
48
+ return str
49
+ }
50
+ }
51
+
52
+ // TODO: should we find other ways to get the user ID ?
53
+ function getUserId (user) {
54
+ if (!user) return
55
+
56
+ for (const field of USER_ID_FIELDS) {
57
+ let id = user[field]
58
+
59
+ // try to find a field that can be stringified
60
+ if (id && typeof id.toString === 'function') {
61
+ id = id.toString()
62
+
63
+ if (typeof id !== 'string' || id.startsWith('[object ')) {
64
+ // probably not a usable ID ?
65
+ continue
66
+ }
67
+
68
+ return obfuscateIfNeeded(id)
69
+ }
70
+ }
71
+ }
72
+
73
+ function trackLogin (framework, login, user, success, rootSpan) {
74
+ if (!collectionMode || collectionMode === 'disabled') return
75
+
76
+ if (!rootSpan) {
77
+ log.error('[ASM] No rootSpan found in AppSec trackLogin')
78
+ return
79
+ }
80
+
81
+ if (typeof login !== 'string') {
82
+ log.error('[ASM] Invalid login provided to AppSec trackLogin')
83
+
84
+ telemetry.incrementMissingUserLoginMetric(framework, success ? 'login_success' : 'login_failure')
85
+ // note:
86
+ // if we start supporting using userId if login is missing, we need to only give up if both are missing, and
87
+ // implement 'appsec.instrum.user_auth.missing_user_id' telemetry too
88
+ return
89
+ }
90
+
91
+ login = obfuscateIfNeeded(login)
92
+ const userId = getUserId(user)
93
+
94
+ let newTags
95
+
96
+ const persistent = {
97
+ [addresses.USER_LOGIN]: login
98
+ }
99
+
100
+ const currentTags = rootSpan.context()._tags
101
+ const isSdkCalled = currentTags[`_dd.appsec.events.users.login.${success ? 'success' : 'failure'}.sdk`] === 'true'
102
+
103
+ // used to not overwrite tags set by SDK
104
+ function shouldSetTag (tag) {
105
+ return !(isSdkCalled && currentTags[tag])
106
+ }
107
+
108
+ if (success) {
109
+ newTags = {
110
+ 'appsec.events.users.login.success.track': 'true',
111
+ '_dd.appsec.events.users.login.success.auto.mode': collectionMode,
112
+ '_dd.appsec.usr.login': login
113
+ }
114
+
115
+ if (shouldSetTag('appsec.events.users.login.success.usr.login')) {
116
+ newTags['appsec.events.users.login.success.usr.login'] = login
117
+ }
118
+
119
+ if (userId) {
120
+ newTags['_dd.appsec.usr.id'] = userId
121
+
122
+ if (shouldSetTag('usr.id')) {
123
+ newTags['usr.id'] = userId
124
+ persistent[addresses.USER_ID] = userId
125
+ }
126
+ }
127
+
128
+ persistent[addresses.LOGIN_SUCCESS] = null
129
+ } else {
130
+ newTags = {
131
+ 'appsec.events.users.login.failure.track': 'true',
132
+ '_dd.appsec.events.users.login.failure.auto.mode': collectionMode,
133
+ '_dd.appsec.usr.login': login
134
+ }
135
+
136
+ if (shouldSetTag('appsec.events.users.login.failure.usr.login')) {
137
+ newTags['appsec.events.users.login.failure.usr.login'] = login
138
+ }
139
+
140
+ if (userId) {
141
+ newTags['_dd.appsec.usr.id'] = userId
142
+
143
+ if (shouldSetTag('appsec.events.users.login.failure.usr.id')) {
144
+ newTags['appsec.events.users.login.failure.usr.id'] = userId
145
+ }
146
+ }
147
+
148
+ /* TODO: if one day we have this info
149
+ if (exists != null && shouldSetTag('appsec.events.users.login.failure.usr.exists')) {
150
+ newTags['appsec.events.users.login.failure.usr.exists'] = exists
151
+ }
152
+ */
153
+
154
+ persistent[addresses.LOGIN_FAILURE] = null
155
+ }
156
+
157
+ keepTrace(rootSpan, SAMPLING_MECHANISM_APPSEC)
158
+ standalone.sample(rootSpan)
159
+
160
+ rootSpan.addTags(newTags)
161
+
162
+ return waf.run({ persistent })
163
+ }
164
+
165
+ module.exports = {
166
+ setCollectionMode,
167
+ trackLogin
168
+ }
@@ -41,7 +41,7 @@ function update (newRules) {
41
41
  try {
42
42
  waf.wafManager.update(newRules)
43
43
  } catch (err) {
44
- log.error('Could not apply rules from remote config')
44
+ log.error('[ASM] Could not apply rules from remote config')
45
45
  throw err
46
46
  }
47
47
  }
@@ -50,7 +50,7 @@ function run (data, req, raspRuleType) {
50
50
  if (!req) {
51
51
  const store = storage.getStore()
52
52
  if (!store || !store.req) {
53
- log.warn('Request object not available in waf.run')
53
+ log.warn('[ASM] Request object not available in waf.run')
54
54
  return
55
55
  }
56
56
 
@@ -23,7 +23,7 @@ class WAFContextWrapper {
23
23
 
24
24
  run ({ persistent, ephemeral }, raspRuleType) {
25
25
  if (this.ddwafContext.disposed) {
26
- log.warn('Calling run on a disposed context')
26
+ log.warn('[ASM] Calling run on a disposed context')
27
27
  return
28
28
  }
29
29
 
@@ -101,8 +101,7 @@ class WAFContextWrapper {
101
101
 
102
102
  return result.actions
103
103
  } catch (err) {
104
- log.error('Error while running the AppSec WAF')
105
- log.error(err)
104
+ log.error('[ASM] Error while running the AppSec WAF', err)
106
105
  }
107
106
  }
108
107
 
@@ -25,7 +25,7 @@ class WAFManager {
25
25
  const { obfuscatorKeyRegex, obfuscatorValueRegex } = this.config
26
26
  return new DDWAF(rules, { obfuscatorKeyRegex, obfuscatorValueRegex })
27
27
  } catch (err) {
28
- log.error('AppSec could not load native package. In-app WAF features will not be available.')
28
+ log.error('[ASM] AppSec could not load native package. In-app WAF features will not be available.')
29
29
 
30
30
  throw err
31
31
  }
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- // eslint-disable-next-line max-len
3
+ // eslint-disable-next-line @stylistic/js/max-len
4
4
  // Modeled after https://github.com/DataDog/libdatadog/blob/f3994857a59bb5679a65967138c5a3aec418a65f/ddcommon/src/azure_app_services.rs
5
5
 
6
6
  const os = require('os')
@@ -79,7 +79,7 @@ function buildMetadata () {
79
79
  function getAzureAppMetadata () {
80
80
  // DD_AZURE_APP_SERVICES is an environment variable introduced by the .NET APM team and is set automatically for
81
81
  // anyone using the Datadog APM Extensions (.NET, Java, or Node) for Windows Azure App Services
82
- // eslint-disable-next-line max-len
82
+ // eslint-disable-next-line @stylistic/js/max-len
83
83
  // See: https://github.com/DataDog/datadog-aas-extension/blob/01f94b5c28b7fa7a9ab264ca28bd4e03be603900/node/src/applicationHost.xdt#L20-L21
84
84
  return process.env.DD_AZURE_APP_SERVICES !== undefined ? buildMetadata() : undefined
85
85
  }
@@ -88,9 +88,9 @@ function getAzureFunctionMetadata () {
88
88
  return getIsAzureFunction() ? buildMetadata() : undefined
89
89
  }
90
90
 
91
- // eslint-disable-next-line max-len
91
+ // eslint-disable-next-line @stylistic/js/max-len
92
92
  // Modeled after https://github.com/DataDog/libdatadog/blob/92272e90a7919f07178f3246ef8f82295513cfed/profiling/src/exporter/mod.rs#L187
93
- // eslint-disable-next-line max-len
93
+ // eslint-disable-next-line @stylistic/js/max-len
94
94
  // and https://github.com/DataDog/libdatadog/blob/f3994857a59bb5679a65967138c5a3aec418a65f/trace-utils/src/trace_utils.rs#L533
95
95
  function getAzureTagsFromMetadata (metadata) {
96
96
  if (metadata === undefined) {
@@ -73,8 +73,7 @@ class TestVisDynamicInstrumentation {
73
73
  // Allow the parent to exit even if the worker is still running
74
74
  this.worker.unref()
75
75
 
76
- this.breakpointSetChannel.port2.on('message', (message) => {
77
- const { probeId } = message
76
+ this.breakpointSetChannel.port2.on('message', ({ probeId }) => {
78
77
  const resolve = probeIdToResolveBreakpointSet.get(probeId)
79
78
  if (resolve) {
80
79
  resolve()
@@ -82,8 +81,7 @@ class TestVisDynamicInstrumentation {
82
81
  }
83
82
  }).unref()
84
83
 
85
- this.breakpointHitChannel.port2.on('message', (message) => {
86
- const { snapshot } = message
84
+ this.breakpointHitChannel.port2.on('message', ({ snapshot }) => {
87
85
  const { probe: { id: probeId } } = snapshot
88
86
  const resolve = probeIdToResolveBreakpointHit.get(probeId)
89
87
  if (resolve) {
@@ -91,6 +89,9 @@ class TestVisDynamicInstrumentation {
91
89
  probeIdToResolveBreakpointHit.delete(probeId)
92
90
  }
93
91
  }).unref()
92
+
93
+ this.worker.on('error', (err) => log.error('ci-visibility DI worker error', err))
94
+ this.worker.on('messageerror', (err) => log.error('ci-visibility DI worker messageerror', err))
94
95
  }
95
96
  }
96
97
 
@@ -1,6 +1,8 @@
1
1
  'use strict'
2
-
2
+ const sourceMap = require('source-map')
3
+ const path = require('path')
3
4
  const { workerData: { breakpointSetChannel, breakpointHitChannel } } = require('worker_threads')
5
+
4
6
  // TODO: move debugger/devtools_client/session to common place
5
7
  const session = require('../../../debugger/devtools_client/session')
6
8
  // TODO: move debugger/devtools_client/snapshot to common place
@@ -69,14 +71,24 @@ async function addBreakpoint (snapshotId, probe) {
69
71
  const script = findScriptFromPartialPath(file)
70
72
  if (!script) throw new Error(`No loaded script found for ${file}`)
71
73
 
72
- const [path, scriptId] = script
74
+ const [path, scriptId, sourceMapURL] = script
73
75
 
74
76
  log.debug(`Adding breakpoint at ${path}:${line}`)
75
77
 
78
+ let lineNumber = line
79
+
80
+ if (sourceMapURL && sourceMapURL.startsWith('data:')) {
81
+ try {
82
+ lineNumber = await processScriptWithInlineSourceMap({ file, line, sourceMapURL })
83
+ } catch (err) {
84
+ log.error(err)
85
+ }
86
+ }
87
+
76
88
  const { breakpointId } = await session.post('Debugger.setBreakpoint', {
77
89
  location: {
78
90
  scriptId,
79
- lineNumber: line - 1
91
+ lineNumber: lineNumber - 1
80
92
  }
81
93
  })
82
94
 
@@ -88,3 +100,27 @@ function start () {
88
100
  sessionStarted = true
89
101
  return session.post('Debugger.enable') // return instead of await to reduce number of promises created
90
102
  }
103
+
104
+ async function processScriptWithInlineSourceMap (params) {
105
+ const { file, line, sourceMapURL } = params
106
+
107
+ // Extract the base64-encoded source map
108
+ const base64SourceMap = sourceMapURL.split('base64,')[1]
109
+
110
+ // Decode the base64 source map
111
+ const decodedSourceMap = Buffer.from(base64SourceMap, 'base64').toString('utf8')
112
+
113
+ // Parse the source map
114
+ const consumer = await new sourceMap.SourceMapConsumer(decodedSourceMap)
115
+
116
+ // Map to the generated position
117
+ const generatedPosition = consumer.generatedPositionFor({
118
+ source: path.basename(file), // this needs to be the file, not the filepath
119
+ line,
120
+ column: 0
121
+ })
122
+
123
+ consumer.destroy()
124
+
125
+ return generatedPosition.line
126
+ }
@@ -63,7 +63,7 @@ class Writer extends BaseWriter {
63
63
  TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
64
64
  { endpoint: 'code_coverage' }
65
65
  )
66
- log.error(err)
66
+ log.error('Error sending CI coverage payload', err)
67
67
  done()
68
68
  return
69
69
  }
@@ -40,7 +40,7 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
40
40
 
41
41
  request(data, options, (err, res) => {
42
42
  if (err) {
43
- log.error(err)
43
+ log.error('Error sending DI logs payload', err)
44
44
  done()
45
45
  return
46
46
  }
@@ -38,7 +38,7 @@ class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
38
38
  apiUrl = new URL(apiUrl)
39
39
  this._apiUrl = apiUrl
40
40
  } catch (e) {
41
- log.error(e)
41
+ log.error('Error setting CI exporter api url', e)
42
42
  }
43
43
  }
44
44
 
@@ -64,7 +64,7 @@ class Writer extends BaseWriter {
64
64
  TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
65
65
  { endpoint: 'test_cycle' }
66
66
  )
67
- log.error(err)
67
+ log.error('Error sending CI agentless payload', err)
68
68
  done()
69
69
  return
70
70
  }
@@ -73,6 +73,9 @@ class CiVisibilityExporter extends AgentInfoExporter {
73
73
  if (this._coverageWriter) {
74
74
  this._coverageWriter.flush()
75
75
  }
76
+ if (this._logsWriter) {
77
+ this._logsWriter.flush()
78
+ }
76
79
  })
77
80
  }
78
81
 
@@ -193,7 +196,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
193
196
  isEarlyFlakeDetectionEnabled,
194
197
  earlyFlakeDetectionNumRetries,
195
198
  earlyFlakeDetectionFaultyThreshold,
196
- isFlakyTestRetriesEnabled
199
+ isFlakyTestRetriesEnabled,
200
+ isDiEnabled
197
201
  } = remoteConfiguration
198
202
  return {
199
203
  isCodeCoverageEnabled,
@@ -204,7 +208,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
204
208
  earlyFlakeDetectionNumRetries,
205
209
  earlyFlakeDetectionFaultyThreshold,
206
210
  isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled,
207
- flakyTestRetriesCount: this._config.flakyTestRetriesCount
211
+ flakyTestRetriesCount: this._config.flakyTestRetriesCount,
212
+ isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled
208
213
  }
209
214
  }
210
215
 
@@ -222,7 +227,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
222
227
  repositoryUrl,
223
228
  (err) => {
224
229
  if (err) {
225
- log.error(`Error uploading git metadata: ${err.message}`)
230
+ log.error('Error uploading git metadata: %s', err.message)
226
231
  } else {
227
232
  log.debug('Successfully uploaded git metadata')
228
233
  }
@@ -302,13 +307,28 @@ class CiVisibilityExporter extends AgentInfoExporter {
302
307
  if (!this._isInitialized) {
303
308
  return done()
304
309
  }
305
- this._writer.flush(() => {
306
- if (this._coverageWriter) {
307
- this._coverageWriter.flush(done)
308
- } else {
310
+
311
+ // TODO: safe to do them at once? Or do we want to do them one by one?
312
+ const writers = [
313
+ this._writer,
314
+ this._coverageWriter,
315
+ this._logsWriter
316
+ ].filter(writer => writer)
317
+
318
+ let remaining = writers.length
319
+
320
+ if (remaining === 0) {
321
+ return done()
322
+ }
323
+
324
+ const onFlushComplete = () => {
325
+ remaining -= 1
326
+ if (remaining === 0) {
309
327
  done()
310
328
  }
311
- })
329
+ }
330
+
331
+ writers.forEach(writer => writer.flush(onFlushComplete))
312
332
  }
313
333
 
314
334
  exportUncodedCoverages () {
@@ -327,7 +347,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
327
347
  this._writer.setUrl(url)
328
348
  this._coverageWriter.setUrl(coverageUrl)
329
349
  } catch (e) {
330
- log.error(e)
350
+ log.error('Error setting CI exporter url', e)
331
351
  }
332
352
  }
333
353
 
@@ -92,7 +92,8 @@ function getLibraryConfiguration ({
92
92
  itr_enabled: isItrEnabled,
93
93
  require_git: requireGit,
94
94
  early_flake_detection: earlyFlakeDetectionConfig,
95
- flaky_test_retries_enabled: isFlakyTestRetriesEnabled
95
+ flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
96
+ di_enabled: isDiEnabled
96
97
  }
97
98
  }
98
99
  } = JSON.parse(res)
@@ -107,7 +108,8 @@ function getLibraryConfiguration ({
107
108
  earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
108
109
  earlyFlakeDetectionFaultyThreshold:
109
110
  earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
110
- isFlakyTestRetriesEnabled
111
+ isFlakyTestRetriesEnabled,
112
+ isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled
111
113
  }
112
114
 
113
115
  log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)