dd-trace 5.132.0 → 5.134.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/ci/diagnose.js +9 -14
- package/ci/init.js +1 -2
- package/ci/test-optimization-validation/ci-discovery.js +9 -4
- package/ci/test-optimization-validation/executable.js +1 -5
- package/ci/test-optimization-validation/framework-adapters/cypress.js +1 -4
- package/ci/test-optimization-validation/framework-adapters/vitest.js +1 -1
- package/ci/test-optimization-validation/generated-files.js +6 -4
- package/ci/test-optimization-validation/generated-test-contract.js +7 -3
- package/ci/test-optimization-validation/manifest-scaffold.js +7 -2
- package/ci/test-optimization-validation/manifest-schema.js +6 -7
- package/ci/test-optimization-validation/report-writer.js +6 -2
- package/ci/test-optimization-validation/runner-command.js +2 -4
- package/ci/test-optimization-validation/runner-contract.js +1 -2
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +1 -15
- package/ci/vitest-no-worker-init-runner-setup.mjs +27 -0
- package/ci/vitest-no-worker-init-setup.mjs +10 -7
- package/index.d.ts +41 -19
- package/initialize.mjs +1 -3
- package/openfeature/rules-based.d.ts +11 -0
- package/openfeature/rules-based.js +7 -0
- package/package.json +25 -22
- package/packages/datadog-core/src/storage.js +16 -0
- package/packages/datadog-esbuild/index.js +18 -12
- package/packages/datadog-instrumentations/index.js +2 -1
- package/packages/datadog-instrumentations/src/aerospike.js +3 -3
- package/packages/datadog-instrumentations/src/ai.js +3 -3
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -6
- package/packages/datadog-instrumentations/src/aws-sdk.js +21 -13
- package/packages/datadog-instrumentations/src/cassandra-driver.js +25 -20
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +9 -23
- package/packages/datadog-instrumentations/src/cucumber.js +65 -41
- package/packages/datadog-instrumentations/src/elasticsearch.js +1 -5
- package/packages/datadog-instrumentations/src/electron.js +6 -6
- package/packages/datadog-instrumentations/src/fastify.js +13 -4
- package/packages/datadog-instrumentations/src/fs.js +2 -2
- package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +9 -5
- package/packages/datadog-instrumentations/src/grpc/client.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +28 -9
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +45 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +89 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +5 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/jest.js +12 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +48 -31
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/vitest.js +8 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +7 -7
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +5 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +42 -4
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +7 -10
- package/packages/datadog-instrumentations/src/ioredis.js +7 -5
- package/packages/datadog-instrumentations/src/iovalkey.js +7 -5
- package/packages/datadog-instrumentations/src/jest.js +72 -67
- package/packages/datadog-instrumentations/src/knex.js +9 -5
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +3 -3
- package/packages/datadog-instrumentations/src/mocha/common.js +20 -8
- package/packages/datadog-instrumentations/src/mocha/main.js +140 -43
- package/packages/datadog-instrumentations/src/mocha/utils.js +38 -4
- package/packages/datadog-instrumentations/src/mocha/worker.js +1 -2
- package/packages/datadog-instrumentations/src/mongodb-core.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +3 -3
- package/packages/datadog-instrumentations/src/nova-sonic/audio.js +173 -0
- package/packages/datadog-instrumentations/src/nova-sonic/index.js +209 -0
- package/packages/datadog-instrumentations/src/nova-sonic/session.js +492 -0
- package/packages/datadog-instrumentations/src/openai-realtime/index.js +18 -6
- package/packages/datadog-instrumentations/src/openai-realtime/session.js +1 -1
- package/packages/datadog-instrumentations/src/openai.js +7 -0
- package/packages/datadog-instrumentations/src/pino.js +5 -6
- package/packages/datadog-instrumentations/src/playwright.js +2 -0
- package/packages/datadog-instrumentations/src/redis.js +27 -13
- package/packages/datadog-instrumentations/src/router.js +30 -0
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +2 -6
- package/packages/datadog-instrumentations/src/stripe.js +23 -12
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +8 -5
- package/packages/datadog-instrumentations/src/vitest-main.js +16 -18
- package/packages/datadog-instrumentations/src/vitest-util.js +7 -4
- package/packages/datadog-instrumentations/src/vitest-worker.js +1 -2
- package/packages/datadog-instrumentations/src/vitest.js +9 -1
- package/packages/datadog-instrumentations/src/webdriverio.js +5 -8
- package/packages/datadog-instrumentations/src/ws.js +1 -4
- package/packages/datadog-plugin-amqplib/src/client.js +1 -2
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -5
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -8
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +18 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/sonic.js +45 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -5
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +5 -4
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -3
- package/packages/datadog-plugin-claude-agent-sdk/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +4 -5
- package/packages/datadog-plugin-cypress/src/index.js +6 -6
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -2
- package/packages/datadog-plugin-cypress/src/support.js +3 -4
- package/packages/datadog-plugin-express/src/code_origin.js +1 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
- package/packages/datadog-plugin-graphql/src/execute.js +5 -5
- package/packages/datadog-plugin-grpc/src/util.js +1 -2
- package/packages/datadog-plugin-kafkajs/src/producer.js +1 -2
- package/packages/datadog-plugin-mocha/src/index.js +7 -10
- package/packages/datadog-plugin-mocha/src/webdriverio-video.js +8 -4
- package/packages/datadog-plugin-mongodb-core/src/query.js +8 -5
- package/packages/datadog-plugin-next/src/index.js +1 -2
- package/packages/datadog-plugin-openai/src/tracing.js +5 -2
- package/packages/datadog-plugin-openai-agents/src/integration.js +6 -2
- package/packages/datadog-plugin-openai-agents/src/processor.js +2 -4
- package/packages/datadog-plugin-postgres/src/index.js +24 -0
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -5
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -4
- package/packages/datadog-plugin-vitest/src/index.js +5 -2
- package/packages/datadog-shimmer/src/shimmer.js +5 -4
- package/packages/datadog-webpack/index.js +55 -43
- package/packages/datadog-webpack/src/loader.js +56 -8
- package/packages/dd-trace/src/aiguard/evaluation.js +143 -1
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -4
- package/packages/dd-trace/src/aiguard/messages/utils.js +1 -2
- package/packages/dd-trace/src/aiguard/redaction.js +8 -2
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +3 -2
- package/packages/dd-trace/src/appsec/api_security/sampler.js +2 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -9
- package/packages/dd-trace/src/appsec/handlers/http-request.js +3 -9
- package/packages/dd-trace/src/appsec/handlers/http-response.js +7 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +4 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +1 -4
- package/packages/dd-trace/src/appsec/iast/path-line.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +7 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -3
- package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +1 -6
- package/packages/dd-trace/src/appsec/lambda.js +1 -3
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +37 -27
- package/packages/dd-trace/src/appsec/rasp/lfi.js +9 -5
- package/packages/dd-trace/src/appsec/reporter.js +21 -1
- package/packages/dd-trace/src/appsec/stack_trace.js +4 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +3 -6
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +13 -7
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +2 -8
- package/packages/dd-trace/src/ci-visibility/resolve-runfile-path.js +54 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +5 -8
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +2 -53
- package/packages/dd-trace/src/config/config-types.d.ts +2 -2
- package/packages/dd-trace/src/config/defaults.js +5 -5
- package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
- package/packages/dd-trace/src/config/helper.js +34 -3
- package/packages/dd-trace/src/config/index.js +55 -9
- package/packages/dd-trace/src/config/normalize-service.js +1 -1
- package/packages/dd-trace/src/config/parsers.js +2 -2
- package/packages/dd-trace/src/config/supported-configurations.json +44 -0
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -5
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -5
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +4 -6
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -0
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +2 -2
- package/packages/dd-trace/src/debugger/unsupported-runtime.js +16 -0
- package/packages/dd-trace/src/dogstatsd.js +1 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/request.js +1 -5
- package/packages/dd-trace/src/id.js +14 -1
- package/packages/dd-trace/src/lambda/handler.js +179 -19
- package/packages/dd-trace/src/lambda/index.js +15 -1
- package/packages/dd-trace/src/lambda/runtime/patch.js +34 -7
- package/packages/dd-trace/src/llmobs/agent-manifest.js +19 -2
- package/packages/dd-trace/src/llmobs/audio-utils.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +15 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +15 -0
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +1 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -3
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/nova-sonic.js +92 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +5 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +64 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +38 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +5 -7
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +15 -4
- package/packages/dd-trace/src/llmobs/span_processor.js +13 -2
- package/packages/dd-trace/src/llmobs/tagger.js +20 -10
- package/packages/dd-trace/src/llmobs/util.js +11 -6
- package/packages/dd-trace/src/llmobs/writers/base.js +4 -5
- package/packages/dd-trace/src/log/log.js +1 -5
- package/packages/dd-trace/src/openfeature/evaluation-telemetry-opt-out-hook.js +51 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +48 -21
- package/packages/dd-trace/src/openfeature/index.js +6 -0
- package/packages/dd-trace/src/openfeature/writers/util.js +4 -4
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -2
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +24 -24
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +53 -13
- package/packages/dd-trace/src/otel-sampling.js +4 -5
- package/packages/dd-trace/src/otel-thread-ctx.js +79 -13
- package/packages/dd-trace/src/plugin_manager.js +1 -2
- package/packages/dd-trace/src/plugins/database.js +7 -16
- package/packages/dd-trace/src/plugins/tracing.js +0 -1
- package/packages/dd-trace/src/plugins/util/git.js +99 -59
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -5
- package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -1
- package/packages/dd-trace/src/plugins/util/test.js +50 -4
- package/packages/dd-trace/src/plugins/util/web.js +90 -20
- package/packages/dd-trace/src/priority_sampler.js +1 -2
- package/packages/dd-trace/src/profiling/profiler.js +4 -6
- package/packages/dd-trace/src/proxy.js +1 -2
- package/packages/dd-trace/src/ritm.js +4 -2
- package/packages/dd-trace/src/serverless.js +5 -0
- package/packages/dd-trace/src/span_processor.js +13 -17
- package/packages/dd-trace/src/span_stats.js +4 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +1 -3
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +1 -1
- package/packages/dd-trace/src/util.js +37 -4
- package/packages/dd-trace/src/web-tags-cache.js +6 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +8 -8
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/vendor/dist/@datadog/openfeature-node-server/rules-based/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.d.ts +925 -0
- package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.js +1 -0
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
|
@@ -58,9 +58,7 @@ function disable () {
|
|
|
58
58
|
* @returns {'sample' | 'missing_route' | 'skip'}
|
|
59
59
|
*/
|
|
60
60
|
function sampleRootSpanRequest (rootSpan, request, record = false) {
|
|
61
|
-
if (!enabled) return SamplingDecision.SKIP
|
|
62
|
-
|
|
63
|
-
if (!rootSpan) return SamplingDecision.SKIP
|
|
61
|
+
if (!enabled || !rootSpan) return SamplingDecision.SKIP
|
|
64
62
|
|
|
65
63
|
const { method, statusCode, route, blocked = false } = request ?? {}
|
|
66
64
|
|
|
@@ -102,9 +100,7 @@ function sampleRequest (req, res, record = false) {
|
|
|
102
100
|
if (!enabled) return SamplingDecision.SKIP
|
|
103
101
|
|
|
104
102
|
const rootSpan = web.root(req)
|
|
105
|
-
if (!rootSpan) return SamplingDecision.SKIP
|
|
106
|
-
|
|
107
|
-
if (isRejected(rootSpan)) return SamplingDecision.SKIP
|
|
103
|
+
if (!rootSpan || isRejected(rootSpan)) return SamplingDecision.SKIP
|
|
108
104
|
|
|
109
105
|
const statusCode = res.statusCode
|
|
110
106
|
const route = getRouteOrEndpoint(web.getContext(req), statusCode)
|
|
@@ -163,15 +163,7 @@ function isRedirectResponse (res) {
|
|
|
163
163
|
* @param {object} ctx http client instrumentation context (mutated).
|
|
164
164
|
*/
|
|
165
165
|
function planResponseBodyCollection (originatingReq, res, ctx) {
|
|
166
|
-
if (!config) {
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (isRedirectResponse(res)) {
|
|
171
|
-
return
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!shouldSampleBody(originatingReq)) {
|
|
166
|
+
if (!config || isRedirectResponse(res) || !shouldSampleBody(originatingReq)) {
|
|
175
167
|
return
|
|
176
168
|
}
|
|
177
169
|
|
|
@@ -60,9 +60,7 @@ function onRequestCookieParser ({ req, res, abortController, cookies }) {
|
|
|
60
60
|
if (!cookies || typeof cookies !== 'object') return
|
|
61
61
|
|
|
62
62
|
const rootSpan = web.root(req)
|
|
63
|
-
if (!rootSpan) return
|
|
64
|
-
|
|
65
|
-
if (isEmpty(cookies)) return
|
|
63
|
+
if (!rootSpan || isEmpty(cookies)) return
|
|
66
64
|
analyzedCookies.add(cookies)
|
|
67
65
|
|
|
68
66
|
const results = waf.run({
|
|
@@ -189,9 +187,7 @@ function onRequestQueryParsed ({ req, res, query, abortController }) {
|
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
const rootSpan = web.root(req)
|
|
192
|
-
if (!rootSpan) return
|
|
193
|
-
|
|
194
|
-
if (isEmpty(query)) return
|
|
190
|
+
if (!rootSpan || isEmpty(query)) return
|
|
195
191
|
|
|
196
192
|
const results = waf.run({
|
|
197
193
|
persistent: {
|
|
@@ -204,9 +200,7 @@ function onRequestQueryParsed ({ req, res, query, abortController }) {
|
|
|
204
200
|
|
|
205
201
|
function onRequestProcessParams ({ req, res, abortController, params }) {
|
|
206
202
|
const rootSpan = web.root(req)
|
|
207
|
-
if (!rootSpan) return
|
|
208
|
-
|
|
209
|
-
if (!params || typeof params !== 'object' || isEmpty(params)) return
|
|
203
|
+
if (!rootSpan || !params || typeof params !== 'object' || isEmpty(params)) return
|
|
210
204
|
|
|
211
205
|
const results = waf.run({
|
|
212
206
|
persistent: {
|
|
@@ -11,8 +11,13 @@ const { storedResponseHeaders, copyHeadersOmitting } = require('./http-shared')
|
|
|
11
11
|
const responseAnalyzedSet = new WeakSet()
|
|
12
12
|
|
|
13
13
|
function onResponseBody ({ req, res, body }) {
|
|
14
|
-
if (
|
|
15
|
-
|
|
14
|
+
if (
|
|
15
|
+
!body ||
|
|
16
|
+
typeof body !== 'object' ||
|
|
17
|
+
apiSecurity.sampleRequest(req, res) !== apiSecurity.SamplingDecision.SAMPLE
|
|
18
|
+
) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
16
21
|
|
|
17
22
|
// we don't support blocking at this point, so no results needed
|
|
18
23
|
waf.run({
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
|
|
5
|
+
const { APPSEC_FS_STORAGE } = require('../../rasp/fs-plugin')
|
|
5
6
|
const { getIastContext } = require('../iast-context')
|
|
6
7
|
const { storage } = require('../../../../../datadog-core')
|
|
7
8
|
const { PATH_TRAVERSAL } = require('../vulnerabilities')
|
|
@@ -29,10 +30,10 @@ class PathTraversalAnalyzer extends InjectionAnalyzer {
|
|
|
29
30
|
|
|
30
31
|
onConfigure () {
|
|
31
32
|
this.addSub('apm:fs:operation:start', (obj) => {
|
|
32
|
-
const
|
|
33
|
-
const outOfReqOrChild = !
|
|
33
|
+
const fs = storage(APPSEC_FS_STORAGE).getStore()
|
|
34
|
+
const outOfReqOrChild = !fs?.root
|
|
34
35
|
|
|
35
|
-
// we could filter out all the nested fs.operations based on
|
|
36
|
+
// we could filter out all the nested fs.operations based on fs.root
|
|
36
37
|
// but if we spect a store in the context to be present we are going to exclude
|
|
37
38
|
// all out_of_the_request fs.operations
|
|
38
39
|
// AppsecFsPlugin must be enabled
|
|
@@ -17,10 +17,7 @@ class SetCookiesHeaderInterceptor extends Plugin {
|
|
|
17
17
|
|
|
18
18
|
_handleCookies (name, value, res) {
|
|
19
19
|
if (name.toLowerCase() === 'set-cookie') {
|
|
20
|
-
|
|
21
|
-
if (typeof value === 'string') {
|
|
22
|
-
allCookies = [value]
|
|
23
|
-
}
|
|
20
|
+
const allCookies = typeof value === 'string' ? [value] : value
|
|
24
21
|
const alreadyCheckedCookies = this._getAlreadyCheckedCookiesInResponse(res)
|
|
25
22
|
|
|
26
23
|
let location
|
|
@@ -66,7 +66,8 @@ function getCallSiteFramesForLocation (callSiteFrames, externallyExcludedPaths)
|
|
|
66
66
|
|
|
67
67
|
if (
|
|
68
68
|
!isExcluded(callsite, externallyExcludedPaths) &&
|
|
69
|
-
(!filepath.includes(pathLine.ddBasePath) ||
|
|
69
|
+
(pathLine.ddBasePath === undefined || !filepath.includes(pathLine.ddBasePath) ||
|
|
70
|
+
globalThis.__DD_ESBUILD_IAST_WITH_NO_SM)
|
|
70
71
|
) {
|
|
71
72
|
clientFrames.push(callsite)
|
|
72
73
|
}
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
const TaintedUtils = require('@datadog/native-iast-taint-tracking')
|
|
4
4
|
const { IAST_TRANSACTION_ID } = require('../iast-context')
|
|
5
5
|
const log = require('../../../log')
|
|
6
|
+
const { typedArrayLength } = require('../../../util')
|
|
6
7
|
const { HTTP_REQUEST_PARAMETER } = require('./source-types')
|
|
7
8
|
|
|
8
|
-
const SEPARATOR = '\
|
|
9
|
+
const SEPARATOR = '\0' // Unit Separator (cannot be in URL keys)
|
|
10
|
+
const MAX_TRAVERSED_BINARY_VIEW_LENGTH = 1024
|
|
9
11
|
|
|
10
12
|
function taintObject (iastContext, object, type) {
|
|
11
13
|
let result = object
|
|
@@ -31,6 +33,10 @@ function taintObject (iastContext, object, type) {
|
|
|
31
33
|
} else if (typeof value === 'object' && !visited.has(value)) {
|
|
32
34
|
visited.add(value)
|
|
33
35
|
|
|
36
|
+
// Binary view elements are numbers, but named properties may hold strings. Their keys cannot be listed
|
|
37
|
+
// without also materializing one key per element, so only small views are walked.
|
|
38
|
+
if (ArrayBuffer.isView(value) && typedArrayLength(value) > MAX_TRAVERSED_BINARY_VIEW_LENGTH) continue
|
|
39
|
+
|
|
34
40
|
for (const key of Object.keys(value)) {
|
|
35
41
|
queue.push({ parent: value, property: property ? `${property}.${key}` : key, value: value[key], key })
|
|
36
42
|
}
|
|
@@ -264,9 +264,7 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
_taintDatabaseResult (result, dbOrigin, iastContext, name) {
|
|
267
|
-
if (!iastContext) return result
|
|
268
|
-
|
|
269
|
-
if (this._rowsToTaint === 0) return result
|
|
267
|
+
if (!iastContext || this._rowsToTaint === 0) return result
|
|
270
268
|
|
|
271
269
|
if (Array.isArray(result)) {
|
|
272
270
|
for (let i = 0; i < result.length && i < this._rowsToTaint; i++) {
|
|
@@ -31,9 +31,7 @@ export async function initialize (data) {
|
|
|
31
31
|
export async function load (url, context, nextLoad) {
|
|
32
32
|
const result = await nextLoad(url, context)
|
|
33
33
|
|
|
34
|
-
if (!port) return result
|
|
35
|
-
if (!result.source) return result
|
|
36
|
-
if (url.includes(ddTraceDir) || url.includes('iitm=true')) return result
|
|
34
|
+
if (!port || !result.source || url.includes(ddTraceDir) || url.includes('iitm=true')) return result
|
|
37
35
|
|
|
38
36
|
let passes
|
|
39
37
|
try {
|
|
@@ -24,12 +24,7 @@ function formatTags (tags, tagKey) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function getNamespace (scope, context) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (scope === Scope.REQUEST) {
|
|
30
|
-
namespace = getNamespaceFromContext(context) || globalNamespace
|
|
31
|
-
}
|
|
32
|
-
return namespace
|
|
27
|
+
return scope === Scope.REQUEST ? getNamespaceFromContext(context) || globalNamespace : globalNamespace
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
class IastMetric {
|
|
@@ -169,9 +169,7 @@ function parseResponseBody (rawBody, headers, isBase64Encoded) {
|
|
|
169
169
|
// A handler that answered with the payload itself needs no parsing, and no content type either.
|
|
170
170
|
if (typeof rawBody === 'object') return rawBody
|
|
171
171
|
|
|
172
|
-
if (typeof rawBody !== 'string') return
|
|
173
|
-
|
|
174
|
-
if (!isJsonContentType(headers?.['content-type'])) return
|
|
172
|
+
if (typeof rawBody !== 'string' || !isJsonContentType(headers?.['content-type'])) return
|
|
175
173
|
|
|
176
174
|
if (isOverSizeCap(rawBody, isBase64Encoded)) {
|
|
177
175
|
log.debug('[ASM] Lambda response body larger than %d bytes, skipping schema extraction',
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
4
|
+
|
|
4
5
|
const { storage } = require('../../../../datadog-core')
|
|
5
6
|
const log = require('../../log')
|
|
6
7
|
|
|
7
8
|
const RASP_MODULE = 'rasp'
|
|
8
9
|
const IAST_MODULE = 'iast'
|
|
10
|
+
const APPSEC_FS_STORAGE = 'appsec-fs'
|
|
9
11
|
|
|
10
12
|
const enabledFor = {
|
|
11
13
|
[RASP_MODULE]: false,
|
|
@@ -13,42 +15,53 @@ const enabledFor = {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
let fsPlugin
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const legacyStorage = storage('legacy')
|
|
19
|
+
const appsecFsStorage = storage(APPSEC_FS_STORAGE)
|
|
20
|
+
const fsOperationStart = dc.channel('apm:fs:operation:start')
|
|
21
|
+
const fsOperationFinish = dc.channel('apm:fs:operation:finish')
|
|
22
|
+
const responseRenderStart = dc.channel('tracing:datadog:express:response:render:start')
|
|
23
|
+
const responseRenderEnd = dc.channel('tracing:datadog:express:response:render:end')
|
|
24
|
+
|
|
25
|
+
function getStoreToStart (fsProps, store = appsecFsStorage.getStore()) {
|
|
26
|
+
// Only track operations inside a traced context, like a request. Callbacks of fs streams and watchers keep
|
|
27
|
+
// the state of the operation that created them, so state created outside of one would leak into every request
|
|
28
|
+
// of a server started from such a callback. The tracing fs plugin enters a noop store when no span is active.
|
|
29
|
+
const legacyStore = legacyStorage.getStore()
|
|
30
|
+
if (!legacyStore || legacyStore.noop) return
|
|
31
|
+
|
|
32
|
+
if (!store || !store.opExcluded) {
|
|
19
33
|
return {
|
|
20
34
|
...store,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
...fsProps,
|
|
24
|
-
parentStore: store,
|
|
25
|
-
},
|
|
35
|
+
...fsProps,
|
|
36
|
+
parentStore: store,
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
|
|
29
40
|
return store
|
|
30
41
|
}
|
|
31
42
|
|
|
32
|
-
class AppsecFsPlugin
|
|
43
|
+
class AppsecFsPlugin {
|
|
33
44
|
enable () {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
// The tracing fs plugin binds the legacy store on these channels. AppSec
|
|
46
|
+
// keeps its fs-only state in a dedicated storage namespace to avoid
|
|
47
|
+
// clobbering tracing state while still tracking nested operations.
|
|
48
|
+
fsOperationStart.bindStore(appsecFsStorage, this._onFsOperationStart)
|
|
49
|
+
fsOperationFinish.bindStore(appsecFsStorage, this._onFsOperationFinishOrRenderEnd)
|
|
50
|
+
responseRenderStart.bindStore(appsecFsStorage, this._onResponseRenderStart)
|
|
51
|
+
responseRenderEnd.bindStore(appsecFsStorage, this._onFsOperationFinishOrRenderEnd)
|
|
41
52
|
}
|
|
42
53
|
|
|
43
54
|
disable () {
|
|
44
|
-
|
|
55
|
+
fsOperationStart.unbindStore(appsecFsStorage)
|
|
56
|
+
fsOperationFinish.unbindStore(appsecFsStorage)
|
|
57
|
+
responseRenderStart.unbindStore(appsecFsStorage)
|
|
58
|
+
responseRenderEnd.unbindStore(appsecFsStorage)
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
_onFsOperationStart () {
|
|
48
|
-
const store =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
62
|
+
const store = appsecFsStorage.getStore()
|
|
63
|
+
|
|
64
|
+
return getStoreToStart({ root: store?.root === undefined }, store)
|
|
52
65
|
}
|
|
53
66
|
|
|
54
67
|
_onResponseRenderStart () {
|
|
@@ -56,11 +69,7 @@ class AppsecFsPlugin extends Plugin {
|
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
_onFsOperationFinishOrRenderEnd () {
|
|
59
|
-
|
|
60
|
-
if (store?.fs) {
|
|
61
|
-
return store.fs.parentStore
|
|
62
|
-
}
|
|
63
|
-
return store
|
|
72
|
+
return appsecFsStorage.getStore()?.parentStore
|
|
64
73
|
}
|
|
65
74
|
}
|
|
66
75
|
|
|
@@ -97,6 +106,7 @@ module.exports = {
|
|
|
97
106
|
disable,
|
|
98
107
|
|
|
99
108
|
AppsecFsPlugin,
|
|
109
|
+
APPSEC_FS_STORAGE,
|
|
100
110
|
|
|
101
111
|
RASP_MODULE,
|
|
102
112
|
IAST_MODULE,
|
|
@@ -6,9 +6,14 @@ const { fsOperationStart, incomingHttpRequestStart, expressResponseRenderStart }
|
|
|
6
6
|
const { storage } = require('../../../../datadog-core')
|
|
7
7
|
const web = require('../../plugins/util/web')
|
|
8
8
|
const { FS_OPERATION_PATH } = require('../addresses')
|
|
9
|
-
const {
|
|
9
|
+
const { getActiveRequest } = require('../store')
|
|
10
10
|
const waf = require('../waf')
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
APPSEC_FS_STORAGE,
|
|
13
|
+
enable: enableFsPlugin,
|
|
14
|
+
disable: disableFsPlugin,
|
|
15
|
+
RASP_MODULE,
|
|
16
|
+
} = require('./fs-plugin')
|
|
12
17
|
const { RULE_TYPES, handleResult } = require('./utils')
|
|
13
18
|
|
|
14
19
|
let config
|
|
@@ -59,11 +64,10 @@ function analyzeLfiInResponseRender (ctx) {
|
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
function analyzeLfi (ctx) {
|
|
62
|
-
const
|
|
63
|
-
const fs = store?.fs
|
|
67
|
+
const fs = storage(APPSEC_FS_STORAGE).getStore()
|
|
64
68
|
if (!fs) return
|
|
65
69
|
|
|
66
|
-
const req =
|
|
70
|
+
const req = getActiveRequest()
|
|
67
71
|
if (!req) return
|
|
68
72
|
|
|
69
73
|
const res = web.getContext(req)?.res
|
|
@@ -8,7 +8,7 @@ const web = require('../plugins/util/web')
|
|
|
8
8
|
const { ipHeaderList } = require('../plugins/util/ip_extractor')
|
|
9
9
|
const { keepTrace } = require('../priority_sampler')
|
|
10
10
|
const { ASM } = require('../standalone/product')
|
|
11
|
-
const { isEmpty, truncateString } = require('../util')
|
|
11
|
+
const { isEmpty, truncateString, typedArrayLength } = require('../util')
|
|
12
12
|
const { getActiveRequest } = require('./store')
|
|
13
13
|
const {
|
|
14
14
|
incrementWafInitMetric,
|
|
@@ -431,6 +431,20 @@ function reportAttack ({ events: attackData, actions }, req, rootSpan) {
|
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Copies the first elements by index, the one typed array access that user code cannot override, unlike `subarray`,
|
|
436
|
+
* `toJSON` or their species constructors. The result keeps the shape `Buffer#toJSON` and `Object.keys` produce.
|
|
437
|
+
*
|
|
438
|
+
* @param {import('../util').BinaryView} view
|
|
439
|
+
*/
|
|
440
|
+
function truncateTypedArray (view) {
|
|
441
|
+
const data = new Array(COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE)
|
|
442
|
+
for (let i = 0; i < COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE; i++) {
|
|
443
|
+
data[i] = view[i]
|
|
444
|
+
}
|
|
445
|
+
return Buffer.isBuffer(view) ? { type: 'Buffer', data } : { ...data }
|
|
446
|
+
}
|
|
447
|
+
|
|
434
448
|
function truncateRequestBody (target, depth = 0) {
|
|
435
449
|
switch (typeof target) {
|
|
436
450
|
case 'string':
|
|
@@ -447,6 +461,12 @@ function truncateRequestBody (target, depth = 0) {
|
|
|
447
461
|
return { truncated: true }
|
|
448
462
|
}
|
|
449
463
|
|
|
464
|
+
// `Buffer#toJSON` and `Object.keys` both materialize one entry per byte, so cut large binary views down
|
|
465
|
+
// before they are serialized.
|
|
466
|
+
if (ArrayBuffer.isView(target) && typedArrayLength(target) > COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE) {
|
|
467
|
+
return { value: truncateTypedArray(target), truncated: true }
|
|
468
|
+
}
|
|
469
|
+
|
|
450
470
|
if (typeof target.toJSON === 'function') {
|
|
451
471
|
try {
|
|
452
472
|
return truncateRequestBody(target.toJSON(), depth + 1)
|
|
@@ -34,8 +34,9 @@ function getCallSiteList (maxDepth = 100, constructorOpt) {
|
|
|
34
34
|
|
|
35
35
|
function filterOutFramesFromLibrary (callSiteList) {
|
|
36
36
|
return callSiteList.filter(callSite => {
|
|
37
|
-
if (globalThis.__DD_ESBUILD_IAST_WITH_NO_SM) {
|
|
38
|
-
// bundled
|
|
37
|
+
if (globalThis.__DD_ESBUILD_IAST_WITH_NO_SM || ddBasePath === undefined) {
|
|
38
|
+
// bundled without a SourceMap, or dd-trace's location is unknown: not possible to discriminate if the frame
|
|
39
|
+
// comes from dd-trace code or not
|
|
39
40
|
return true
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -81,8 +82,7 @@ function getCallsiteFrames (maxDepth = 32, constructorOpt = getCallsiteFrames, c
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
function reportStackTrace (rootSpan, stackId, frames, namespace = STACK_TRACE_NAMESPACES.RASP) {
|
|
84
|
-
if (!rootSpan) return
|
|
85
|
-
if (!Array.isArray(frames)) return
|
|
85
|
+
if (!rootSpan || !Array.isArray(frames)) return
|
|
86
86
|
|
|
87
87
|
if (!rootSpan.meta_struct) {
|
|
88
88
|
rootSpan.meta_struct = {}
|
|
@@ -86,12 +86,9 @@ function getDynamicAtrBuckets (value) {
|
|
|
86
86
|
* @param {number[] | null} customBuckets
|
|
87
87
|
*/
|
|
88
88
|
function getDynamicAtrRetryCount (durationMs, efdRetryPolicy, customBuckets) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
} else {
|
|
93
|
-
retryCount = retriesForDuration(durationMs, efdRetryPolicy)
|
|
94
|
-
}
|
|
89
|
+
const retryCount = customBuckets
|
|
90
|
+
? customBuckets[retryBucketIndexForDuration(durationMs)]
|
|
91
|
+
: retriesForDuration(durationMs, efdRetryPolicy)
|
|
95
92
|
return Math.max(1, retryCount)
|
|
96
93
|
}
|
|
97
94
|
|
|
@@ -228,9 +228,10 @@ async function addBreakpoint (probe) {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
function start () {
|
|
231
|
+
async function start () {
|
|
232
|
+
await session.post('Debugger.enable')
|
|
233
|
+
// Only flag the session as started once enabled, so the next probe retries a failed start and reports its cause
|
|
232
234
|
sessionStarted = true
|
|
233
|
-
return session.post('Debugger.enable') // return instead of await to reduce number of promises created
|
|
234
235
|
}
|
|
235
236
|
|
|
236
237
|
function drainBreakpointHitRequests () {
|
|
@@ -224,7 +224,7 @@ class MsgpackJsonConverter {
|
|
|
224
224
|
* @param {number} value decoded floating-point value
|
|
225
225
|
*/
|
|
226
226
|
#writeFloat (value) {
|
|
227
|
-
if (!Number.isFinite(value)) throw new
|
|
227
|
+
if (!Number.isFinite(value)) throw new TypeError('MessagePack validation payload contains a non-finite number.')
|
|
228
228
|
this.#writer.write(Object.is(value, -0) ? '-0' : String(value))
|
|
229
229
|
}
|
|
230
230
|
|
|
@@ -114,10 +114,14 @@ function isValidRetryCount (value) {
|
|
|
114
114
|
* @param {unknown} retryPolicy - Candidate retry policy.
|
|
115
115
|
*/
|
|
116
116
|
function isValidCachedEfdRetryPolicy (retryPolicy) {
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
retryPolicy
|
|
117
|
+
if (
|
|
118
|
+
retryPolicy === null ||
|
|
119
|
+
typeof retryPolicy !== 'object' ||
|
|
120
|
+
Array.isArray(retryPolicy) ||
|
|
121
|
+
!isValidRetryCount(retryPolicy.schedulingRetryCount) ||
|
|
122
|
+
!Array.isArray(retryPolicy.durationRetryCounts) ||
|
|
123
|
+
retryPolicy.durationRetryCounts.length !== EMPTY_EFD_RETRY_POLICY.durationRetryCounts.length
|
|
124
|
+
) {
|
|
121
125
|
return false
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -152,9 +156,11 @@ function isValidCachedSettings (settings) {
|
|
|
152
156
|
}
|
|
153
157
|
if (settings.isDiEnabled && !settings.isFlakyTestRetriesEnabled) return false
|
|
154
158
|
if (settings.isEarlyFlakeDetectionEnabled && !settings.isKnownTestsEnabled) return false
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
settings.earlyFlakeDetectionFaultyThreshold
|
|
159
|
+
if (
|
|
160
|
+
!isValidCachedEfdRetryPolicy(settings.earlyFlakeDetectionRetryPolicy) ||
|
|
161
|
+
!isNonNegativeSafeInteger(settings.earlyFlakeDetectionFaultyThreshold) ||
|
|
162
|
+
settings.earlyFlakeDetectionFaultyThreshold > 100
|
|
163
|
+
) {
|
|
158
164
|
return false
|
|
159
165
|
}
|
|
160
166
|
return settings.testManagementAttemptToFixRetries === undefined ||
|
|
@@ -12,8 +12,7 @@ const getConfig = require('../../config')
|
|
|
12
12
|
* @param {object} configuration - Request configuration for the settings endpoint.
|
|
13
13
|
*/
|
|
14
14
|
function buildSettingsCacheKey (configuration) {
|
|
15
|
-
const
|
|
16
|
-
const { testOptimization } = config
|
|
15
|
+
const { testOptimization } = getConfig()
|
|
17
16
|
return buildCacheKey('settings', [
|
|
18
17
|
tracerVersion,
|
|
19
18
|
configuration.url?.href,
|
|
@@ -35,10 +35,7 @@ function getInterprocessTraceCode () {
|
|
|
35
35
|
if (DD_PLAYWRIGHT_WORKER) {
|
|
36
36
|
return PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE
|
|
37
37
|
}
|
|
38
|
-
if (getEnvironmentVariable('TINYPOOL_WORKER_ID')) {
|
|
39
|
-
return VITEST_WORKER_TRACE_PAYLOAD_CODE
|
|
40
|
-
}
|
|
41
|
-
if (DD_VITEST_WORKER) {
|
|
38
|
+
if (getEnvironmentVariable('TINYPOOL_WORKER_ID') || DD_VITEST_WORKER) {
|
|
42
39
|
return VITEST_WORKER_TRACE_PAYLOAD_CODE
|
|
43
40
|
}
|
|
44
41
|
return null
|
|
@@ -62,10 +59,7 @@ function getInterprocessLogsCode () {
|
|
|
62
59
|
if (getEnvironmentVariable('MOCHA_WORKER_ID') === 'webdriverio') {
|
|
63
60
|
return MOCHA_WORKER_LOGS_PAYLOAD_CODE
|
|
64
61
|
}
|
|
65
|
-
if (getEnvironmentVariable('TINYPOOL_WORKER_ID')) {
|
|
66
|
-
return VITEST_WORKER_LOGS_PAYLOAD_CODE
|
|
67
|
-
}
|
|
68
|
-
if (getConfig().DD_VITEST_WORKER) {
|
|
62
|
+
if (getEnvironmentVariable('TINYPOOL_WORKER_ID') || getConfig().DD_VITEST_WORKER) {
|
|
69
63
|
return VITEST_WORKER_LOGS_PAYLOAD_CODE
|
|
70
64
|
}
|
|
71
65
|
return null
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs')
|
|
4
|
+
const path = require('node:path')
|
|
5
|
+
|
|
6
|
+
const log = require('../log')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} filePath
|
|
10
|
+
* @param {Record<string, string | undefined>} env
|
|
11
|
+
*/
|
|
12
|
+
function resolveRunfilePath (filePath, env) {
|
|
13
|
+
if (fs.existsSync(filePath)) return filePath
|
|
14
|
+
|
|
15
|
+
const runfilesDir = env.RUNFILES_DIR
|
|
16
|
+
if (runfilesDir) {
|
|
17
|
+
const candidate = path.join(runfilesDir, filePath)
|
|
18
|
+
if (fs.existsSync(candidate)) return candidate
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const manifestCandidate = resolveFromManifest(filePath, env.RUNFILES_MANIFEST_FILE)
|
|
22
|
+
if (manifestCandidate) return manifestCandidate
|
|
23
|
+
|
|
24
|
+
const testSrcdir = env.TEST_SRCDIR
|
|
25
|
+
if (testSrcdir) {
|
|
26
|
+
const candidate = path.join(testSrcdir, filePath)
|
|
27
|
+
if (fs.existsSync(candidate)) return candidate
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return filePath
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} filePath
|
|
35
|
+
* @param {string | undefined} runfilesManifest
|
|
36
|
+
*/
|
|
37
|
+
function resolveFromManifest (filePath, runfilesManifest) {
|
|
38
|
+
if (!runfilesManifest || !fs.existsSync(runfilesManifest)) return
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const lines = fs.readFileSync(runfilesManifest, 'utf8').split('\n')
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
const separatorIndex = line.indexOf(' ')
|
|
44
|
+
if (separatorIndex <= 0 || line.slice(0, separatorIndex) !== filePath) continue
|
|
45
|
+
|
|
46
|
+
const resolvedPath = line.slice(separatorIndex + 1).trim()
|
|
47
|
+
if (resolvedPath) return resolvedPath
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
log.debug('Failed to resolve Test Optimization runfile from %s: %s', runfilesManifest, err.message)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = resolveRunfilePath
|
|
@@ -75,14 +75,12 @@ function validateSettingsResponse (response, options = {}) {
|
|
|
75
75
|
assertBooleanFields(attributes.test_management, ['enabled'], 'settings test_management')
|
|
76
76
|
assertOptionalBoundedNumber(
|
|
77
77
|
attributes.early_flake_detection.faulty_session_threshold,
|
|
78
|
-
'settings early_flake_detection faulty_session_threshold'
|
|
79
|
-
{ integer: true }
|
|
78
|
+
'settings early_flake_detection faulty_session_threshold'
|
|
80
79
|
)
|
|
81
80
|
assertRetryMap(attributes.early_flake_detection.slow_test_retries)
|
|
82
81
|
assertOptionalBoundedNumber(
|
|
83
82
|
attributes.test_management.attempt_to_fix_retries,
|
|
84
|
-
'settings test_management attempt_to_fix_retries'
|
|
85
|
-
{ integer: true }
|
|
83
|
+
'settings test_management attempt_to_fix_retries'
|
|
86
84
|
)
|
|
87
85
|
}
|
|
88
86
|
|
|
@@ -214,10 +212,9 @@ function assertBooleanFields (object, keys, endpoint) {
|
|
|
214
212
|
}
|
|
215
213
|
}
|
|
216
214
|
|
|
217
|
-
function assertOptionalBoundedNumber (value, endpoint
|
|
215
|
+
function assertOptionalBoundedNumber (value, endpoint) {
|
|
218
216
|
if (value === undefined) return
|
|
219
|
-
if (!Number.isFinite(value) ||
|
|
220
|
-
value < 0 || value > MAX_RETRIES) {
|
|
217
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > MAX_RETRIES) {
|
|
221
218
|
throw new TypeError(`Invalid ${endpoint}: value must be between 0 and ${MAX_RETRIES}`)
|
|
222
219
|
}
|
|
223
220
|
}
|
|
@@ -230,7 +227,7 @@ function assertRetryMap (retries) {
|
|
|
230
227
|
if (!RETRY_THRESHOLD_PATTERN.test(threshold)) {
|
|
231
228
|
throw new TypeError('Invalid early flake detection retry threshold: expected a duration such as 5s')
|
|
232
229
|
}
|
|
233
|
-
assertOptionalBoundedNumber(count, `early flake detection retry count ${threshold}
|
|
230
|
+
assertOptionalBoundedNumber(count, `early flake detection retry count ${threshold}`)
|
|
234
231
|
}
|
|
235
232
|
}
|
|
236
233
|
|