dd-trace 4.18.0 → 5.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.
- package/CONTRIBUTING.md +98 -0
- package/LICENSE-3rdparty.csv +4 -5
- package/MIGRATING.md +15 -0
- package/README.md +20 -140
- package/ci/cypress/after-run.js +1 -0
- package/ci/cypress/after-spec.js +1 -0
- package/ci/init.js +1 -4
- package/ext/kinds.d.ts +1 -0
- package/ext/kinds.js +2 -1
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +6 -1
- package/index.d.ts +1523 -1460
- package/package.json +19 -19
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-core/src/utils/src/get.js +11 -0
- package/packages/datadog-core/src/utils/src/has.js +14 -0
- package/packages/datadog-core/src/utils/src/kebabcase.js +16 -0
- package/packages/datadog-core/src/utils/src/pick.js +11 -0
- package/packages/datadog-core/src/utils/src/set.js +16 -0
- package/packages/datadog-core/src/utils/src/uniq.js +5 -0
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/amqplib.js +2 -2
- package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
- package/packages/datadog-instrumentations/src/child_process.js +150 -0
- package/packages/datadog-instrumentations/src/couchbase.js +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +163 -46
- package/packages/datadog-instrumentations/src/dns.js +2 -1
- package/packages/datadog-instrumentations/src/express.js +20 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/grpc/client.js +56 -36
- package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/http/server.js +7 -4
- package/packages/datadog-instrumentations/src/http2/client.js +3 -1
- package/packages/datadog-instrumentations/src/http2/server.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +239 -52
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/mocha.js +154 -18
- package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
- package/packages/datadog-instrumentations/src/mongoose.js +23 -10
- package/packages/datadog-instrumentations/src/mquery.js +65 -0
- package/packages/datadog-instrumentations/src/net.js +10 -2
- package/packages/datadog-instrumentations/src/next.js +35 -9
- package/packages/datadog-instrumentations/src/playwright.js +110 -16
- package/packages/datadog-instrumentations/src/restify.js +14 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- package/packages/datadog-plugin-aerospike/src/index.js +113 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +13 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +163 -27
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +46 -8
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +129 -22
- package/packages/datadog-plugin-child_process/src/index.js +91 -0
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +125 -0
- package/packages/datadog-plugin-cucumber/src/index.js +70 -13
- package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
- package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -454
- package/packages/datadog-plugin-cypress/src/support.js +50 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
- package/packages/datadog-plugin-graphql/src/index.js +1 -6
- package/packages/datadog-plugin-graphql/src/resolve.js +28 -18
- package/packages/datadog-plugin-grpc/src/client.js +16 -2
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-jest/src/index.js +118 -12
- package/packages/datadog-plugin-jest/src/util.js +38 -16
- package/packages/datadog-plugin-kafkajs/src/consumer.js +76 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -8
- package/packages/datadog-plugin-mocha/src/index.js +87 -17
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/datadog-plugin-playwright/src/index.js +71 -8
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -1
- package/packages/datadog-plugin-rhea/src/producer.js +10 -0
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +5 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +61 -0
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
- package/packages/dd-trace/src/appsec/blocking.js +95 -43
- package/packages/dd-trace/src/appsec/channels.js +7 -3
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -28
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +10 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
- package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +13 -2
- package/packages/dd-trace/src/appsec/iast/index.js +15 -5
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +10 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +19 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +41 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
- package/packages/dd-trace/src/appsec/index.js +49 -33
- package/packages/dd-trace/src/appsec/recommended.json +1763 -106
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +42 -16
- package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
- package/packages/dd-trace/src/appsec/reporter.js +51 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +11 -8
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
- package/packages/dd-trace/src/ci-visibility/{intelligent-test-runner/get-itr-configuration.js → early-flake-detection/get-known-tests.js} +17 -22
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +25 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +95 -37
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +134 -61
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +37 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +131 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
- package/packages/dd-trace/src/config.js +561 -470
- package/packages/dd-trace/src/data_streams_context.js +1 -1
- package/packages/dd-trace/src/datastreams/pathway.js +58 -1
- package/packages/dd-trace/src/datastreams/processor.js +196 -27
- package/packages/dd-trace/src/datastreams/writer.js +11 -5
- package/packages/dd-trace/src/dogstatsd.js +3 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -6
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
- package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
- package/packages/dd-trace/src/exporters/common/request.js +21 -3
- package/packages/dd-trace/src/format.js +30 -2
- package/packages/dd-trace/src/id.js +12 -0
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +1 -1
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +104 -4
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +16 -7
- package/packages/dd-trace/src/opentracing/span.js +48 -4
- package/packages/dd-trace/src/opentracing/span_context.js +15 -6
- package/packages/dd-trace/src/opentracing/tracer.js +4 -3
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +78 -19
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +7 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +6 -19
- package/packages/dd-trace/src/plugins/util/git.js +104 -22
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +60 -10
- package/packages/dd-trace/src/plugins/util/url.js +26 -0
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +30 -38
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +77 -24
- package/packages/dd-trace/src/profiling/exporters/agent.js +77 -31
- package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
- package/packages/dd-trace/src/profiling/profiler.js +33 -22
- package/packages/dd-trace/src/profiling/profilers/events.js +270 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +45 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +18 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +146 -70
- package/packages/dd-trace/src/proxy.js +56 -24
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/sampling_rule.js +130 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/span_processor.js +9 -1
- package/packages/dd-trace/src/span_sampler.js +6 -64
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/startup-log.js +7 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
- package/packages/dd-trace/src/telemetry/index.js +182 -53
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +65 -7
- package/packages/dd-trace/src/tracer.js +12 -5
- package/register.js +4 -0
- package/scripts/install_plugin_modules.js +11 -3
- package/scripts/st.js +105 -0
- package/packages/datadog-instrumentations/src/child-process.js +0 -30
- package/packages/dd-trace/src/plugins/util/exec.js +0 -13
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -9,5 +9,11 @@ module.exports = {
|
|
|
9
9
|
ASM_USER_BLOCKING: 1n << 7n,
|
|
10
10
|
ASM_CUSTOM_RULES: 1n << 8n,
|
|
11
11
|
ASM_CUSTOM_BLOCKING_RESPONSE: 1n << 9n,
|
|
12
|
-
ASM_TRUSTED_IPS: 1n << 10n
|
|
12
|
+
ASM_TRUSTED_IPS: 1n << 10n,
|
|
13
|
+
ASM_API_SECURITY_SAMPLE_RATE: 1n << 11n,
|
|
14
|
+
APM_TRACING_SAMPLE_RATE: 1n << 12n,
|
|
15
|
+
APM_TRACING_LOGS_INJECTION: 1n << 13n,
|
|
16
|
+
APM_TRACING_HTTP_HEADER_TAGS: 1n << 14n,
|
|
17
|
+
APM_TRACING_CUSTOM_TAGS: 1n << 15n,
|
|
18
|
+
APM_TRACING_ENABLED: 1n << 19n
|
|
13
19
|
}
|
|
@@ -1,40 +1,66 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const Activation = require('../activation')
|
|
4
|
+
|
|
3
5
|
const RemoteConfigManager = require('./manager')
|
|
4
6
|
const RemoteConfigCapabilities = require('./capabilities')
|
|
7
|
+
const apiSecuritySampler = require('../api_security_sampler')
|
|
5
8
|
|
|
6
9
|
let rc
|
|
7
10
|
|
|
8
11
|
function enable (config) {
|
|
9
12
|
rc = new RemoteConfigManager(config)
|
|
13
|
+
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_CUSTOM_TAGS, true)
|
|
14
|
+
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_HTTP_HEADER_TAGS, true)
|
|
15
|
+
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_LOGS_INJECTION, true)
|
|
16
|
+
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RATE, true)
|
|
17
|
+
rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_ENABLED, true)
|
|
18
|
+
|
|
19
|
+
const activation = Activation.fromConfig(config)
|
|
10
20
|
|
|
11
|
-
if (
|
|
12
|
-
|
|
21
|
+
if (activation !== Activation.DISABLED) {
|
|
22
|
+
if (activation === Activation.ONECLICK) {
|
|
23
|
+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
|
|
24
|
+
}
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
if (config.appsec.apiSecurity?.enabled) {
|
|
27
|
+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_API_SECURITY_SAMPLE_RATE, true)
|
|
28
|
+
}
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} else {
|
|
21
|
-
shouldEnable = config.appsec.enabled // give back control to local config
|
|
22
|
-
}
|
|
30
|
+
rc.on('ASM_FEATURES', (action, rcConfig) => {
|
|
31
|
+
if (!rcConfig) return
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} else {
|
|
27
|
-
require('..').disable()
|
|
28
|
-
}
|
|
33
|
+
if (activation === Activation.ONECLICK) {
|
|
34
|
+
enableOrDisableAppsec(action, rcConfig, config)
|
|
29
35
|
}
|
|
36
|
+
|
|
37
|
+
apiSecuritySampler.setRequestSampling(rcConfig.api_security?.request_sample_rate)
|
|
30
38
|
})
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
return rc
|
|
34
42
|
}
|
|
35
43
|
|
|
44
|
+
function enableOrDisableAppsec (action, rcConfig, config) {
|
|
45
|
+
if (typeof rcConfig.asm?.enabled === 'boolean') {
|
|
46
|
+
let shouldEnable
|
|
47
|
+
|
|
48
|
+
if (action === 'apply' || action === 'modify') {
|
|
49
|
+
shouldEnable = rcConfig.asm.enabled // take control
|
|
50
|
+
} else {
|
|
51
|
+
shouldEnable = config.appsec.enabled // give back control to local config
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (shouldEnable) {
|
|
55
|
+
require('..').enable(config)
|
|
56
|
+
} else {
|
|
57
|
+
require('..').disable()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
36
62
|
function enableWafUpdate (appsecConfig) {
|
|
37
|
-
if (rc && appsecConfig && !appsecConfig.
|
|
63
|
+
if (rc && appsecConfig && !appsecConfig.rules) {
|
|
38
64
|
// dirty require to make startup faster for serverless
|
|
39
65
|
const RuleManager = require('../rule_manager')
|
|
40
66
|
|
|
@@ -25,7 +25,8 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
25
25
|
super()
|
|
26
26
|
|
|
27
27
|
const pollInterval = Math.floor(config.remoteConfig.pollInterval * 1000)
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
this.url = config.url || new URL(format({
|
|
29
30
|
protocol: 'http:',
|
|
30
31
|
hostname: config.hostname || 'localhost',
|
|
31
32
|
port: config.port
|
|
@@ -33,12 +34,6 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
33
34
|
|
|
34
35
|
this.scheduler = new Scheduler((cb) => this.poll(cb), pollInterval)
|
|
35
36
|
|
|
36
|
-
this.requestOptions = {
|
|
37
|
-
url,
|
|
38
|
-
method: 'POST',
|
|
39
|
-
path: '/v0.7/config'
|
|
40
|
-
}
|
|
41
|
-
|
|
42
37
|
this.state = {
|
|
43
38
|
client: {
|
|
44
39
|
state: { // updated by `parseConfig()`
|
|
@@ -122,7 +117,13 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
poll (cb) {
|
|
125
|
-
|
|
120
|
+
const options = {
|
|
121
|
+
url: this.url,
|
|
122
|
+
method: 'POST',
|
|
123
|
+
path: '/v0.7/config'
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
request(this.getPayload(), options, (err, data, statusCode) => {
|
|
126
127
|
// 404 means RC is disabled, ignore it
|
|
127
128
|
if (statusCode === 404) return cb()
|
|
128
129
|
|
|
@@ -3,64 +3,62 @@
|
|
|
3
3
|
const Limiter = require('../rate_limiter')
|
|
4
4
|
const { storage } = require('../../../datadog-core')
|
|
5
5
|
const web = require('../plugins/util/web')
|
|
6
|
+
const { ipHeaderList } = require('../plugins/util/ip_extractor')
|
|
6
7
|
const {
|
|
7
8
|
incrementWafInitMetric,
|
|
8
9
|
updateWafRequestsMetricTags,
|
|
9
10
|
incrementWafUpdatesMetric,
|
|
10
11
|
incrementWafRequestsMetric
|
|
11
12
|
} = require('./telemetry')
|
|
13
|
+
const zlib = require('zlib')
|
|
12
14
|
|
|
13
15
|
// default limiter, configurable with setRateLimit()
|
|
14
16
|
let limiter = new Limiter(100)
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'accept-encoding',
|
|
20
|
-
'accept-language',
|
|
18
|
+
const metricsQueue = new Map()
|
|
19
|
+
|
|
20
|
+
const contentHeaderList = [
|
|
21
21
|
'content-encoding',
|
|
22
22
|
'content-language',
|
|
23
23
|
'content-length',
|
|
24
|
-
'content-type'
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
'content-type'
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const REQUEST_HEADERS_MAP = mapHeaderAndTags([
|
|
28
|
+
'accept',
|
|
29
|
+
'accept-encoding',
|
|
30
|
+
'accept-language',
|
|
27
31
|
'host',
|
|
28
|
-
'
|
|
32
|
+
'forwarded',
|
|
29
33
|
'user-agent',
|
|
30
34
|
'via',
|
|
31
|
-
'x-
|
|
32
|
-
'x-cluster-client-ip',
|
|
33
|
-
'x-forwarded',
|
|
34
|
-
'x-forwarded-for',
|
|
35
|
-
'x-real-ip'
|
|
36
|
-
]
|
|
35
|
+
'x-amzn-trace-id',
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'content-length',
|
|
42
|
-
'content-type'
|
|
43
|
-
]
|
|
37
|
+
...ipHeaderList,
|
|
38
|
+
...contentHeaderList
|
|
39
|
+
], 'http.request.headers.')
|
|
44
40
|
|
|
45
|
-
const
|
|
41
|
+
const RESPONSE_HEADERS_MAP = mapHeaderAndTags(contentHeaderList, 'http.response.headers.')
|
|
46
42
|
|
|
47
|
-
function
|
|
43
|
+
function mapHeaderAndTags (headerList, tagPrefix) {
|
|
44
|
+
return new Map(headerList.map(headerName => [headerName, `${tagPrefix}${formatHeaderName(headerName)}`]))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function filterHeaders (headers, map) {
|
|
48
48
|
const result = {}
|
|
49
49
|
|
|
50
50
|
if (!headers) return result
|
|
51
51
|
|
|
52
|
-
for (
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
result[`${prefix}${formatHeaderName(headerName)}`] = '' + headers[headerName]
|
|
52
|
+
for (const [headerName, tagName] of map) {
|
|
53
|
+
const headerValue = headers[headerName]
|
|
54
|
+
if (headerValue) {
|
|
55
|
+
result[tagName] = '' + headerValue
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
return result
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
// TODO: this can be precomputed at start time
|
|
64
62
|
function formatHeaderName (name) {
|
|
65
63
|
return name
|
|
66
64
|
.trim()
|
|
@@ -86,7 +84,7 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
|
|
|
86
84
|
function reportMetrics (metrics) {
|
|
87
85
|
// TODO: metrics should be incremental, there already is an RFC to report metrics
|
|
88
86
|
const store = storage.getStore()
|
|
89
|
-
const rootSpan = store
|
|
87
|
+
const rootSpan = store?.req && web.root(store.req)
|
|
90
88
|
if (!rootSpan) return
|
|
91
89
|
|
|
92
90
|
if (metrics.duration) {
|
|
@@ -106,13 +104,13 @@ function reportMetrics (metrics) {
|
|
|
106
104
|
|
|
107
105
|
function reportAttack (attackData) {
|
|
108
106
|
const store = storage.getStore()
|
|
109
|
-
const req = store
|
|
107
|
+
const req = store?.req
|
|
110
108
|
const rootSpan = web.root(req)
|
|
111
109
|
if (!rootSpan) return
|
|
112
110
|
|
|
113
111
|
const currentTags = rootSpan.context()._tags
|
|
114
112
|
|
|
115
|
-
const newTags = filterHeaders(req.headers,
|
|
113
|
+
const newTags = filterHeaders(req.headers, REQUEST_HEADERS_MAP)
|
|
116
114
|
|
|
117
115
|
newTags['appsec.event'] = 'true'
|
|
118
116
|
|
|
@@ -144,6 +142,23 @@ function reportAttack (attackData) {
|
|
|
144
142
|
rootSpan.addTags(newTags)
|
|
145
143
|
}
|
|
146
144
|
|
|
145
|
+
function reportSchemas (derivatives) {
|
|
146
|
+
if (!derivatives) return
|
|
147
|
+
|
|
148
|
+
const req = storage.getStore()?.req
|
|
149
|
+
const rootSpan = web.root(req)
|
|
150
|
+
|
|
151
|
+
if (!rootSpan) return
|
|
152
|
+
|
|
153
|
+
const tags = {}
|
|
154
|
+
for (const [address, value] of Object.entries(derivatives)) {
|
|
155
|
+
const gzippedValue = zlib.gzipSync(JSON.stringify(value))
|
|
156
|
+
tags[address] = gzippedValue.toString('base64')
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
rootSpan.addTags(tags)
|
|
160
|
+
}
|
|
161
|
+
|
|
147
162
|
function finishRequest (req, res) {
|
|
148
163
|
const rootSpan = web.root(req)
|
|
149
164
|
if (!rootSpan) return
|
|
@@ -158,7 +173,7 @@ function finishRequest (req, res) {
|
|
|
158
173
|
|
|
159
174
|
if (!rootSpan.context()._tags['appsec.event']) return
|
|
160
175
|
|
|
161
|
-
const newTags = filterHeaders(res.getHeaders(),
|
|
176
|
+
const newTags = filterHeaders(res.getHeaders(), RESPONSE_HEADERS_MAP)
|
|
162
177
|
|
|
163
178
|
if (req.route && typeof req.route.path === 'string') {
|
|
164
179
|
newTags['http.endpoint'] = req.route.path
|
|
@@ -179,6 +194,8 @@ module.exports = {
|
|
|
179
194
|
reportMetrics,
|
|
180
195
|
reportAttack,
|
|
181
196
|
reportWafUpdate: incrementWafUpdatesMetric,
|
|
197
|
+
reportSchemas,
|
|
182
198
|
finishRequest,
|
|
183
|
-
setRateLimit
|
|
199
|
+
setRateLimit,
|
|
200
|
+
mapHeaderAndTags
|
|
184
201
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const fs = require('fs')
|
|
3
4
|
const waf = require('./waf')
|
|
4
5
|
const { ACKNOWLEDGED, ERROR } = require('./remote_config/apply_states')
|
|
5
6
|
const blocking = require('./blocking')
|
|
@@ -13,13 +14,15 @@ let appliedExclusions = new Map()
|
|
|
13
14
|
let appliedCustomRules = new Map()
|
|
14
15
|
let appliedActions = new Map()
|
|
15
16
|
|
|
16
|
-
function
|
|
17
|
-
defaultRules = rules
|
|
17
|
+
function loadRules (config) {
|
|
18
|
+
defaultRules = config.rules
|
|
19
|
+
? JSON.parse(fs.readFileSync(config.rules))
|
|
20
|
+
: require('./recommended.json')
|
|
18
21
|
|
|
19
|
-
waf.init(
|
|
22
|
+
waf.init(defaultRules, config)
|
|
20
23
|
|
|
21
|
-
if (
|
|
22
|
-
blocking.updateBlockingConfiguration(
|
|
24
|
+
if (defaultRules.actions) {
|
|
25
|
+
blocking.updateBlockingConfiguration(defaultRules.actions.find(action => action.id === 'block'))
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -66,9 +69,9 @@ function updateWafFromRC ({ toUnapply, toApply, toModify }) {
|
|
|
66
69
|
item.apply_error = 'Multiple ruleset received in ASM_DD'
|
|
67
70
|
} else {
|
|
68
71
|
if (file && file.rules && file.rules.length) {
|
|
69
|
-
const { version, metadata, rules } = file
|
|
72
|
+
const { version, metadata, rules, processors, scanners } = file
|
|
70
73
|
|
|
71
|
-
newRuleset = { version, metadata, rules }
|
|
74
|
+
newRuleset = { version, metadata, rules, processors, scanners }
|
|
72
75
|
newRulesetId = id
|
|
73
76
|
}
|
|
74
77
|
|
|
@@ -252,7 +255,7 @@ function clearAllRules () {
|
|
|
252
255
|
}
|
|
253
256
|
|
|
254
257
|
module.exports = {
|
|
255
|
-
|
|
258
|
+
loadRules,
|
|
256
259
|
updateWafFromRC,
|
|
257
260
|
clearAllRules
|
|
258
261
|
}
|
|
@@ -9,7 +9,7 @@ const { setUserTags } = require('./set_user')
|
|
|
9
9
|
const log = require('../../log')
|
|
10
10
|
|
|
11
11
|
function isUserBlocked (user) {
|
|
12
|
-
const actions = waf.run({ [USER_ID]: user.id })
|
|
12
|
+
const actions = waf.run({ persistent: { [USER_ID]: user.id } })
|
|
13
13
|
|
|
14
14
|
if (!actions) return false
|
|
15
15
|
|
|
@@ -10,37 +10,50 @@ const preventDuplicateAddresses = new Set([
|
|
|
10
10
|
])
|
|
11
11
|
|
|
12
12
|
class WAFContextWrapper {
|
|
13
|
-
constructor (ddwafContext,
|
|
13
|
+
constructor (ddwafContext, wafTimeout, wafVersion, rulesVersion) {
|
|
14
14
|
this.ddwafContext = ddwafContext
|
|
15
|
-
this.requiredAddresses = requiredAddresses
|
|
16
15
|
this.wafTimeout = wafTimeout
|
|
17
16
|
this.wafVersion = wafVersion
|
|
18
17
|
this.rulesVersion = rulesVersion
|
|
19
18
|
this.addressesToSkip = new Set()
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
run (
|
|
21
|
+
run ({ persistent, ephemeral }) {
|
|
22
|
+
const payload = {}
|
|
23
|
+
let payloadHasData = false
|
|
23
24
|
const inputs = {}
|
|
24
|
-
let someInputAdded = false
|
|
25
25
|
const newAddressesToSkip = new Set(this.addressesToSkip)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
if (persistent && typeof persistent === 'object') {
|
|
28
|
+
// TODO: possible optimization: only send params that haven't already been sent with same value to this wafContext
|
|
29
|
+
for (const key of Object.keys(persistent)) {
|
|
30
|
+
// TODO: requiredAddresses is no longer used due to processor addresses are not included in the list. Check on
|
|
31
|
+
// future versions when the actual addresses are included in the 'loaded' section inside diagnostics.
|
|
32
|
+
if (!this.addressesToSkip.has(key)) {
|
|
33
|
+
inputs[key] = persistent[key]
|
|
34
|
+
if (preventDuplicateAddresses.has(key)) {
|
|
35
|
+
newAddressesToSkip.add(key)
|
|
36
|
+
}
|
|
33
37
|
}
|
|
34
|
-
someInputAdded = true
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
if (
|
|
41
|
+
if (Object.keys(inputs).length) {
|
|
42
|
+
payload['persistent'] = inputs
|
|
43
|
+
payloadHasData = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (ephemeral && Object.keys(ephemeral).length) {
|
|
47
|
+
payload['ephemeral'] = ephemeral
|
|
48
|
+
payloadHasData = true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!payloadHasData) return
|
|
39
52
|
|
|
40
53
|
try {
|
|
41
54
|
const start = process.hrtime.bigint()
|
|
42
55
|
|
|
43
|
-
const result = this.ddwafContext.run(
|
|
56
|
+
const result = this.ddwafContext.run(payload, this.wafTimeout)
|
|
44
57
|
|
|
45
58
|
const end = process.hrtime.bigint()
|
|
46
59
|
|
|
@@ -63,6 +76,8 @@ class WAFContextWrapper {
|
|
|
63
76
|
Reporter.reportAttack(JSON.stringify(result.events))
|
|
64
77
|
}
|
|
65
78
|
|
|
79
|
+
Reporter.reportSchemas(result.derivatives)
|
|
80
|
+
|
|
66
81
|
return result.actions
|
|
67
82
|
} catch (err) {
|
|
68
83
|
log.error('Error while running the AppSec WAF')
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const request = require('../../exporters/common/request')
|
|
2
2
|
const id = require('../../id')
|
|
3
|
-
const log = require('../../log')
|
|
4
3
|
|
|
5
|
-
function
|
|
4
|
+
function getKnownTests ({
|
|
6
5
|
url,
|
|
7
6
|
isEvpProxy,
|
|
7
|
+
evpProxyPrefix,
|
|
8
|
+
isGzipCompatible,
|
|
8
9
|
env,
|
|
9
10
|
service,
|
|
10
11
|
repositoryUrl,
|
|
@@ -14,35 +15,39 @@ function getItrConfiguration ({
|
|
|
14
15
|
osArchitecture,
|
|
15
16
|
runtimeName,
|
|
16
17
|
runtimeVersion,
|
|
17
|
-
branch,
|
|
18
18
|
custom
|
|
19
19
|
}, done) {
|
|
20
20
|
const options = {
|
|
21
|
-
path: '/api/v2/libraries/tests
|
|
21
|
+
path: '/api/v2/ci/libraries/tests',
|
|
22
22
|
method: 'POST',
|
|
23
23
|
headers: {
|
|
24
24
|
'Content-Type': 'application/json'
|
|
25
25
|
},
|
|
26
|
+
timeout: 20000,
|
|
26
27
|
url
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
if (isGzipCompatible) {
|
|
31
|
+
options.headers['accept-encoding'] = 'gzip'
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
if (isEvpProxy) {
|
|
30
|
-
options.path =
|
|
35
|
+
options.path = `${evpProxyPrefix}/api/v2/ci/libraries/tests`
|
|
31
36
|
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
|
|
32
37
|
} else {
|
|
33
38
|
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
34
39
|
if (!apiKey) {
|
|
35
|
-
return done(new Error('
|
|
40
|
+
return done(new Error('Known tests were not fetched because Datadog API key is not defined.'))
|
|
36
41
|
}
|
|
42
|
+
|
|
37
43
|
options.headers['dd-api-key'] = apiKey
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
const data = JSON.stringify({
|
|
41
47
|
data: {
|
|
42
48
|
id: id().toString(10),
|
|
43
|
-
type: '
|
|
49
|
+
type: 'ci_app_libraries_tests_request',
|
|
44
50
|
attributes: {
|
|
45
|
-
test_level: 'suite',
|
|
46
51
|
configurations: {
|
|
47
52
|
'os.platform': osPlatform,
|
|
48
53
|
'os.version': osVersion,
|
|
@@ -54,8 +59,7 @@ function getItrConfiguration ({
|
|
|
54
59
|
service,
|
|
55
60
|
env,
|
|
56
61
|
repository_url: repositoryUrl,
|
|
57
|
-
sha
|
|
58
|
-
branch
|
|
62
|
+
sha
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
})
|
|
@@ -65,17 +69,8 @@ function getItrConfiguration ({
|
|
|
65
69
|
done(err)
|
|
66
70
|
} else {
|
|
67
71
|
try {
|
|
68
|
-
const {
|
|
69
|
-
|
|
70
|
-
attributes: {
|
|
71
|
-
code_coverage: isCodeCoverageEnabled,
|
|
72
|
-
tests_skipping: isSuitesSkippingEnabled
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} = JSON.parse(res)
|
|
76
|
-
const config = { isCodeCoverageEnabled, isSuitesSkippingEnabled }
|
|
77
|
-
log.debug(() => `Received settings: ${config}`)
|
|
78
|
-
done(null, config)
|
|
72
|
+
const { data: { attributes: { tests: knownTests } } } = JSON.parse(res)
|
|
73
|
+
done(null, knownTests)
|
|
79
74
|
} catch (err) {
|
|
80
75
|
done(err)
|
|
81
76
|
}
|
|
@@ -83,4 +78,4 @@ function getItrConfiguration ({
|
|
|
83
78
|
})
|
|
84
79
|
}
|
|
85
80
|
|
|
86
|
-
module.exports = {
|
|
81
|
+
module.exports = { getKnownTests }
|
|
@@ -5,10 +5,23 @@ const AgentlessWriter = require('../agentless/writer')
|
|
|
5
5
|
const CoverageWriter = require('../agentless/coverage-writer')
|
|
6
6
|
const CiVisibilityExporter = require('../ci-visibility-exporter')
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const AGENT_EVP_PROXY_PATH_PREFIX = '/evp_proxy/v'
|
|
9
|
+
const AGENT_EVP_PROXY_PATH_REGEX = /\/evp_proxy\/v(\d+)\/?/
|
|
9
10
|
|
|
10
|
-
function
|
|
11
|
-
|
|
11
|
+
function getLatestEvpProxyVersion (err, agentInfo) {
|
|
12
|
+
if (err) {
|
|
13
|
+
return 0
|
|
14
|
+
}
|
|
15
|
+
return agentInfo.endpoints.reduce((acc, endpoint) => {
|
|
16
|
+
if (endpoint.includes(AGENT_EVP_PROXY_PATH_PREFIX)) {
|
|
17
|
+
const version = Number(endpoint.replace(AGENT_EVP_PROXY_PATH_REGEX, '$1'))
|
|
18
|
+
if (isNaN(version)) {
|
|
19
|
+
return acc
|
|
20
|
+
}
|
|
21
|
+
return version > acc ? version : acc
|
|
22
|
+
}
|
|
23
|
+
return acc
|
|
24
|
+
}, 0)
|
|
12
25
|
}
|
|
13
26
|
|
|
14
27
|
class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
|
|
@@ -25,17 +38,22 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
|
|
|
25
38
|
|
|
26
39
|
this.getAgentInfo((err, agentInfo) => {
|
|
27
40
|
this._isInitialized = true
|
|
28
|
-
const
|
|
41
|
+
const latestEvpProxyVersion = getLatestEvpProxyVersion(err, agentInfo)
|
|
42
|
+
const isEvpCompatible = latestEvpProxyVersion >= 2
|
|
43
|
+
const isGzipCompatible = latestEvpProxyVersion >= 4
|
|
44
|
+
|
|
45
|
+
const evpProxyPrefix = `${AGENT_EVP_PROXY_PATH_PREFIX}${latestEvpProxyVersion}`
|
|
29
46
|
if (isEvpCompatible) {
|
|
30
47
|
this._isUsingEvpProxy = true
|
|
48
|
+
this.evpProxyPrefix = evpProxyPrefix
|
|
31
49
|
this._writer = new AgentlessWriter({
|
|
32
50
|
url: this._url,
|
|
33
51
|
tags,
|
|
34
|
-
evpProxyPrefix
|
|
52
|
+
evpProxyPrefix
|
|
35
53
|
})
|
|
36
54
|
this._coverageWriter = new CoverageWriter({
|
|
37
55
|
url: this._url,
|
|
38
|
-
evpProxyPrefix
|
|
56
|
+
evpProxyPrefix
|
|
39
57
|
})
|
|
40
58
|
} else {
|
|
41
59
|
this._writer = new AgentWriter({
|
|
@@ -51,6 +69,7 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
|
|
|
51
69
|
this._resolveCanUseCiVisProtocol(isEvpCompatible)
|
|
52
70
|
this.exportUncodedTraces()
|
|
53
71
|
this.exportUncodedCoverages()
|
|
72
|
+
this._isGzipCompatible = isGzipCompatible
|
|
54
73
|
})
|
|
55
74
|
}
|
|
56
75
|
|
|
@@ -5,6 +5,16 @@ const { safeJSONStringify } = require('../../../exporters/common/util')
|
|
|
5
5
|
|
|
6
6
|
const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
|
|
7
7
|
const BaseWriter = require('../../../exporters/common/writer')
|
|
8
|
+
const {
|
|
9
|
+
incrementCountMetric,
|
|
10
|
+
distributionMetric,
|
|
11
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS,
|
|
12
|
+
TELEMETRY_ENDPOINT_PAYLOAD_BYTES,
|
|
13
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
|
|
14
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
|
|
15
|
+
TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
|
|
16
|
+
getErrorTypeFromStatusCode
|
|
17
|
+
} = require('../../../ci-visibility/telemetry')
|
|
8
18
|
|
|
9
19
|
class Writer extends BaseWriter {
|
|
10
20
|
constructor ({ url, evpProxyPrefix = '' }) {
|
|
@@ -34,8 +44,27 @@ class Writer extends BaseWriter {
|
|
|
34
44
|
|
|
35
45
|
log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
const startRequestTime = Date.now()
|
|
48
|
+
|
|
49
|
+
incrementCountMetric(TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS, { endpoint: 'code_coverage' })
|
|
50
|
+
distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_BYTES, { endpoint: 'code_coverage' }, form.size())
|
|
51
|
+
|
|
52
|
+
request(form, options, (err, res, statusCode) => {
|
|
53
|
+
distributionMetric(
|
|
54
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
|
|
55
|
+
{ endpoint: 'code_coverage' },
|
|
56
|
+
Date.now() - startRequestTime
|
|
57
|
+
)
|
|
38
58
|
if (err) {
|
|
59
|
+
const errorType = getErrorTypeFromStatusCode(statusCode)
|
|
60
|
+
incrementCountMetric(
|
|
61
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
|
|
62
|
+
{ endpoint: 'code_coverage', errorType }
|
|
63
|
+
)
|
|
64
|
+
incrementCountMetric(
|
|
65
|
+
TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
|
|
66
|
+
{ endpoint: 'code_coverage' }
|
|
67
|
+
)
|
|
39
68
|
log.error(err)
|
|
40
69
|
done()
|
|
41
70
|
return
|
|
@@ -21,6 +21,8 @@ class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
|
|
|
21
21
|
this._coverageWriter = new CoverageWriter({ url: this._coverageUrl })
|
|
22
22
|
|
|
23
23
|
this._apiUrl = url || new URL(`https://api.${site}`)
|
|
24
|
+
// Agentless is always gzip compatible
|
|
25
|
+
this._isGzipCompatible = true
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
setUrl (url, coverageUrl = url, apiUrl = url) {
|