dd-trace 4.3.0 → 4.5.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
@@ -144,6 +144,11 @@ class Config {
144
144
  process.env.DD_DBM_PROPAGATION_MODE,
145
145
  'disabled'
146
146
  )
147
+ const DD_DATA_STREAMS_ENABLED = coalesce(
148
+ options.dsmEnabled,
149
+ process.env.DD_DATA_STREAMS_ENABLED,
150
+ false
151
+ )
147
152
  const DD_AGENT_HOST = coalesce(
148
153
  options.hostname,
149
154
  process.env.DD_AGENT_HOST,
@@ -172,6 +177,11 @@ class Config {
172
177
  true
173
178
  )
174
179
 
180
+ const DD_CIVISIBILITY_MANUAL_API_ENABLED = coalesce(
181
+ process.env.DD_CIVISIBILITY_MANUAL_API_ENABLED,
182
+ false
183
+ )
184
+
175
185
  const DD_SERVICE = options.service ||
176
186
  process.env.DD_SERVICE ||
177
187
  process.env.DD_SERVICE_NAME ||
@@ -230,6 +240,9 @@ class Config {
230
240
  const DD_TELEMETRY_HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
231
241
  ? parseInt(process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL) * 1000
232
242
  : 60000
243
+ const DD_OPENAI_SPAN_CHAR_LIMIT = process.env.DD_OPENAI_SPAN_CHAR_LIMIT
244
+ ? parseInt(process.env.DD_OPENAI_SPAN_CHAR_LIMIT)
245
+ : 128
233
246
  const DD_TELEMETRY_DEBUG = coalesce(
234
247
  process.env.DD_TELEMETRY_DEBUG,
235
248
  false
@@ -306,6 +319,12 @@ class Config {
306
319
  const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
307
320
  process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
308
321
  )
322
+ const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
323
+
324
+ const DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED = coalesce(
325
+ isTrue(process.env.DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED),
326
+ false
327
+ )
309
328
  const DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH = coalesce(
310
329
  process.env.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
311
330
  '512'
@@ -380,6 +399,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
380
399
  maybeFile(appsec.blockedTemplateJson),
381
400
  maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
382
401
  )
402
+ const DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING = coalesce(
403
+ appsec.eventTracking && appsec.eventTracking.mode,
404
+ process.env.DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
405
+ 'safe'
406
+ ).toLowerCase()
383
407
 
384
408
  const remoteConfigOptions = options.remoteConfig || {}
385
409
  const DD_REMOTE_CONFIGURATION_ENABLED = coalesce(
@@ -482,6 +506,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
482
506
 
483
507
  this.tracing = !isFalse(DD_TRACING_ENABLED)
484
508
  this.dbmPropagationMode = DD_DBM_PROPAGATION_MODE
509
+ this.dsmEnabled = isTrue(DD_DATA_STREAMS_ENABLED)
485
510
  this.openAiLogsEnabled = DD_OPENAI_LOGS_ENABLED
486
511
  this.apiKey = DD_API_KEY
487
512
  this.logInjection = isTrue(DD_LOGS_INJECTION)
@@ -524,6 +549,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
524
549
  exporters: DD_PROFILING_EXPORTERS
525
550
  }
526
551
  this.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
552
+ this.spanComputePeerService = (this.spanAttributeSchema === 'v0'
553
+ ? isTrue(DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED)
554
+ : true
555
+ )
556
+ this.traceRemoveIntegrationServiceNamesEnabled = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
527
557
  this.lookup = options.lookup
528
558
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
529
559
  // Disabled for CI Visibility's agentless
@@ -544,7 +574,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
544
574
  obfuscatorKeyRegex: DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
545
575
  obfuscatorValueRegex: DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
546
576
  blockedTemplateHtml: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
547
- blockedTemplateJson: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON
577
+ blockedTemplateJson: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
578
+ eventTracking: {
579
+ enabled: ['extended', 'safe'].includes(DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING),
580
+ mode: DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING
581
+ }
548
582
  }
549
583
  this.remoteConfig = {
550
584
  enabled: DD_REMOTE_CONFIGURATION_ENABLED,
@@ -566,6 +600,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
566
600
  (this.isIntelligentTestRunnerEnabled && !isFalse(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED))
567
601
 
568
602
  this.gitMetadataEnabled = isTrue(DD_TRACE_GIT_METADATA_ENABLED)
603
+ this.isManualApiEnabled = this.isCiVisibility && isTrue(DD_CIVISIBILITY_MANUAL_API_ENABLED)
604
+
605
+ this.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
569
606
 
570
607
  if (this.gitMetadataEnabled) {
571
608
  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
+ }