dd-trace 5.32.0 → 5.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +12 -11
  2. package/index.d.ts +11 -1
  3. package/package.json +2 -2
  4. package/packages/datadog-instrumentations/src/aws-sdk.js +3 -1
  5. package/packages/datadog-instrumentations/src/cucumber.js +17 -9
  6. package/packages/datadog-instrumentations/src/jest.js +36 -21
  7. package/packages/datadog-instrumentations/src/mocha/main.js +9 -4
  8. package/packages/datadog-instrumentations/src/mocha/utils.js +4 -2
  9. package/packages/datadog-instrumentations/src/mocha/worker.js +4 -2
  10. package/packages/datadog-instrumentations/src/playwright.js +8 -3
  11. package/packages/datadog-instrumentations/src/vitest.js +35 -11
  12. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +16 -0
  13. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +63 -0
  14. package/packages/datadog-plugin-aws-sdk/src/services/{bedrockruntime.js → bedrockruntime/utils.js} +67 -75
  15. package/packages/datadog-plugin-cucumber/src/index.js +3 -1
  16. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -8
  17. package/packages/datadog-plugin-cypress/src/support.js +6 -2
  18. package/packages/datadog-plugin-fetch/src/index.js +3 -3
  19. package/packages/datadog-plugin-http/src/client.js +5 -33
  20. package/packages/datadog-plugin-jest/src/index.js +4 -1
  21. package/packages/datadog-plugin-mocha/src/index.js +3 -1
  22. package/packages/datadog-plugin-playwright/src/index.js +3 -1
  23. package/packages/datadog-plugin-vitest/src/index.js +16 -4
  24. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +3 -3
  25. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -24
  26. package/packages/dd-trace/src/appsec/iast/iast-context.js +12 -0
  27. package/packages/dd-trace/src/appsec/iast/path-line.js +19 -23
  28. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -0
  29. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +75 -24
  30. package/packages/dd-trace/src/appsec/rasp/utils.js +10 -5
  31. package/packages/dd-trace/src/appsec/stack_trace.js +38 -28
  32. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -4
  33. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -3
  34. package/packages/dd-trace/src/config.js +4 -0
  35. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +59 -0
  36. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -0
  37. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +0 -2
  38. package/packages/dd-trace/src/plugins/util/test.js +2 -0
@@ -6,11 +6,18 @@ const ddBasePath = calculateDDBasePath(__dirname)
6
6
 
7
7
  const LIBRARY_FRAMES_BUFFER = 20
8
8
 
9
+ const STACK_TRACE_NAMESPACES = {
10
+ RASP: 'exploit',
11
+ IAST: 'vulnerability'
12
+ }
13
+
9
14
  function getCallSiteList (maxDepth = 100) {
10
15
  const previousPrepareStackTrace = Error.prepareStackTrace
11
16
  const previousStackTraceLimit = Error.stackTraceLimit
12
17
  let callsiteList
13
- Error.stackTraceLimit = maxDepth
18
+ // Since some frames will be discarded because they come from tracer codebase, a buffer is added
19
+ // to the limit in order to get as close as `maxDepth` number of frames.
20
+ Error.stackTraceLimit = maxDepth + LIBRARY_FRAMES_BUFFER
14
21
 
15
22
  try {
16
23
  Error.prepareStackTrace = function (_, callsites) {
@@ -30,7 +37,10 @@ function filterOutFramesFromLibrary (callSiteList) {
30
37
  return callSiteList.filter(callSite => !callSite.getFileName()?.startsWith(ddBasePath))
31
38
  }
32
39
 
33
- function getFramesForMetaStruct (callSiteList, maxDepth = 32) {
40
+ function getCallsiteFrames (maxDepth = 32, callSiteListGetter = getCallSiteList) {
41
+ if (maxDepth < 1) maxDepth = Infinity
42
+
43
+ const callSiteList = callSiteListGetter(maxDepth)
34
44
  const filteredFrames = filterOutFramesFromLibrary(callSiteList)
35
45
 
36
46
  const half = filteredFrames.length > maxDepth ? Math.round(maxDepth / 2) : Infinity
@@ -45,46 +55,46 @@ function getFramesForMetaStruct (callSiteList, maxDepth = 32) {
45
55
  line: callSite.getLineNumber(),
46
56
  column: callSite.getColumnNumber(),
47
57
  function: callSite.getFunctionName(),
48
- class_name: callSite.getTypeName()
58
+ class_name: callSite.getTypeName(),
59
+ isNative: callSite.isNative()
49
60
  })
50
61
  }
51
62
 
52
63
  return indexedFrames
53
64
  }
54
65
 
55
- function reportStackTrace (rootSpan, stackId, maxDepth, maxStackTraces, callSiteListGetter = getCallSiteList) {
66
+ function reportStackTrace (rootSpan, stackId, frames, namespace = STACK_TRACE_NAMESPACES.RASP) {
56
67
  if (!rootSpan) return
68
+ if (!Array.isArray(frames)) return
57
69
 
58
- if (maxStackTraces < 1 || (rootSpan.meta_struct?.['_dd.stack']?.exploit?.length ?? 0) < maxStackTraces) {
59
- // Since some frames will be discarded because they come from tracer codebase, a buffer is added
60
- // to the limit in order to get as close as `maxDepth` number of frames.
61
- if (maxDepth < 1) maxDepth = Infinity
62
- const callSiteList = callSiteListGetter(maxDepth + LIBRARY_FRAMES_BUFFER)
63
- if (!Array.isArray(callSiteList)) return
70
+ if (!rootSpan.meta_struct) {
71
+ rootSpan.meta_struct = {}
72
+ }
64
73
 
65
- if (!rootSpan.meta_struct) {
66
- rootSpan.meta_struct = {}
67
- }
74
+ if (!rootSpan.meta_struct['_dd.stack']) {
75
+ rootSpan.meta_struct['_dd.stack'] = {}
76
+ }
68
77
 
69
- if (!rootSpan.meta_struct['_dd.stack']) {
70
- rootSpan.meta_struct['_dd.stack'] = {}
71
- }
78
+ if (!rootSpan.meta_struct['_dd.stack'][namespace]) {
79
+ rootSpan.meta_struct['_dd.stack'][namespace] = []
80
+ }
72
81
 
73
- if (!rootSpan.meta_struct['_dd.stack'].exploit) {
74
- rootSpan.meta_struct['_dd.stack'].exploit = []
75
- }
82
+ rootSpan.meta_struct['_dd.stack'][namespace].push({
83
+ id: stackId,
84
+ language: 'nodejs',
85
+ frames
86
+ })
87
+ }
76
88
 
77
- const frames = getFramesForMetaStruct(callSiteList, maxDepth)
89
+ function canReportStackTrace (rootSpan, maxStackTraces, namespace = STACK_TRACE_NAMESPACES.RASP) {
90
+ if (!rootSpan) return false
78
91
 
79
- rootSpan.meta_struct['_dd.stack'].exploit.push({
80
- id: stackId,
81
- language: 'nodejs',
82
- frames
83
- })
84
- }
92
+ return maxStackTraces < 1 || (rootSpan.meta_struct?.['_dd.stack']?.[namespace]?.length ?? 0) < maxStackTraces
85
93
  }
86
94
 
87
95
  module.exports = {
88
- getCallSiteList,
89
- reportStackTrace
96
+ getCallsiteFrames,
97
+ reportStackTrace,
98
+ canReportStackTrace,
99
+ STACK_TRACE_NAMESPACES
90
100
  }
@@ -87,9 +87,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
87
87
 
88
88
  shouldRequestKnownTests () {
89
89
  return !!(
90
- this._config.isEarlyFlakeDetectionEnabled &&
91
90
  this._canUseCiVisProtocol &&
92
- this._libraryConfig?.isEarlyFlakeDetectionEnabled
91
+ this._libraryConfig?.isKnownTestsEnabled
93
92
  )
94
93
  }
95
94
 
@@ -197,7 +196,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
197
196
  earlyFlakeDetectionNumRetries,
198
197
  earlyFlakeDetectionFaultyThreshold,
199
198
  isFlakyTestRetriesEnabled,
200
- isDiEnabled
199
+ isDiEnabled,
200
+ isKnownTestsEnabled
201
201
  } = remoteConfiguration
202
202
  return {
203
203
  isCodeCoverageEnabled,
@@ -209,7 +209,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
209
209
  earlyFlakeDetectionFaultyThreshold,
210
210
  isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled,
211
211
  flakyTestRetriesCount: this._config.flakyTestRetriesCount,
212
- isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled
212
+ isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled,
213
+ isKnownTestsEnabled
213
214
  }
214
215
  }
215
216
 
@@ -93,7 +93,8 @@ function getLibraryConfiguration ({
93
93
  require_git: requireGit,
94
94
  early_flake_detection: earlyFlakeDetectionConfig,
95
95
  flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
96
- di_enabled: isDiEnabled
96
+ di_enabled: isDiEnabled,
97
+ known_tests_enabled: isKnownTestsEnabled
97
98
  }
98
99
  }
99
100
  } = JSON.parse(res)
@@ -103,13 +104,14 @@ function getLibraryConfiguration ({
103
104
  isSuitesSkippingEnabled,
104
105
  isItrEnabled,
105
106
  requireGit,
106
- isEarlyFlakeDetectionEnabled: earlyFlakeDetectionConfig?.enabled ?? false,
107
+ isEarlyFlakeDetectionEnabled: isKnownTestsEnabled && (earlyFlakeDetectionConfig?.enabled ?? false),
107
108
  earlyFlakeDetectionNumRetries:
108
109
  earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
109
110
  earlyFlakeDetectionFaultyThreshold:
110
111
  earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
111
112
  isFlakyTestRetriesEnabled,
112
- isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled
113
+ isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
114
+ isKnownTestsEnabled
113
115
  }
114
116
 
115
117
  log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
@@ -497,6 +497,7 @@ class Config {
497
497
  this._setValue(defaults, 'iast.redactionValuePattern', null)
498
498
  this._setValue(defaults, 'iast.requestSampling', 30)
499
499
  this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION')
500
+ this._setValue(defaults, 'iast.stackTrace.enabled', true)
500
501
  this._setValue(defaults, 'injectionEnabled', [])
501
502
  this._setValue(defaults, 'isAzureFunction', false)
502
503
  this._setValue(defaults, 'isCiVisibility', false)
@@ -622,6 +623,7 @@ class Config {
622
623
  DD_IAST_REDACTION_VALUE_PATTERN,
623
624
  DD_IAST_REQUEST_SAMPLING,
624
625
  DD_IAST_TELEMETRY_VERBOSITY,
626
+ DD_IAST_STACK_TRACE_ENABLED,
625
627
  DD_INJECTION_ENABLED,
626
628
  DD_INSTRUMENTATION_TELEMETRY_ENABLED,
627
629
  DD_INSTRUMENTATION_CONFIG_ID,
@@ -787,6 +789,7 @@ class Config {
787
789
  }
788
790
  this._envUnprocessed['iast.requestSampling'] = DD_IAST_REQUEST_SAMPLING
789
791
  this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
792
+ this._setBoolean(env, 'iast.stackTrace.enabled', DD_IAST_STACK_TRACE_ENABLED)
790
793
  this._setArray(env, 'injectionEnabled', DD_INJECTION_ENABLED)
791
794
  this._setBoolean(env, 'isAzureFunction', getIsAzureFunction())
792
795
  this._setBoolean(env, 'isGCPFunction', getIsGCPFunction())
@@ -976,6 +979,7 @@ class Config {
976
979
  this._optsUnprocessed['iast.requestSampling'] = options.iast?.requestSampling
977
980
  }
978
981
  this._setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
982
+ this._setBoolean(opts, 'iast.stackTrace.enabled', options.iast?.stackTrace?.enabled)
979
983
  this._setBoolean(opts, 'isCiVisibility', options.isCiVisibility)
980
984
  this._setBoolean(opts, 'legacyBaggageEnabled', options.legacyBaggageEnabled)
981
985
  this._setBoolean(opts, 'llmobs.agentlessEnabled', options.llmobs?.agentlessEnabled)
@@ -0,0 +1,59 @@
1
+ const BaseLLMObsPlugin = require('./base')
2
+ const { storage } = require('../../../../datadog-core')
3
+ const llmobsStore = storage('llmobs')
4
+
5
+ const {
6
+ extractRequestParams,
7
+ extractTextAndResponseReason,
8
+ parseModelId
9
+ } = require('../../../../datadog-plugin-aws-sdk/src/services/bedrockruntime/utils')
10
+
11
+ const enabledOperations = ['invokeModel']
12
+
13
+ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
14
+ constructor () {
15
+ super(...arguments)
16
+
17
+ this.addSub('apm:aws:request:complete:bedrockruntime', ({ response }) => {
18
+ const request = response.request
19
+ const operation = request.operation
20
+ // avoids instrumenting other non supported runtime operations
21
+ if (!enabledOperations.includes(operation)) {
22
+ return
23
+ }
24
+ const { modelProvider, modelName } = parseModelId(request.params.modelId)
25
+
26
+ // avoids instrumenting non llm type
27
+ if (modelName.includes('embed')) {
28
+ return
29
+ }
30
+ const span = storage.getStore()?.span
31
+ this.setLLMObsTags({ request, span, response, modelProvider, modelName })
32
+ })
33
+ }
34
+
35
+ setLLMObsTags ({ request, span, response, modelProvider, modelName }) {
36
+ const parent = llmobsStore.getStore()?.span
37
+ this._tagger.registerLLMObsSpan(span, {
38
+ parent,
39
+ modelName: modelName.toLowerCase(),
40
+ modelProvider: modelProvider.toLowerCase(),
41
+ kind: 'llm',
42
+ name: 'bedrock-runtime.command'
43
+ })
44
+
45
+ const requestParams = extractRequestParams(request.params, modelProvider)
46
+ const textAndResponseReason = extractTextAndResponseReason(response, modelProvider, modelName)
47
+
48
+ // add metadata tags
49
+ this._tagger.tagMetadata(span, {
50
+ temperature: parseFloat(requestParams.temperature) || 0.0,
51
+ max_tokens: parseInt(requestParams.maxTokens) || 0
52
+ })
53
+
54
+ // add I/O tags
55
+ this._tagger.tagLLMIO(span, requestParams.prompt, textAndResponseReason.message)
56
+ }
57
+ }
58
+
59
+ module.exports = BedrockRuntimeLLMObsPlugin
@@ -158,6 +158,7 @@ module.exports = class CiPlugin extends Plugin {
158
158
  if (err) {
159
159
  log.error('Known tests could not be fetched. %s', err.message)
160
160
  this.libraryConfig.isEarlyFlakeDetectionEnabled = false
161
+ this.libraryConfig.isKnownTestsEnabled = false
161
162
  }
162
163
  onDone({ err, knownTests })
163
164
  })
@@ -2,7 +2,6 @@ const log = require('../../log')
2
2
  const tags = require('../../../../../ext/tags')
3
3
 
4
4
  const RESOURCE_NAME = tags.RESOURCE_NAME
5
- const HTTP_ROUTE = tags.HTTP_ROUTE
6
5
  const SPAN_KIND = tags.SPAN_KIND
7
6
  const SPAN_TYPE = tags.SPAN_TYPE
8
7
  const HTTP_URL = tags.HTTP_URL
@@ -54,7 +53,6 @@ function createInferredProxySpan (headers, childOf, tracer, context) {
54
53
  [SPAN_TYPE]: 'web',
55
54
  [HTTP_METHOD]: proxyContext.method,
56
55
  [HTTP_URL]: proxyContext.domainName + proxyContext.path,
57
- [HTTP_ROUTE]: proxyContext.path,
58
56
  stage: proxyContext.stage
59
57
  }
60
58
  }
@@ -59,6 +59,7 @@ const TEST_IS_NEW = 'test.is_new'
59
59
  const TEST_IS_RETRY = 'test.is_retry'
60
60
  const TEST_EARLY_FLAKE_ENABLED = 'test.early_flake.enabled'
61
61
  const TEST_EARLY_FLAKE_ABORT_REASON = 'test.early_flake.abort_reason'
62
+ const TEST_RETRY_REASON = 'test.retry_reason'
62
63
 
63
64
  const CI_APP_ORIGIN = 'ciapp-test'
64
65
 
@@ -145,6 +146,7 @@ module.exports = {
145
146
  TEST_IS_RETRY,
146
147
  TEST_EARLY_FLAKE_ENABLED,
147
148
  TEST_EARLY_FLAKE_ABORT_REASON,
149
+ TEST_RETRY_REASON,
148
150
  getTestEnvironmentMetadata,
149
151
  getTestParametersString,
150
152
  finishAllTraceSpans,