dd-trace 2.37.0 → 2.39.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 (88) hide show
  1. package/LICENSE-3rdparty.csv +4 -3
  2. package/index.d.ts +27 -0
  3. package/package.json +4 -4
  4. package/packages/datadog-instrumentations/src/aws-sdk.js +5 -0
  5. package/packages/datadog-instrumentations/src/cassandra-driver.js +6 -3
  6. package/packages/datadog-instrumentations/src/elasticsearch.js +39 -1
  7. package/packages/datadog-instrumentations/src/express.js +23 -0
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  9. package/packages/datadog-instrumentations/src/kafkajs.js +2 -2
  10. package/packages/datadog-instrumentations/src/openai.js +50 -0
  11. package/packages/datadog-instrumentations/src/opensearch.js +2 -1
  12. package/packages/datadog-instrumentations/src/passport-http.js +22 -0
  13. package/packages/datadog-instrumentations/src/passport-local.js +22 -0
  14. package/packages/datadog-instrumentations/src/passport-utils.js +36 -0
  15. package/packages/datadog-instrumentations/src/pg.js +17 -4
  16. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
  17. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
  18. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  19. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -0
  20. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
  21. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  22. package/packages/datadog-plugin-cassandra-driver/src/index.js +6 -6
  23. package/packages/datadog-plugin-dns/src/lookup.js +1 -1
  24. package/packages/datadog-plugin-elasticsearch/src/index.js +2 -2
  25. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
  26. package/packages/datadog-plugin-graphql/src/execute.js +1 -1
  27. package/packages/datadog-plugin-graphql/src/parse.js +1 -1
  28. package/packages/datadog-plugin-graphql/src/resolve.js +0 -5
  29. package/packages/datadog-plugin-graphql/src/validate.js +1 -1
  30. package/packages/datadog-plugin-grpc/src/client.js +9 -3
  31. package/packages/datadog-plugin-grpc/src/server.js +3 -3
  32. package/packages/datadog-plugin-http/src/client.js +1 -1
  33. package/packages/datadog-plugin-http/src/server.js +38 -34
  34. package/packages/datadog-plugin-http2/src/client.js +0 -5
  35. package/packages/datadog-plugin-http2/src/server.js +23 -23
  36. package/packages/datadog-plugin-kafkajs/src/consumer.js +6 -1
  37. package/packages/datadog-plugin-kafkajs/src/producer.js +8 -1
  38. package/packages/datadog-plugin-mocha/src/index.js +3 -3
  39. package/packages/datadog-plugin-moleculer/src/client.js +3 -3
  40. package/packages/datadog-plugin-moleculer/src/server.js +2 -2
  41. package/packages/datadog-plugin-mongodb-core/src/index.js +15 -4
  42. package/packages/datadog-plugin-next/src/index.js +50 -52
  43. package/packages/datadog-plugin-openai/src/index.js +685 -0
  44. package/packages/datadog-plugin-openai/src/services.js +43 -0
  45. package/packages/datadog-plugin-oracledb/src/index.js +3 -10
  46. package/packages/datadog-plugin-pg/src/index.js +3 -11
  47. package/packages/datadog-plugin-sharedb/src/index.js +1 -1
  48. package/packages/dd-trace/src/appsec/channels.js +1 -0
  49. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +3 -2
  50. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +12 -2
  51. package/packages/dd-trace/src/appsec/index.js +20 -0
  52. package/packages/dd-trace/src/appsec/passport.js +110 -0
  53. package/packages/dd-trace/src/appsec/sdk/track_event.js +14 -5
  54. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +17 -4
  55. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +45 -0
  56. package/packages/dd-trace/src/config.js +38 -1
  57. package/packages/dd-trace/src/constants.js +2 -0
  58. package/packages/dd-trace/src/data_streams_context.js +15 -0
  59. package/packages/dd-trace/src/datastreams/pathway.js +58 -0
  60. package/packages/dd-trace/src/datastreams/processor.js +194 -0
  61. package/packages/dd-trace/src/datastreams/writer.js +66 -0
  62. package/packages/dd-trace/src/dogstatsd.js +12 -4
  63. package/packages/dd-trace/src/external-logger/src/index.js +4 -0
  64. package/packages/dd-trace/src/opentelemetry/span.js +1 -0
  65. package/packages/dd-trace/src/opentracing/span.js +32 -0
  66. package/packages/dd-trace/src/opentracing/tracer.js +3 -1
  67. package/packages/dd-trace/src/plugin_manager.js +7 -2
  68. package/packages/dd-trace/src/plugins/client.js +1 -0
  69. package/packages/dd-trace/src/plugins/database.js +2 -1
  70. package/packages/dd-trace/src/plugins/index.js +2 -0
  71. package/packages/dd-trace/src/plugins/outbound.js +59 -1
  72. package/packages/dd-trace/src/plugins/server.js +2 -0
  73. package/packages/dd-trace/src/plugins/tracing.js +5 -1
  74. package/packages/dd-trace/src/plugins/util/exec.js +2 -0
  75. package/packages/dd-trace/src/plugins/util/git.js +38 -10
  76. package/packages/dd-trace/src/plugins/util/user-provided-git.js +36 -2
  77. package/packages/dd-trace/src/profiling/config.js +34 -7
  78. package/packages/dd-trace/src/proxy.js +6 -0
  79. package/packages/dd-trace/src/service-naming/index.js +13 -1
  80. package/packages/dd-trace/src/service-naming/schemas/v0/index.js +2 -1
  81. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +34 -1
  82. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +27 -0
  83. package/packages/dd-trace/src/service-naming/schemas/v1/index.js +2 -1
  84. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +31 -0
  85. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +26 -0
  86. package/packages/dd-trace/src/telemetry/index.js +3 -0
  87. package/packages/dd-trace/src/telemetry/metrics.js +281 -0
  88. package/packages/dd-trace/src/tracer.js +19 -1
@@ -0,0 +1,43 @@
1
+ 'use strict'
2
+
3
+ const DogStatsDClient = require('../../dd-trace/src/dogstatsd')
4
+ const ExternalLogger = require('../../dd-trace/src/external-logger/src')
5
+
6
+ const FLUSH_INTERVAL = 10 * 1000
7
+
8
+ let metrics = null
9
+ let logger = null
10
+ let interval = null
11
+
12
+ module.exports.init = function (tracerConfig) {
13
+ metrics = new DogStatsDClient({
14
+ host: tracerConfig.dogstatsd.hostname,
15
+ port: tracerConfig.dogstatsd.port,
16
+ tags: [
17
+ `service:${tracerConfig.tags.service}`,
18
+ `env:${tracerConfig.tags.env}`,
19
+ `version:${tracerConfig.tags.version}`
20
+ ]
21
+ })
22
+
23
+ logger = new ExternalLogger({
24
+ ddsource: 'openai',
25
+ hostname: tracerConfig.hostname,
26
+ service: tracerConfig.service,
27
+ apiKey: tracerConfig.apiKey,
28
+ interval: FLUSH_INTERVAL
29
+ })
30
+
31
+ interval = setInterval(() => {
32
+ metrics.flush()
33
+ }, FLUSH_INTERVAL).unref()
34
+
35
+ return { metrics, logger }
36
+ }
37
+
38
+ module.exports.shutdown = function () {
39
+ clearInterval(interval)
40
+ metrics = null
41
+ logger = null
42
+ interval = null
43
+ }
@@ -7,12 +7,13 @@ const log = require('../../dd-trace/src/log')
7
7
  class OracledbPlugin extends DatabasePlugin {
8
8
  static get id () { return 'oracledb' }
9
9
  static get system () { return 'oracle' }
10
+ static get peerServicePrecursors () { return ['db.instance', 'db.hostname'] }
10
11
 
11
12
  start ({ query, connAttrs }) {
12
- const service = getServiceName(this.config, connAttrs)
13
+ const service = this.serviceName(this.config, connAttrs)
13
14
  const url = getUrl(connAttrs.connectString)
14
15
 
15
- this.startSpan('oracle.query', {
16
+ this.startSpan(this.operationName(), {
16
17
  service,
17
18
  resource: query,
18
19
  type: 'sql',
@@ -27,14 +28,6 @@ class OracledbPlugin extends DatabasePlugin {
27
28
  }
28
29
  }
29
30
 
30
- function getServiceName (config, connAttrs) {
31
- if (typeof config.service === 'function') {
32
- return config.service(connAttrs)
33
- }
34
-
35
- return config.service
36
- }
37
-
38
31
  // TODO: Avoid creating an error since it's a heavy operation.
39
32
  function getUrl (connectString) {
40
33
  try {
@@ -9,10 +9,10 @@ class PGPlugin extends DatabasePlugin {
9
9
  static get system () { return 'postgres' }
10
10
 
11
11
  start ({ params = {}, query, processId }) {
12
- const service = getServiceName(this, params)
12
+ const service = this.serviceName(this.config, params)
13
13
  const originalStatement = query.text
14
14
 
15
- this.startSpan('pg.query', {
15
+ this.startSpan(this.operationName(), {
16
16
  service,
17
17
  resource: originalStatement,
18
18
  type: 'sql',
@@ -27,16 +27,8 @@ class PGPlugin extends DatabasePlugin {
27
27
  }
28
28
  })
29
29
 
30
- query.text = this.injectDbmQuery(query.text, service, !!query.name)
30
+ query.__ddInjectableQuery = this.injectDbmQuery(query.text, service, !!query.name)
31
31
  }
32
32
  }
33
33
 
34
- function getServiceName (tracer, params) {
35
- if (typeof tracer.config.service === 'function') {
36
- return tracer.config.service(params)
37
- }
38
-
39
- return tracer.config.service || `${tracer._tracer._tracer._service}-postgres`
40
- }
41
-
42
34
  module.exports = PGPlugin
@@ -25,7 +25,7 @@ class SharedbPlugin extends ServerPlugin {
25
25
  if (this.config.hooks && this.config.hooks.reply) {
26
26
  this.config.hooks.reply(span, request, res)
27
27
  }
28
- span.finish()
28
+ super.finish()
29
29
  }
30
30
  }
31
31
 
@@ -7,6 +7,7 @@ module.exports = {
7
7
  bodyParser: dc.channel('datadog:body-parser:read:finish'),
8
8
  incomingHttpRequestStart: dc.channel('dd-trace:incomingHttpRequestStart'),
9
9
  incomingHttpRequestEnd: dc.channel('dd-trace:incomingHttpRequestEnd'),
10
+ passportVerify: dc.channel('datadog:passport:verify:finish'),
10
11
  queryParser: dc.channel('datadog:query:read:finish'),
11
12
  setCookieChannel: dc.channel('datadog:iast:set-cookie')
12
13
  }
@@ -2,9 +2,10 @@
2
2
 
3
3
  module.exports = {
4
4
  HTTP_REQUEST_BODY: 'http.request.body',
5
- HTTP_REQUEST_PARAMETER: 'http.request.parameter',
6
5
  HTTP_REQUEST_COOKIE_VALUE: 'http.request.cookie.value',
7
6
  HTTP_REQUEST_COOKIE_NAME: 'http.request.cookie.name',
8
7
  HTTP_REQUEST_HEADER_NAME: 'http.request.header.name',
9
- HTTP_REQUEST_HEADER_VALUE: 'http.request.header'
8
+ HTTP_REQUEST_HEADER_VALUE: 'http.request.header',
9
+ HTTP_REQUEST_PARAMETER: 'http.request.parameter',
10
+ HTTP_REQUEST_PATH_PARAM: 'http.request.path.parameter'
10
11
  }
@@ -5,12 +5,14 @@ const { getIastContext } = require('../iast-context')
5
5
  const { storage } = require('../../../../../datadog-core')
6
6
  const { taintObject } = require('./operations')
7
7
  const {
8
- HTTP_REQUEST_PARAMETER,
9
8
  HTTP_REQUEST_BODY,
10
9
  HTTP_REQUEST_COOKIE_VALUE,
11
10
  HTTP_REQUEST_COOKIE_NAME,
12
11
  HTTP_REQUEST_HEADER_VALUE,
13
- HTTP_REQUEST_HEADER_NAME
12
+ HTTP_REQUEST_HEADER_NAME,
13
+ HTTP_REQUEST_PARAMETER,
14
+ HTTP_REQUEST_PATH_PARAM
15
+
14
16
  } = require('./origin-types')
15
17
 
16
18
  class TaintTrackingPlugin extends Plugin {
@@ -44,6 +46,14 @@ class TaintTrackingPlugin extends Plugin {
44
46
  'datadog:cookie:parse:finish',
45
47
  ({ cookies }) => this._cookiesTaintTrackingHandler(cookies)
46
48
  )
49
+ this.addSub(
50
+ 'datadog:express:process_params:start',
51
+ ({ req }) => {
52
+ if (req && req.params && typeof req.params === 'object') {
53
+ this._taintTrackingHandler(HTTP_REQUEST_PATH_PARAM, req, 'params')
54
+ }
55
+ }
56
+ )
47
57
  }
48
58
 
49
59
  _taintTrackingHandler (type, target, property, iastContext = getIastContext(storage.getStore())) {
@@ -7,6 +7,7 @@ const {
7
7
  incomingHttpRequestStart,
8
8
  incomingHttpRequestEnd,
9
9
  bodyParser,
10
+ passportVerify,
10
11
  queryParser
11
12
  } = require('./channels')
12
13
  const waf = require('./waf')
@@ -16,6 +17,8 @@ const web = require('../plugins/util/web')
16
17
  const { extractIp } = require('../plugins/util/ip_extractor')
17
18
  const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
18
19
  const { block, setTemplates } = require('./blocking')
20
+ const { passportTrackEvent } = require('./passport')
21
+ const { storage } = require('../../../datadog-core')
19
22
 
20
23
  let isEnabled = false
21
24
  let config
@@ -37,6 +40,10 @@ function enable (_config) {
37
40
  bodyParser.subscribe(onRequestBodyParsed)
38
41
  queryParser.subscribe(onRequestQueryParsed)
39
42
 
43
+ if (_config.appsec.eventTracking.enabled) {
44
+ passportVerify.subscribe(onPassportVerify)
45
+ }
46
+
40
47
  isEnabled = true
41
48
  config = _config
42
49
  } catch (err) {
@@ -139,6 +146,18 @@ function onRequestQueryParsed ({ req, res, abortController }) {
139
146
  handleResults(results, req, res, rootSpan, abortController)
140
147
  }
141
148
 
149
+ function onPassportVerify ({ credentials, user }) {
150
+ const store = storage.getStore()
151
+ const rootSpan = store && store.req && web.root(store.req)
152
+
153
+ if (!rootSpan) {
154
+ log.warn('No rootSpan found in onPassportVerify')
155
+ return
156
+ }
157
+
158
+ passportTrackEvent(credentials, user, rootSpan, config.appsec.eventTracking.mode)
159
+ }
160
+
142
161
  function handleResults (actions, req, res, rootSpan, abortController) {
143
162
  if (!actions || !req || !res || !rootSpan || !abortController) return
144
163
 
@@ -160,6 +179,7 @@ function disable () {
160
179
  if (incomingHttpRequestEnd.hasSubscribers) incomingHttpRequestEnd.unsubscribe(incomingHttpEndTranslator)
161
180
  if (bodyParser.hasSubscribers) bodyParser.unsubscribe(onRequestBodyParsed)
162
181
  if (queryParser.hasSubscribers) queryParser.unsubscribe(onRequestQueryParsed)
182
+ if (passportVerify.hasSubscribers) passportVerify.unsubscribe(onPassportVerify)
163
183
  }
164
184
 
165
185
  module.exports = {
@@ -0,0 +1,110 @@
1
+ 'use strict'
2
+
3
+ const log = require('../log')
4
+ const { trackEvent } = require('./sdk/track_event')
5
+ const { setUserTags } = require('./sdk/set_user')
6
+
7
+ const UUID_PATTERN = '^[0-9A-F]{8}-[0-9A-F]{4}-[1-5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$'
8
+ const regexUsername = new RegExp(UUID_PATTERN, 'i')
9
+
10
+ const SDK_USER_EVENT_PATTERN = '^_dd\\.appsec\\.events\\.users\\.[\\W\\w+]+\\.sdk$'
11
+ const regexSdkEvent = new RegExp(SDK_USER_EVENT_PATTERN, 'i')
12
+
13
+ function isSdkCalled (tags) {
14
+ let called = false
15
+
16
+ if (tags && typeof tags === 'object') {
17
+ called = Object.entries(tags).some(([key, value]) => regexSdkEvent.test(key) && value === 'true')
18
+ }
19
+
20
+ return called
21
+ }
22
+
23
+ // delete this function later if we know it's always credential.username
24
+ function getLogin (credentials) {
25
+ const type = credentials && credentials.type
26
+ let login
27
+ if (type === 'local' || type === 'http') {
28
+ login = credentials.username
29
+ }
30
+
31
+ return login
32
+ }
33
+
34
+ function parseUser (login, passportUser, mode) {
35
+ const user = {
36
+ 'usr.id': login
37
+ }
38
+
39
+ if (!user['usr.id']) {
40
+ return user
41
+ }
42
+
43
+ if (passportUser) {
44
+ // Guess id
45
+ if (passportUser.id) {
46
+ user['usr.id'] = passportUser.id
47
+ } else if (passportUser._id) {
48
+ user['usr.id'] = passportUser._id
49
+ }
50
+
51
+ if (mode === 'extended') {
52
+ if (login) {
53
+ user['usr.login'] = login
54
+ }
55
+
56
+ if (passportUser.email) {
57
+ user['usr.email'] = passportUser.email
58
+ }
59
+
60
+ // Guess username
61
+ if (passportUser.username) {
62
+ user['usr.username'] = passportUser.username
63
+ } else if (passportUser.name) {
64
+ user['usr.username'] = passportUser.name
65
+ }
66
+ }
67
+ }
68
+
69
+ if (mode === 'safe') {
70
+ // Remove PII in safe mode
71
+ if (!regexUsername.test(user['usr.id'])) {
72
+ user['usr.id'] = ' '
73
+ }
74
+ }
75
+
76
+ return user
77
+ }
78
+
79
+ function passportTrackEvent (credentials, passportUser, rootSpan, mode) {
80
+ const tags = rootSpan && rootSpan.context() && rootSpan.context()._tags
81
+
82
+ if (isSdkCalled(tags)) {
83
+ // Don't overwrite tags set by SDK callings
84
+ return
85
+ }
86
+ const user = parseUser(getLogin(credentials), passportUser, mode)
87
+
88
+ if (user['usr.id'] === undefined) {
89
+ log.warn('No user ID found in authentication instrumentation')
90
+ return
91
+ }
92
+
93
+ if (passportUser) {
94
+ // If a passportUser object is published then the login succeded
95
+ const userTags = {}
96
+ Object.entries(user).forEach(([k, v]) => {
97
+ const attr = k.split('.', 2)[1]
98
+ userTags[attr] = v
99
+ })
100
+
101
+ setUserTags(userTags, rootSpan)
102
+ trackEvent('users.login.success', null, 'passportTrackEvent', rootSpan, mode)
103
+ } else {
104
+ trackEvent('users.login.failure', user, 'passportTrackEvent', rootSpan, mode)
105
+ }
106
+ }
107
+
108
+ module.exports = {
109
+ passportTrackEvent
110
+ }
@@ -20,7 +20,7 @@ function trackUserLoginSuccessEvent (tracer, user, metadata) {
20
20
 
21
21
  setUserTags(user, rootSpan)
22
22
 
23
- trackEvent(tracer, 'users.login.success', metadata, 'trackUserLoginSuccessEvent', rootSpan)
23
+ trackEvent('users.login.success', metadata, 'trackUserLoginSuccessEvent', rootSpan, 'sdk')
24
24
  }
25
25
 
26
26
  function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
@@ -35,7 +35,7 @@ function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
35
35
  ...metadata
36
36
  }
37
37
 
38
- trackEvent(tracer, 'users.login.failure', fields, 'trackUserLoginFailureEvent')
38
+ trackEvent('users.login.failure', fields, 'trackUserLoginFailureEvent', getRootSpan(tracer), 'sdk')
39
39
  }
40
40
 
41
41
  function trackCustomEvent (tracer, eventName, metadata) {
@@ -44,10 +44,10 @@ function trackCustomEvent (tracer, eventName, metadata) {
44
44
  return
45
45
  }
46
46
 
47
- trackEvent(tracer, eventName, metadata, 'trackCustomEvent')
47
+ trackEvent(eventName, metadata, 'trackCustomEvent', getRootSpan(tracer), 'sdk')
48
48
  }
49
49
 
50
- function trackEvent (tracer, eventName, fields, sdkMethodName, rootSpan = getRootSpan(tracer)) {
50
+ function trackEvent (eventName, fields, sdkMethodName, rootSpan, mode) {
51
51
  if (!rootSpan) {
52
52
  log.warn(`Root span not available in ${sdkMethodName}`)
53
53
  return
@@ -58,6 +58,14 @@ function trackEvent (tracer, eventName, fields, sdkMethodName, rootSpan = getRoo
58
58
  [MANUAL_KEEP]: 'true'
59
59
  }
60
60
 
61
+ if (mode === 'sdk') {
62
+ tags[`_dd.appsec.events.${eventName}.sdk`] = 'true'
63
+ }
64
+
65
+ if (mode === 'safe' || mode === 'extended') {
66
+ tags[`_dd.appsec.events.${eventName}.auto.mode`] = mode
67
+ }
68
+
61
69
  if (fields) {
62
70
  for (const metadataKey of Object.keys(fields)) {
63
71
  tags[`appsec.events.${eventName}.${metadataKey}`] = '' + fields[metadataKey]
@@ -70,5 +78,6 @@ function trackEvent (tracer, eventName, fields, sdkMethodName, rootSpan = getRoo
70
78
  module.exports = {
71
79
  trackUserLoginSuccessEvent,
72
80
  trackUserLoginFailureEvent,
73
- trackCustomEvent
81
+ trackCustomEvent,
82
+ trackEvent
74
83
  }
@@ -48,7 +48,8 @@ function getCommonRequestOptions (url) {
48
48
  */
49
49
  function getCommitsToExclude ({ url, isEvpProxy, repositoryUrl }, callback) {
50
50
  const latestCommits = getLatestCommits()
51
- const [headCommit] = latestCommits
51
+
52
+ log.debug(`There were ${latestCommits.length} commits since last month.`)
52
53
 
53
54
  const commonOptions = getCommonRequestOptions(url)
54
55
 
@@ -88,7 +89,7 @@ function getCommitsToExclude ({ url, isEvpProxy, repositoryUrl }, callback) {
88
89
  } catch (e) {
89
90
  return callback(new Error(`Can't parse commits to exclude response: ${e.message}`))
90
91
  }
91
- callback(null, commitsToExclude, headCommit)
92
+ callback(null, commitsToExclude, latestCommits)
92
93
  })
93
94
  }
94
95
 
@@ -158,26 +159,38 @@ function sendGitMetadata (url, isEvpProxy, configRepositoryUrl, callback) {
158
159
  repositoryUrl = getRepositoryUrl()
159
160
  }
160
161
 
162
+ log.debug(`Uploading git history for repository ${repositoryUrl}`)
163
+
161
164
  if (!repositoryUrl) {
162
165
  return callback(new Error('Repository URL is empty'))
163
166
  }
164
167
 
165
168
  if (isShallowRepository()) {
169
+ log.debug('It is shallow clone, unshallowing...')
166
170
  unshallowRepository()
167
171
  }
168
172
 
169
- getCommitsToExclude({ url, repositoryUrl, isEvpProxy }, (err, commitsToExclude, headCommit) => {
173
+ getCommitsToExclude({ url, repositoryUrl, isEvpProxy }, (err, commitsToExclude, latestCommits) => {
170
174
  if (err) {
171
175
  return callback(err)
172
176
  }
173
- const commitsToUpload = getCommitsToUpload(commitsToExclude)
177
+ log.debug(`There are ${commitsToExclude.length} commits to exclude.`)
178
+ const [headCommit] = latestCommits
179
+ const commitsToInclude = latestCommits.filter((commit) => !commitsToExclude.includes(commit))
180
+ log.debug(`There are ${commitsToInclude.length} commits to include.`)
181
+
182
+ const commitsToUpload = getCommitsToUpload(commitsToExclude, commitsToInclude)
174
183
 
175
184
  if (!commitsToUpload.length) {
176
185
  log.debug('No commits to upload')
177
186
  return callback(null)
178
187
  }
188
+ log.debug(`There are ${commitsToUpload.length} commits to upload`)
189
+
179
190
  const packFilesToUpload = generatePackFilesForCommits(commitsToUpload)
180
191
 
192
+ log.debug(`Uploading ${packFilesToUpload.length} packfiles.`)
193
+
181
194
  if (!packFilesToUpload.length) {
182
195
  return callback(new Error('Failed to generate packfiles'))
183
196
  }
@@ -0,0 +1,45 @@
1
+ const CiPlugin = require('../../plugins/ci_plugin')
2
+ const {
3
+ TEST_STATUS,
4
+ finishAllTraceSpans,
5
+ getTestSuitePath
6
+ } = require('../../plugins/util/test')
7
+ const { storage } = require('../../../../datadog-core')
8
+
9
+ class TestApiManualPlugin extends CiPlugin {
10
+ static get id () {
11
+ return 'test-api-manual'
12
+ }
13
+ constructor (...args) {
14
+ super(...args)
15
+ this.sourceRoot = process.cwd()
16
+
17
+ this.addSub('dd-trace:ci:manual:test:start', ({ testName, testSuite }) => {
18
+ const store = storage.getStore()
19
+ const testSuiteRelative = getTestSuitePath(testSuite, this.sourceRoot)
20
+ const testSpan = this.startTestSpan(testName, testSuiteRelative)
21
+ this.enter(testSpan, store)
22
+ })
23
+ this.addSub('dd-trace:ci:manual:test:finish', ({ status, error }) => {
24
+ const store = storage.getStore()
25
+ const testSpan = store && store.span
26
+ if (testSpan) {
27
+ testSpan.setTag(TEST_STATUS, status)
28
+ if (error) {
29
+ testSpan.setTag('error', error)
30
+ }
31
+ testSpan.finish()
32
+ finishAllTraceSpans(testSpan)
33
+ }
34
+ })
35
+ this.addSub('dd-trace:ci:manual:test:addTags', (tags) => {
36
+ const store = storage.getStore()
37
+ const testSpan = store && store.span
38
+ if (testSpan) {
39
+ testSpan.addTags(tags)
40
+ }
41
+ })
42
+ }
43
+ }
44
+
45
+ module.exports = TestApiManualPlugin
@@ -141,6 +141,11 @@ class Config {
141
141
  process.env.DD_DBM_PROPAGATION_MODE,
142
142
  'disabled'
143
143
  )
144
+ const DD_DATA_STREAMS_ENABLED = coalesce(
145
+ options.dsmEnabled,
146
+ process.env.DD_DATA_STREAMS_ENABLED,
147
+ false
148
+ )
144
149
  const DD_AGENT_HOST = coalesce(
145
150
  options.hostname,
146
151
  process.env.DD_AGENT_HOST,
@@ -169,6 +174,11 @@ class Config {
169
174
  true
170
175
  )
171
176
 
177
+ const DD_CIVISIBILITY_MANUAL_API_ENABLED = coalesce(
178
+ process.env.DD_CIVISIBILITY_MANUAL_API_ENABLED,
179
+ false
180
+ )
181
+
172
182
  const DD_SERVICE = options.service ||
173
183
  process.env.DD_SERVICE ||
174
184
  process.env.DD_SERVICE_NAME ||
@@ -227,6 +237,9 @@ class Config {
227
237
  const DD_TELEMETRY_HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
228
238
  ? parseInt(process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL) * 1000
229
239
  : 60000
240
+ const DD_OPENAI_SPAN_CHAR_LIMIT = process.env.DD_OPENAI_SPAN_CHAR_LIMIT
241
+ ? parseInt(process.env.DD_OPENAI_SPAN_CHAR_LIMIT)
242
+ : 128
230
243
  const DD_TELEMETRY_DEBUG = coalesce(
231
244
  process.env.DD_TELEMETRY_DEBUG,
232
245
  false
@@ -303,6 +316,12 @@ class Config {
303
316
  const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
304
317
  process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
305
318
  )
319
+ const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
320
+
321
+ const DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED = coalesce(
322
+ isTrue(process.env.DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED),
323
+ false
324
+ )
306
325
  const DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH = coalesce(
307
326
  process.env.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
308
327
  '512'
@@ -377,6 +396,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
377
396
  maybeFile(appsec.blockedTemplateJson),
378
397
  maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
379
398
  )
399
+ const DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING = coalesce(
400
+ appsec.eventTracking && appsec.eventTracking.mode,
401
+ process.env.DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
402
+ 'safe'
403
+ ).toLowerCase()
380
404
 
381
405
  const remoteConfigOptions = options.remoteConfig || {}
382
406
  const DD_REMOTE_CONFIGURATION_ENABLED = coalesce(
@@ -479,6 +503,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
479
503
 
480
504
  this.tracing = !isFalse(DD_TRACING_ENABLED)
481
505
  this.dbmPropagationMode = DD_DBM_PROPAGATION_MODE
506
+ this.dsmEnabled = isTrue(DD_DATA_STREAMS_ENABLED)
482
507
  this.openAiLogsEnabled = DD_OPENAI_LOGS_ENABLED
483
508
  this.apiKey = DD_API_KEY
484
509
  this.logInjection = isTrue(DD_LOGS_INJECTION)
@@ -521,6 +546,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
521
546
  exporters: DD_PROFILING_EXPORTERS
522
547
  }
523
548
  this.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
549
+ this.spanComputePeerService = (this.spanAttributeSchema === 'v0'
550
+ ? isTrue(DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED)
551
+ : true
552
+ )
553
+ this.traceRemoveIntegrationServiceNamesEnabled = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
524
554
  this.lookup = options.lookup
525
555
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
526
556
  // Disabled for CI Visibility's agentless
@@ -541,7 +571,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
541
571
  obfuscatorKeyRegex: DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
542
572
  obfuscatorValueRegex: DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
543
573
  blockedTemplateHtml: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
544
- blockedTemplateJson: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON
574
+ blockedTemplateJson: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
575
+ eventTracking: {
576
+ enabled: ['extended', 'safe'].includes(DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING),
577
+ mode: DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING
578
+ }
545
579
  }
546
580
  this.remoteConfig = {
547
581
  enabled: DD_REMOTE_CONFIGURATION_ENABLED,
@@ -563,6 +597,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
563
597
  (this.isIntelligentTestRunnerEnabled && !isFalse(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED))
564
598
 
565
599
  this.gitMetadataEnabled = isTrue(DD_TRACE_GIT_METADATA_ENABLED)
600
+ this.isManualApiEnabled = this.isCiVisibility && isTrue(DD_CIVISIBILITY_MANUAL_API_ENABLED)
601
+
602
+ this.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
566
603
 
567
604
  if (this.gitMetadataEnabled) {
568
605
  this.repositoryUrl = coalesce(
@@ -26,6 +26,8 @@ module.exports = {
26
26
  ERROR_STACK: 'error.stack',
27
27
  COMPONENT: 'component',
28
28
  CLIENT_PORT_KEY: 'network.destination.port',
29
+ PEER_SERVICE_KEY: 'peer.service',
30
+ PEER_SERVICE_SOURCE_KEY: '_dd.peer.service.source',
29
31
  SCI_REPOSITORY_URL: '_dd.git.repository_url',
30
32
  SCI_COMMIT_SHA: '_dd.git.commit.sha'
31
33
  }
@@ -0,0 +1,15 @@
1
+ const { storage } = require('../../datadog-core')
2
+
3
+ function getDataStreamsContext () {
4
+ const store = storage.getStore()
5
+ return (store && store.dataStreamsContext) || null
6
+ }
7
+
8
+ function setDataStreamsContext (dataStreamsContext) {
9
+ storage.enterWith({ ...(storage.getStore()), dataStreamsContext })
10
+ }
11
+
12
+ module.exports = {
13
+ getDataStreamsContext,
14
+ setDataStreamsContext
15
+ }
@@ -0,0 +1,58 @@
1
+ // encoding used here is sha256
2
+ // other languages use FNV1
3
+ // this inconsistency is ok because hashes do not need to be consistent across services
4
+ const crypto = require('crypto')
5
+ const { encodeVarint, decodeVarint } = require('./encoding')
6
+ const LRUCache = require('lru-cache')
7
+
8
+ const options = { max: 500 }
9
+ const cache = new LRUCache(options)
10
+
11
+ function shaHash (checkpointString) {
12
+ const hash = crypto.createHash('md5').update(checkpointString).digest('hex').slice(0, 16)
13
+ return Buffer.from(hash, 'hex')
14
+ }
15
+
16
+ function computeHash (service, env, edgeTags, parentHash) {
17
+ const key = `${service}${env}` + edgeTags.join('') + parentHash.toString()
18
+ if (cache.get(key)) {
19
+ return cache.get(key)
20
+ }
21
+ const currentHash = shaHash(`${service}${env}` + edgeTags.join(''))
22
+ const buf = Buffer.concat([ currentHash, parentHash ], 16)
23
+ const val = shaHash(buf.toString())
24
+ cache.set(key, val)
25
+ return val
26
+ }
27
+
28
+ function encodePathwayContext (dataStreamsContext) {
29
+ return Buffer.concat([
30
+ dataStreamsContext.hash,
31
+ Buffer.from(encodeVarint(Math.round(dataStreamsContext.pathwayStartNs / 1e6))),
32
+ Buffer.from(encodeVarint(Math.round(dataStreamsContext.edgeStartNs / 1e6)))
33
+ ], 20)
34
+ }
35
+
36
+ function decodePathwayContext (pathwayContext) {
37
+ if (pathwayContext == null || pathwayContext.length < 8) {
38
+ return null
39
+ }
40
+ // hash and parent hash are in LE
41
+ const pathwayHash = pathwayContext.subarray(0, 8)
42
+ const encodedTimestamps = pathwayContext.subarray(8)
43
+ const [pathwayStartMs, encodedTimeSincePrev] = decodeVarint(encodedTimestamps)
44
+ if (pathwayStartMs === undefined) {
45
+ return null
46
+ }
47
+ const [edgeStartMs] = decodeVarint(encodedTimeSincePrev)
48
+ if (edgeStartMs === undefined) {
49
+ return null
50
+ }
51
+ return { hash: pathwayHash, pathwayStartNs: pathwayStartMs * 1e6, edgeStartNs: edgeStartMs * 1e6 }
52
+ }
53
+
54
+ module.exports = {
55
+ computePathwayHash: computeHash,
56
+ encodePathwayContext,
57
+ decodePathwayContext
58
+ }