dd-trace 2.4.2 → 2.6.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 (53) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ci/init.js +6 -0
  3. package/ci/jest/env.js +16 -3
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +17 -1
  7. package/package.json +5 -4
  8. package/packages/datadog-instrumentations/index.js +1 -0
  9. package/packages/datadog-instrumentations/src/cypress.js +8 -0
  10. package/packages/datadog-instrumentations/src/jest.js +170 -0
  11. package/packages/datadog-plugin-aws-sdk/src/helpers.js +4 -4
  12. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
  13. package/packages/datadog-plugin-cucumber/src/index.js +16 -16
  14. package/packages/datadog-plugin-cypress/src/index.js +10 -5
  15. package/packages/datadog-plugin-cypress/src/plugin.js +18 -17
  16. package/packages/datadog-plugin-fs/src/index.js +2 -0
  17. package/packages/datadog-plugin-http/src/server.js +0 -8
  18. package/packages/datadog-plugin-jest/src/index.js +101 -3
  19. package/packages/datadog-plugin-jest/src/util.js +1 -29
  20. package/packages/datadog-plugin-mocha/src/index.js +14 -15
  21. package/packages/dd-trace/lib/version.js +1 -1
  22. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +29 -12
  23. package/packages/dd-trace/src/appsec/index.js +7 -3
  24. package/packages/dd-trace/src/appsec/recommended.json +15 -5
  25. package/packages/dd-trace/src/appsec/reporter.js +29 -3
  26. package/packages/dd-trace/src/appsec/rule_manager.js +2 -2
  27. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +32 -0
  28. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +51 -0
  29. package/packages/dd-trace/src/config.js +33 -4
  30. package/packages/dd-trace/src/encode/0.4.js +0 -1
  31. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +193 -0
  32. package/packages/dd-trace/src/encode/tags-processors.js +116 -0
  33. package/packages/dd-trace/src/exporter.js +3 -0
  34. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  35. package/packages/dd-trace/src/exporters/agent/writer.js +7 -32
  36. package/packages/dd-trace/src/exporters/{agent → common}/docker.js +0 -0
  37. package/packages/dd-trace/src/exporters/common/request.js +83 -0
  38. package/packages/dd-trace/src/exporters/common/writer.js +36 -0
  39. package/packages/dd-trace/src/exporters/{agent/scheduler.js → scheduler.js} +0 -0
  40. package/packages/dd-trace/src/format.js +9 -5
  41. package/packages/dd-trace/src/instrumenter.js +3 -0
  42. package/packages/dd-trace/src/pkg.js +11 -6
  43. package/packages/dd-trace/src/plugins/util/test.js +79 -1
  44. package/packages/dd-trace/src/plugins/util/web.js +11 -10
  45. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  46. package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
  47. package/packages/dd-trace/src/proxy.js +2 -0
  48. package/packages/dd-trace/src/span_processor.js +4 -1
  49. package/packages/dd-trace/src/telemetry.js +187 -0
  50. package/scripts/install_plugin_modules.js +1 -0
  51. package/packages/datadog-plugin-jest/src/jest-environment.js +0 -272
  52. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +0 -185
  53. package/packages/dd-trace/src/exporters/agent/request.js +0 -86
@@ -1,8 +1,3 @@
1
- const { SAMPLING_RULE_DECISION } = require('../../dd-trace/src/constants')
2
- const { SAMPLING_PRIORITY, SPAN_TYPE } = require('../../../ext/tags')
3
- const { AUTO_KEEP } = require('../../../ext/priority')
4
- const { TEST_TYPE, TEST_STATUS, getTestParentSpan } = require('../../dd-trace/src/plugins/util/test')
5
-
6
1
  /**
7
2
  * There are two ways to call `test.each` in `jest`:
8
3
  * 1. With an array of arrays: https://jestjs.io/docs/api#1-testeachtablename-fn-timeout
@@ -38,27 +33,4 @@ function getFormattedJestTestParameters (testParameters) {
38
33
  return formattedParameters
39
34
  }
40
35
 
41
- function getTestSpanTags (tracer, testEnvironmentMetadata) {
42
- const childOf = getTestParentSpan(tracer)
43
-
44
- const commonSpanTags = {
45
- [TEST_TYPE]: 'test',
46
- [SAMPLING_RULE_DECISION]: 1,
47
- [SAMPLING_PRIORITY]: AUTO_KEEP,
48
- [SPAN_TYPE]: 'test',
49
- ...testEnvironmentMetadata
50
- }
51
- return {
52
- childOf,
53
- commonSpanTags
54
- }
55
- }
56
-
57
- function setSuppressedErrors (suppressedErrors, testSpan) {
58
- if (suppressedErrors && suppressedErrors.length) {
59
- testSpan.setTag('error', suppressedErrors[0])
60
- testSpan.setTag(TEST_STATUS, 'fail')
61
- }
62
- }
63
-
64
- module.exports = { getFormattedJestTestParameters, getTestSpanTags, setSuppressedErrors }
36
+ module.exports = { getFormattedJestTestParameters }
@@ -5,21 +5,19 @@ const { storage } = require('../../datadog-core')
5
5
 
6
6
  const {
7
7
  CI_APP_ORIGIN,
8
- TEST_TYPE,
9
- TEST_NAME,
8
+ TEST_CODE_OWNERS,
10
9
  TEST_SUITE,
11
- TEST_FRAMEWORK_VERSION,
12
10
  TEST_STATUS,
13
11
  TEST_PARAMETERS,
14
12
  finishAllTraceSpans,
15
13
  getTestEnvironmentMetadata,
16
14
  getTestSuitePath,
17
15
  getTestParentSpan,
18
- getTestParametersString
16
+ getTestParametersString,
17
+ getCodeOwnersFileEntries,
18
+ getCodeOwnersForFilename,
19
+ getTestCommonTags
19
20
  } = require('../../dd-trace/src/plugins/util/test')
20
- const { SPAN_TYPE, RESOURCE_NAME, SAMPLING_PRIORITY } = require('../../../ext/tags')
21
- const { SAMPLING_RULE_DECISION } = require('../../dd-trace/src/constants')
22
- const { AUTO_KEEP } = require('../../../ext/priority')
23
21
 
24
22
  const skippedTests = new WeakSet()
25
23
 
@@ -30,16 +28,11 @@ function getTestSpanMetadata (tracer, test, sourceRoot) {
30
28
  const fullTestName = test.fullTitle()
31
29
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, sourceRoot)
32
30
 
31
+ const commonTags = getTestCommonTags(fullTestName, testSuite, tracer._version)
32
+
33
33
  return {
34
34
  childOf,
35
- [SPAN_TYPE]: 'test',
36
- [TEST_TYPE]: 'test',
37
- [TEST_NAME]: fullTestName,
38
- [TEST_SUITE]: testSuite,
39
- [SAMPLING_RULE_DECISION]: 1,
40
- [SAMPLING_PRIORITY]: AUTO_KEEP,
41
- [TEST_FRAMEWORK_VERSION]: tracer._version,
42
- [RESOURCE_NAME]: `${testSuite}.${fullTestName}`
35
+ ...commonTags
43
36
  }
44
37
  }
45
38
 
@@ -54,6 +47,7 @@ class MochaPlugin extends Plugin {
54
47
  this._testNameToParams = {}
55
48
  this.testEnvironmentMetadata = getTestEnvironmentMetadata('mocha', this.config)
56
49
  this.sourceRoot = process.cwd()
50
+ this.codeOwnersEntries = getCodeOwnersFileEntries(this.sourceRoot)
57
51
 
58
52
  this.addSub('ci:mocha:test:start', (test) => {
59
53
  const store = storage.getStore()
@@ -139,6 +133,11 @@ class MochaPlugin extends Plugin {
139
133
  if (testParametersString) {
140
134
  testSpanMetadata[TEST_PARAMETERS] = testParametersString
141
135
  }
136
+ const codeOwners = getCodeOwnersForFilename(testSpanMetadata[TEST_SUITE], this.codeOwnersEntries)
137
+
138
+ if (codeOwners) {
139
+ testSpanMetadata[TEST_CODE_OWNERS] = codeOwners
140
+ }
142
141
 
143
142
  const testSpan = this.tracer
144
143
  .startSpan('mocha.test', {
@@ -1 +1 @@
1
- module.exports = '2.4.2'
1
+ module.exports = '2.6.0'
@@ -7,16 +7,14 @@ const Reporter = require('../reporter')
7
7
 
8
8
  const validAddressSet = new Set(Object.values(addresses))
9
9
 
10
- const DEFAULT_MAX_BUDGET = 5e3 // µs
11
-
12
10
  // TODO: put reusable code in a base class
13
11
  class WAFCallback {
14
- static loadDDWAF (rules) {
12
+ static loadDDWAF (rules, config) {
15
13
  try {
16
14
  // require in `try/catch` because this can throw at require time
17
15
  const { DDWAF } = require('@datadog/native-appsec')
18
16
 
19
- return new DDWAF(rules)
17
+ return new DDWAF(rules, config)
20
18
  } catch (err) {
21
19
  log.error('AppSec could not load native package. In-app WAF features will not be available.')
22
20
 
@@ -24,8 +22,24 @@ class WAFCallback {
24
22
  }
25
23
  }
26
24
 
27
- constructor (rules) {
28
- this.ddwaf = WAFCallback.loadDDWAF(rules)
25
+ constructor (rules, config) {
26
+ const { wafTimeout, obfuscatorKeyRegex, obfuscatorValueRegex } = config
27
+
28
+ this.ddwaf = WAFCallback.loadDDWAF(rules, { obfuscatorKeyRegex, obfuscatorValueRegex })
29
+
30
+ this.wafTimeout = wafTimeout
31
+
32
+ const version = this.ddwaf.constructor.version()
33
+
34
+ Reporter.metricsQueue.set('_dd.appsec.waf.version', `${version.major}.${version.minor}.${version.patch}`)
35
+
36
+ const { loaded, failed } = this.ddwaf.rulesInfo
37
+
38
+ Reporter.metricsQueue.set('_dd.appsec.event_rules.loaded', loaded)
39
+ Reporter.metricsQueue.set('_dd.appsec.event_rules.error_count', failed)
40
+
41
+ Reporter.metricsQueue.set('manual.keep', true)
42
+
29
43
  this.wafContextCache = new WeakMap()
30
44
 
31
45
  // closures are faster than binds
@@ -70,7 +84,7 @@ class WAFCallback {
70
84
  }
71
85
  }
72
86
 
73
- if (!wafContext) {
87
+ if (!wafContext || wafContext.disposed) {
74
88
  wafContext = this.ddwaf.createContext()
75
89
  }
76
90
 
@@ -81,23 +95,26 @@ class WAFCallback {
81
95
 
82
96
  try {
83
97
  // TODO: possible optimizaion: only send params that haven't already been sent to this wafContext
84
- const result = wafContext.run(params, DEFAULT_MAX_BUDGET)
98
+ const result = wafContext.run(params, this.wafTimeout)
85
99
 
86
100
  return this.applyResult(result, store)
87
101
  } catch (err) {
88
102
  log.error('Error while running the AppSec WAF')
89
103
  log.error(err)
104
+ } finally {
105
+ wafContext.dispose()
90
106
  }
91
107
  }
92
108
 
93
109
  applyResult (result, store) {
110
+ Reporter.reportMetrics({
111
+ duration: result.totalRuntime,
112
+ rulesVersion: this.ddwaf.rulesInfo.version
113
+ }, store)
114
+
94
115
  if (result.data && result.data !== '[]') {
95
116
  Reporter.reportAttack(result.data, store)
96
117
  }
97
-
98
- // TODO: use these values later for budget management
99
- // result.perfData
100
- // result.perfTotalRuntime
101
118
  }
102
119
 
103
120
  clear () {
@@ -16,7 +16,7 @@ function enable (config) {
16
16
  let rules = fs.readFileSync(config.appsec.rules)
17
17
  rules = JSON.parse(rules)
18
18
 
19
- RuleManager.applyRules(rules)
19
+ RuleManager.applyRules(rules, config.appsec)
20
20
  } catch (err) {
21
21
  log.error('Unable to start AppSec')
22
22
  log.error(err)
@@ -94,12 +94,16 @@ function incomingHttpEndTranslator (data) {
94
94
  }
95
95
 
96
96
  if (data.req.cookies && typeof data.req.cookies === 'object') {
97
- payload[addresses.HTTP_INCOMING_COOKIES] = data.req.cookies
97
+ payload[addresses.HTTP_INCOMING_COOKIES] = {}
98
+
99
+ for (const k of Object.keys(data.req.cookies)) {
100
+ payload[addresses.HTTP_INCOMING_COOKIES][k] = [ data.req.cookies[k] ]
101
+ }
98
102
  }
99
103
 
100
104
  Gateway.propagate(payload, context)
101
105
 
102
- Reporter.finishAttacks(data.req, context)
106
+ Reporter.finishRequest(data.req, context)
103
107
  }
104
108
 
105
109
  function disable () {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.3.0"
4
+ "rules_version": "1.3.1"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -3040,7 +3040,9 @@
3040
3040
  "operator": "match_regex"
3041
3041
  }
3042
3042
  ],
3043
- "transformers": []
3043
+ "transformers": [
3044
+ "keys_only"
3045
+ ]
3044
3046
  },
3045
3047
  {
3046
3048
  "id": "crs-942-360",
@@ -4097,15 +4099,23 @@
4097
4099
  "parameters": {
4098
4100
  "inputs": [
4099
4101
  {
4100
- "address": "server.request.headers.no_cookies"
4102
+ "address": "server.request.query"
4103
+ },
4104
+ {
4105
+ "address": "server.request.body"
4106
+ },
4107
+ {
4108
+ "address": "server.request.path_params"
4101
4109
  }
4102
4110
  ],
4103
- "regex": "\\$(eq|ne|lte?|gte?|n?in)\\b"
4111
+ "regex": "^\\$(eq|ne|(l|g)te?|n?in|not|(n|x|)or|and|regex|where|expr|exists)$"
4104
4112
  },
4105
4113
  "operator": "match_regex"
4106
4114
  }
4107
4115
  ],
4108
- "transformers": []
4116
+ "transformers": [
4117
+ "keys_only"
4118
+ ]
4109
4119
  },
4110
4120
  {
4111
4121
  "id": "sqr-000-008",
@@ -35,6 +35,8 @@ const RESPONSE_HEADERS_PASSLIST = [
35
35
  'content-type'
36
36
  ]
37
37
 
38
+ const metricsQueue = new Map()
39
+
38
40
  function resolveHTTPRequest (context) {
39
41
  if (!context) return {}
40
42
 
@@ -82,6 +84,20 @@ function formatHeaderName (name) {
82
84
  .toLowerCase()
83
85
  }
84
86
 
87
+ function reportMetrics (metrics, store) {
88
+ const req = store && store.get('req')
89
+ const topSpan = web.root(req)
90
+ if (!topSpan) return false
91
+
92
+ if (metrics.duration) {
93
+ topSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
94
+ }
95
+
96
+ if (metrics.rulesVersion) {
97
+ topSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
98
+ }
99
+ }
100
+
85
101
  function reportAttack (attackData, store) {
86
102
  const req = store && store.get('req')
87
103
  const topSpan = web.root(req)
@@ -129,9 +145,17 @@ function reportAttack (attackData, store) {
129
145
  topSpan.addTags(newTags)
130
146
  }
131
147
 
132
- function finishAttacks (req, context) {
148
+ function finishRequest (req, context) {
133
149
  const topSpan = web.root(req)
134
- if (!topSpan || !context) return false
150
+ if (!topSpan) return false
151
+
152
+ if (metricsQueue.size) {
153
+ topSpan.addTags(Object.fromEntries(metricsQueue))
154
+
155
+ metricsQueue.clear()
156
+ }
157
+
158
+ if (!context || !topSpan.context()._tags['appsec.event']) return false
135
159
 
136
160
  const resolvedResponse = resolveHTTPResponse(context)
137
161
 
@@ -149,11 +173,13 @@ function setRateLimit (rateLimit) {
149
173
  }
150
174
 
151
175
  module.exports = {
176
+ metricsQueue,
152
177
  resolveHTTPRequest,
153
178
  resolveHTTPResponse,
154
179
  filterHeaders,
155
180
  formatHeaderName,
181
+ reportMetrics,
156
182
  reportAttack,
157
- finishAttacks,
183
+ finishRequest,
158
184
  setRateLimit
159
185
  }
@@ -4,11 +4,11 @@ const callbacks = require('./callbacks')
4
4
 
5
5
  const appliedCallbacks = new Map()
6
6
 
7
- function applyRules (rules) {
7
+ function applyRules (rules, config) {
8
8
  if (appliedCallbacks.has(rules)) return
9
9
 
10
10
  // for now there is only WAF
11
- const callback = new callbacks.DDWAF(rules)
11
+ const callback = new callbacks.DDWAF(rules, config)
12
12
 
13
13
  appliedCallbacks.set(rules, callback)
14
14
  }
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ const URL = require('url').URL
4
+ const Writer = require('./writer')
5
+ const Scheduler = require('../../../exporters/scheduler')
6
+
7
+ class AgentlessCiVisibilityExporter {
8
+ constructor (config) {
9
+ const { flushInterval, tags, site, url } = config
10
+ this._url = url || new URL(`https://citestcycle-intake.${site}`)
11
+ this._writer = new Writer({ url: this._url, tags })
12
+
13
+ if (flushInterval > 0) {
14
+ this._scheduler = new Scheduler(() => this._writer.flush(), flushInterval)
15
+ }
16
+ this._scheduler && this._scheduler.start()
17
+ }
18
+
19
+ export (trace) {
20
+ this._writer.append(trace)
21
+
22
+ if (!this._scheduler) {
23
+ this._writer.flush()
24
+ }
25
+ }
26
+
27
+ flush () {
28
+ this._writer.flush()
29
+ }
30
+ }
31
+
32
+ module.exports = AgentlessCiVisibilityExporter
@@ -0,0 +1,51 @@
1
+ 'use strict'
2
+ const request = require('../../../exporters/common/request')
3
+ const log = require('../../../log')
4
+
5
+ const { AgentlessCiVisibilityEncoder } = require('../../../encode/agentless-ci-visibility')
6
+ const BaseWriter = require('../../../exporters/common/writer')
7
+
8
+ class Writer extends BaseWriter {
9
+ constructor ({ url, tags }) {
10
+ super(...arguments)
11
+ const { 'runtime-id': runtimeId, env, service } = tags
12
+ this._url = url
13
+ this._encoder = new AgentlessCiVisibilityEncoder({ runtimeId, env, service })
14
+ }
15
+
16
+ _sendPayload (data, _, done) {
17
+ makeRequest(data, this._url, (err, res) => {
18
+ if (err) {
19
+ log.error(err)
20
+ done()
21
+ return
22
+ }
23
+ log.debug(`Response from the intake: ${res}`)
24
+ done()
25
+ })
26
+ }
27
+ }
28
+
29
+ function makeRequest (data, url, cb) {
30
+ const options = {
31
+ path: '/api/v2/citestcycle',
32
+ method: 'POST',
33
+ headers: {
34
+ 'Content-Type': 'application/msgpack',
35
+ 'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY
36
+ },
37
+ timeout: 15000
38
+ }
39
+
40
+ options.protocol = url.protocol
41
+ options.hostname = url.hostname
42
+ options.port = url.port
43
+
44
+ log.debug(() => `Request to the intake: ${JSON.stringify(options)}`)
45
+
46
+ request(data, options, false, (err, res) => {
47
+ cb(err, res)
48
+ })
49
+ }
50
+
51
+ module.exports = Writer
@@ -66,6 +66,7 @@ class Config {
66
66
  process.env.DD_TRACE_URL,
67
67
  null
68
68
  )
69
+ const DD_CIVISIBILITY_AGENTLESS_URL = process.env.DD_CIVISIBILITY_AGENTLESS_URL
69
70
  const DD_SERVICE = options.service ||
70
71
  process.env.DD_SERVICE ||
71
72
  process.env.DD_SERVICE_NAME ||
@@ -90,6 +91,10 @@ class Config {
90
91
  process.env.DD_TRACE_STARTUP_LOGS,
91
92
  false
92
93
  )
94
+ const DD_TRACE_TELEMETRY_ENABLED = coalesce(
95
+ process.env.DD_TRACE_TELEMETRY_ENABLED,
96
+ true
97
+ )
93
98
  const DD_TRACE_DEBUG = coalesce(
94
99
  process.env.DD_TRACE_DEBUG,
95
100
  false
@@ -145,10 +150,29 @@ class Config {
145
150
  path.join(__dirname, 'appsec', 'recommended.json')
146
151
  )
147
152
  const DD_APPSEC_TRACE_RATE_LIMIT = coalesce(
148
- appsec.rateLimit,
149
- process.env.DD_APPSEC_TRACE_RATE_LIMIT,
153
+ parseInt(appsec.rateLimit),
154
+ parseInt(process.env.DD_APPSEC_TRACE_RATE_LIMIT),
150
155
  100
151
156
  )
157
+ const DD_APPSEC_WAF_TIMEOUT = coalesce(
158
+ parseInt(appsec.wafTimeout),
159
+ parseInt(process.env.DD_APPSEC_WAF_TIMEOUT),
160
+ 5e3 // µs
161
+ )
162
+ const DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP = coalesce(
163
+ appsec.obfuscatorKeyRegex,
164
+ process.env.DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
165
+ `(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?)key)|token|consumer_?(?:id|key|se\
166
+ cret)|sign(?:ed|ature)|bearer|authorization`
167
+ )
168
+ const DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP = coalesce(
169
+ appsec.obfuscatorValueRegex,
170
+ process.env.DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
171
+ `(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|to\
172
+ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:\\s*=[^;]|"\\s*:\\s*"[^"]+")|bearer\
173
+ \\s+[a-z0-9\\._\\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=-]+\\.ey[I-L][\\w=-]+(?:\\.[\\w.+\\/=-]+)?\
174
+ |[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}`
175
+ )
152
176
 
153
177
  const sampler = (options.experimental && options.experimental.sampler) || {}
154
178
  const ingestion = options.ingestion || {}
@@ -171,7 +195,8 @@ class Config {
171
195
  this.debug = isTrue(DD_TRACE_DEBUG)
172
196
  this.logInjection = isTrue(DD_LOGS_INJECTION)
173
197
  this.env = DD_ENV
174
- this.url = getAgentUrl(DD_TRACE_AGENT_URL, options)
198
+ this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
199
+ : getAgentUrl(DD_TRACE_AGENT_URL, options)
175
200
  this.site = coalesce(options.site, process.env.DD_SITE, 'datadoghq.com')
176
201
  this.hostname = DD_AGENT_HOST || (this.url && this.url.hostname)
177
202
  this.port = String(DD_TRACE_AGENT_PORT || (this.url && this.url.port))
@@ -212,11 +237,15 @@ class Config {
212
237
  }
213
238
  this.lookup = options.lookup
214
239
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
240
+ this.telemetryEnabled = isTrue(DD_TRACE_TELEMETRY_ENABLED)
215
241
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
216
242
  this.appsec = {
217
243
  enabled: isTrue(DD_APPSEC_ENABLED),
218
244
  rules: DD_APPSEC_RULES,
219
- rateLimit: DD_APPSEC_TRACE_RATE_LIMIT
245
+ rateLimit: DD_APPSEC_TRACE_RATE_LIMIT,
246
+ wafTimeout: DD_APPSEC_WAF_TIMEOUT,
247
+ obfuscatorKeyRegex: DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
248
+ obfuscatorValueRegex: DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP
220
249
  }
221
250
 
222
251
  tagger.add(this.tags, {
@@ -196,7 +196,6 @@ class AgentEncoder {
196
196
 
197
197
  for (const key of keys) {
198
198
  if (typeof value[key] !== 'string' && typeof value[key] !== 'number') return
199
-
200
199
  length++
201
200
 
202
201
  this._encodeString(bytes, key)