dd-trace 6.16.0 → 6.17.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 +0 -23
- package/ci/test-optimization-validation/approval-artifacts.js +0 -3
- package/ci/test-optimization-validation/approval.js +0 -6
- package/ci/test-optimization-validation/artifact-id.js +0 -1
- package/ci/test-optimization-validation/bounded-json.js +0 -1
- package/ci/test-optimization-validation/cli.js +0 -12
- package/ci/test-optimization-validation/command-output-policy.js +0 -1
- package/ci/test-optimization-validation/command-runner.js +0 -3
- package/ci/test-optimization-validation/environment.js +0 -4
- package/ci/test-optimization-validation/executable-approval.js +0 -1
- package/ci/test-optimization-validation/executable.js +0 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +0 -6
- package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
- package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
- package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
- package/ci/test-optimization-validation/generated-test-contract.js +0 -5
- package/ci/test-optimization-validation/generated-verifier.js +0 -1
- package/ci/test-optimization-validation/literal-environment.js +0 -1
- package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
- package/ci/test-optimization-validation/manifest-schema.js +0 -21
- package/ci/test-optimization-validation/offline-fixtures.js +0 -4
- package/ci/test-optimization-validation/plan-writer.js +0 -11
- package/ci/test-optimization-validation/preflight-runner.js +0 -1
- package/ci/test-optimization-validation/redaction.js +0 -4
- package/ci/test-optimization-validation/report-writer.js +0 -16
- package/ci/test-optimization-validation/runner-command.js +0 -3
- package/ci/test-optimization-validation/runner-contract.js +0 -4
- package/ci/test-optimization-validation/safe-files.js +0 -1
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +0 -1
- package/ci/test-optimization-validation/source-text.js +0 -3
- package/ci/vitest-no-worker-init-setup.mjs +41 -16
- package/index.d.ts +165 -0
- package/package.json +17 -16
- package/packages/datadog-esbuild/src/utils.js +0 -2
- package/packages/datadog-instrumentations/src/aerospike.js +28 -6
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -2
- package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/console.js +97 -0
- package/packages/datadog-instrumentations/src/cucumber.js +72 -12
- package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
- package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
- package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +0 -3
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +72 -24
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +16 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
- package/packages/datadog-instrumentations/src/jest.js +141 -51
- package/packages/datadog-instrumentations/src/knex.js +0 -1
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
- package/packages/datadog-instrumentations/src/mariadb.js +0 -2
- package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +22 -25
- package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
- package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
- package/packages/datadog-instrumentations/src/mysql2.js +0 -2
- package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
- package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
- package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
- package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
- package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
- package/packages/datadog-instrumentations/src/openai.js +51 -12
- package/packages/datadog-instrumentations/src/oracledb.js +9 -3
- package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -16
- package/packages/datadog-instrumentations/src/playwright.js +238 -55
- package/packages/datadog-instrumentations/src/postgres.js +7 -0
- package/packages/datadog-instrumentations/src/router.js +0 -2
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
- package/packages/datadog-instrumentations/src/sequelize.js +0 -1
- package/packages/datadog-instrumentations/src/supabase.js +15 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
- package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
- package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
- package/packages/datadog-instrumentations/src/vitest-worker.js +49 -13
- package/packages/datadog-instrumentations/src/webdriverio.js +23 -42
- package/packages/datadog-instrumentations/src/ws.js +0 -1
- package/packages/datadog-plugin-ai/src/utils.js +0 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +0 -1
- package/packages/datadog-plugin-cucumber/src/index.js +10 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
- package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
- package/packages/datadog-plugin-cypress/src/support.js +52 -7
- package/packages/datadog-plugin-graphql/src/resolve-error.js +1 -2
- package/packages/datadog-plugin-graphql/src/utils.js +0 -5
- package/packages/datadog-plugin-jest/src/index.js +13 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
- package/packages/datadog-plugin-mocha/src/index.js +39 -11
- package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
- package/packages/datadog-plugin-openai/src/index.js +16 -1
- package/packages/datadog-plugin-openai/src/realtime.js +144 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
- package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
- package/packages/datadog-plugin-playwright/src/index.js +76 -9
- package/packages/datadog-plugin-postgres/src/index.js +167 -0
- package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
- package/packages/datadog-plugin-redis/src/index.js +15 -1
- package/packages/datadog-plugin-supabase/src/error.js +18 -0
- package/packages/datadog-plugin-supabase/src/index.js +21 -0
- package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
- package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
- package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
- package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
- package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
- package/packages/datadog-plugin-supabase/src/url.js +17 -0
- package/packages/datadog-plugin-vitest/src/index.js +10 -0
- package/packages/datadog-plugin-ws/src/util.js +0 -4
- package/packages/datadog-turbopack/index.js +0 -6
- package/packages/datadog-turbopack/src/loader.js +0 -16
- package/packages/datadog-webpack/src/loader.js +0 -1
- package/packages/dd-trace/src/aiguard/client.js +2 -3
- package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
- package/packages/dd-trace/src/aiguard/index.js +2 -2
- package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
- package/packages/dd-trace/src/aiguard/integrations/openai.js +81 -7
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
- package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
- package/packages/dd-trace/src/aiguard/messages/utils.js +0 -1
- package/packages/dd-trace/src/aiguard/redaction.js +0 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/activation.js +1 -1
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
- package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
- package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
- package/packages/dd-trace/src/appsec/index.js +2 -2
- package/packages/dd-trace/src/appsec/lambda.js +71 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
- package/packages/dd-trace/src/appsec/remote_config.js +8 -6
- package/packages/dd-trace/src/appsec/reporter.js +10 -6
- package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
- package/packages/dd-trace/src/carrier.js +0 -5
- package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
- package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
- package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +73 -67
- package/packages/dd-trace/src/config/helper.js +0 -1
- package/packages/dd-trace/src/config/index.js +24 -24
- package/packages/dd-trace/src/config/parsers.js +34 -6
- package/packages/dd-trace/src/config/remote_config.js +25 -109
- package/packages/dd-trace/src/config/supported-configurations.json +139 -10
- package/packages/dd-trace/src/datastreams/encoding.js +0 -1
- package/packages/dd-trace/src/datastreams/pathway.js +0 -1
- package/packages/dd-trace/src/debugger/constants.js +10 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +62 -10
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
- package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
- package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +21 -8
- package/packages/dd-trace/src/debugger/devtools_client/send.js +40 -14
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
- package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
- package/packages/dd-trace/src/debugger/index.js +50 -2
- package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
- package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
- package/packages/dd-trace/src/dogstatsd.js +0 -23
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
- package/packages/dd-trace/src/encode/0.4.js +0 -7
- package/packages/dd-trace/src/encode/0.5.js +0 -2
- package/packages/dd-trace/src/encode/tags-processors.js +0 -1
- package/packages/dd-trace/src/evp_proxy/discovery.js +0 -1
- package/packages/dd-trace/src/evp_proxy/path.js +0 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
- package/packages/dd-trace/src/exporters/common/request.js +1 -0
- package/packages/dd-trace/src/exporters/common/url.js +0 -2
- package/packages/dd-trace/src/exporters/common/writer.js +0 -2
- package/packages/dd-trace/src/id.js +0 -11
- package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
- package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
- package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
- package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
- package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
- package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
- package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
- package/packages/dd-trace/src/llmobs/index.js +1 -3
- package/packages/dd-trace/src/llmobs/noop.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
- package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
- package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +639 -0
- package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -0
- package/packages/dd-trace/src/llmobs/sdk.js +21 -6
- package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
- package/packages/dd-trace/src/llmobs/tagger.js +30 -7
- package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
- package/packages/dd-trace/src/llmobs/util.js +0 -34
- package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
- package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
- package/packages/dd-trace/src/log/channels.js +3 -0
- package/packages/dd-trace/src/log/index.js +23 -5
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
- package/packages/dd-trace/src/msgpack/chunk.js +0 -1
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
- package/packages/dd-trace/src/openfeature/encoding.js +0 -2
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/index.js +0 -4
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
- package/packages/dd-trace/src/openfeature/writers/base.js +0 -6
- package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
- package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -14
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +30 -13
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
- package/packages/dd-trace/src/opentracing/span_context.js +0 -1
- package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
- package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
- package/packages/dd-trace/src/plugins/database.js +2 -6
- package/packages/dd-trace/src/plugins/index.js +7 -0
- package/packages/dd-trace/src/plugins/plugin.js +0 -4
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/git.js +1 -3
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
- package/packages/dd-trace/src/plugins/util/llm.js +0 -2
- package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
- package/packages/dd-trace/src/plugins/util/test.js +21 -20
- package/packages/dd-trace/src/plugins/util/url.js +0 -5
- package/packages/dd-trace/src/priority_sampler.js +0 -6
- package/packages/dd-trace/src/process-tags/index.js +0 -1
- package/packages/dd-trace/src/profiler.js +132 -35
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
- package/packages/dd-trace/src/profiling/profiler.js +101 -41
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
- package/packages/dd-trace/src/propagation-hash/index.js +0 -1
- package/packages/dd-trace/src/proxy.js +21 -45
- package/packages/dd-trace/src/random_sampler.js +0 -4
- package/packages/dd-trace/src/rate_limiter.js +0 -4
- package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
- package/packages/dd-trace/src/remote_config/index.js +0 -1
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
- package/packages/dd-trace/src/sampler.js +0 -4
- package/packages/dd-trace/src/sampling_rule.js +0 -7
- package/packages/dd-trace/src/serverless/vercel.js +0 -1
- package/packages/dd-trace/src/serverless.js +0 -1
- package/packages/dd-trace/src/service-naming/index.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
- package/packages/dd-trace/src/span_processor.js +2 -2
- package/packages/dd-trace/src/span_sampler.js +0 -1
- package/packages/dd-trace/src/standalone/product.js +2 -2
- package/packages/dd-trace/src/standalone/tracesource.js +0 -1
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
- package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
- package/packages/dd-trace/src/telemetry/metrics.js +0 -2
- package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
- package/packages/dd-trace/src/util.js +13 -1
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
|
@@ -11,6 +11,8 @@ const waf = require('./waf')
|
|
|
11
11
|
|
|
12
12
|
const activeInvocations = new WeakMap()
|
|
13
13
|
|
|
14
|
+
const MAX_RESPONSE_BODY_SIZE = 16 * 1024 * 1024
|
|
15
|
+
|
|
14
16
|
/**
|
|
15
17
|
* Maps pre-extracted HTTP data from the Lambda event to WAF addresses,
|
|
16
18
|
* runs the WAF, and reports results on the span.
|
|
@@ -86,11 +88,12 @@ function onLambdaStartInvocation (data) {
|
|
|
86
88
|
* WAF pass, disposes the WAF context, and finishes the request report.
|
|
87
89
|
*
|
|
88
90
|
* @param {{ span: object, statusCode: string | undefined,
|
|
89
|
-
* responseHeaders: Record<string, string> | undefined
|
|
91
|
+
* responseHeaders: Record<string, string> | undefined,
|
|
92
|
+
* responseBody: unknown, isBase64Encoded: boolean | undefined }} data
|
|
90
93
|
*/
|
|
91
94
|
function onLambdaEndInvocation (data) {
|
|
92
95
|
try {
|
|
93
|
-
const { span, statusCode, responseHeaders } = data
|
|
96
|
+
const { span, statusCode, responseHeaders, responseBody, isBase64Encoded } = data
|
|
94
97
|
|
|
95
98
|
if (!span) {
|
|
96
99
|
log.warn('[ASM] No span provided in Lambda end invocation')
|
|
@@ -127,6 +130,11 @@ function onLambdaEndInvocation (data) {
|
|
|
127
130
|
|
|
128
131
|
if (samplingDecision === apiSecurity.SamplingDecision.SAMPLE) {
|
|
129
132
|
persistent[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
|
|
133
|
+
|
|
134
|
+
const parsedBody = parseResponseBody(responseBody, responseHeaders, isBase64Encoded)
|
|
135
|
+
if (parsedBody !== undefined) {
|
|
136
|
+
persistent[addresses.HTTP_INCOMING_RESPONSE_BODY] = parsedBody
|
|
137
|
+
}
|
|
130
138
|
}
|
|
131
139
|
|
|
132
140
|
let wafResult
|
|
@@ -147,6 +155,67 @@ function onLambdaEndInvocation (data) {
|
|
|
147
155
|
}
|
|
148
156
|
}
|
|
149
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Turns the raw response body published by the Lambda layer into the object the WAF expects
|
|
160
|
+
*
|
|
161
|
+
* @param {unknown} rawBody
|
|
162
|
+
* @param {Record<string, string> | undefined} headers Already lowercased by the Lambda layer
|
|
163
|
+
* @param {boolean | undefined} isBase64Encoded
|
|
164
|
+
* @returns {object | undefined} The parsed body, or `undefined` when it cannot be used
|
|
165
|
+
*/
|
|
166
|
+
function parseResponseBody (rawBody, headers, isBase64Encoded) {
|
|
167
|
+
if (!rawBody) return
|
|
168
|
+
|
|
169
|
+
// A handler that answered with the payload itself needs no parsing, and no content type either.
|
|
170
|
+
if (typeof rawBody === 'object') return rawBody
|
|
171
|
+
|
|
172
|
+
if (typeof rawBody !== 'string') return
|
|
173
|
+
|
|
174
|
+
if (!isJsonContentType(headers?.['content-type'])) return
|
|
175
|
+
|
|
176
|
+
if (isOverSizeCap(rawBody, isBase64Encoded)) {
|
|
177
|
+
log.debug('[ASM] Lambda response body larger than %d bytes, skipping schema extraction',
|
|
178
|
+
MAX_RESPONSE_BODY_SIZE)
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const contentEncoding = headers?.['content-encoding']?.toLowerCase()
|
|
183
|
+
if (contentEncoding && contentEncoding !== 'identity') return
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const parsed = JSON.parse(isBase64Encoded ? Buffer.from(rawBody, 'base64').toString('utf8') : rawBody)
|
|
187
|
+
|
|
188
|
+
// A JSON scalar carries no schema worth extracting.
|
|
189
|
+
if (parsed === null || typeof parsed !== 'object') return
|
|
190
|
+
|
|
191
|
+
return parsed
|
|
192
|
+
} catch {
|
|
193
|
+
// The SyntaxError message embeds a fragment of the body, which is customer data.
|
|
194
|
+
log.debug('[ASM] Failed to parse Lambda response body')
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {string | undefined} contentType
|
|
200
|
+
*/
|
|
201
|
+
function isJsonContentType (contentType) {
|
|
202
|
+
return typeof contentType === 'string' && contentType.toLowerCase().includes('json')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Tells whether a raw body exceeds the size cap, without decoding or measuring it when avoidable
|
|
207
|
+
*
|
|
208
|
+
* @param {string} rawBody
|
|
209
|
+
* @param {boolean | undefined} isBase64Encoded
|
|
210
|
+
*/
|
|
211
|
+
function isOverSizeCap (rawBody, isBase64Encoded) {
|
|
212
|
+
if (isBase64Encoded) return Math.floor(rawBody.length * 3 / 4) >= MAX_RESPONSE_BODY_SIZE
|
|
213
|
+
if (rawBody.length >= MAX_RESPONSE_BODY_SIZE) return true
|
|
214
|
+
if (rawBody.length * 3 < MAX_RESPONSE_BODY_SIZE) return false
|
|
215
|
+
|
|
216
|
+
return Buffer.byteLength(rawBody, 'utf8') >= MAX_RESPONSE_BODY_SIZE
|
|
217
|
+
}
|
|
218
|
+
|
|
150
219
|
module.exports = {
|
|
151
220
|
onLambdaStartInvocation,
|
|
152
221
|
onLambdaEndInvocation,
|
|
@@ -45,7 +45,11 @@ class DatadogRaspAbortError extends Error {
|
|
|
45
45
|
function handleResult (result, req, res, abortController, config, raspRule) {
|
|
46
46
|
const generateStackTraceAction = result?.actions?.generate_stack
|
|
47
47
|
|
|
48
|
-
const {
|
|
48
|
+
const {
|
|
49
|
+
DD_APPSEC_STACK_TRACE_ENABLED: enabled,
|
|
50
|
+
DD_APPSEC_MAX_STACK_TRACE_DEPTH: maxDepth,
|
|
51
|
+
DD_APPSEC_MAX_STACK_TRACES: maxStackTraces,
|
|
52
|
+
} = config.appsec
|
|
49
53
|
|
|
50
54
|
const rootSpan = web.root(req)
|
|
51
55
|
|
|
@@ -43,7 +43,7 @@ function enable (rcInstance, config, appsec) {
|
|
|
43
43
|
setCollectionMode(rcConfig.auto_user_instrum.mode)
|
|
44
44
|
autoUserInstrumModeId = configId
|
|
45
45
|
} else if (configId === autoUserInstrumModeId) {
|
|
46
|
-
setCollectionMode(config.appsec.
|
|
46
|
+
setCollectionMode(config.appsec.DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE)
|
|
47
47
|
autoUserInstrumModeId = null
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -68,7 +68,7 @@ function enableOrDisableAppsec (action, rcConfig, config, appsec) {
|
|
|
68
68
|
const isRemoteConfigControlling = action === 'apply' || action === 'modify'
|
|
69
69
|
const shouldEnable = isRemoteConfigControlling
|
|
70
70
|
? rcConfig.asm.enabled // take control
|
|
71
|
-
: config.appsec.
|
|
71
|
+
: config.appsec.DD_APPSEC_ENABLED // give back control to local config
|
|
72
72
|
|
|
73
73
|
if (shouldEnable) {
|
|
74
74
|
appsec.enable(config)
|
|
@@ -79,8 +79,10 @@ function enableOrDisableAppsec (action, rcConfig, config, appsec) {
|
|
|
79
79
|
// TODO: Use configWithOrigin /generateTelemetry instead of manually constructing the change.
|
|
80
80
|
updateConfig([
|
|
81
81
|
{
|
|
82
|
-
name: '
|
|
83
|
-
origin: isRemoteConfigControlling
|
|
82
|
+
name: 'DD_APPSEC_ENABLED',
|
|
83
|
+
origin: isRemoteConfigControlling
|
|
84
|
+
? 'remote_config'
|
|
85
|
+
: config.getOrigin('appsec.DD_APPSEC_ENABLED'),
|
|
84
86
|
value: shouldEnable,
|
|
85
87
|
},
|
|
86
88
|
], config)
|
|
@@ -93,7 +95,7 @@ function enableOrDisableAppsec (action, rcConfig, config, appsec) {
|
|
|
93
95
|
* @param {object} appsecConfig - Appsec config
|
|
94
96
|
*/
|
|
95
97
|
function enableWafUpdate (appsecConfig) {
|
|
96
|
-
if (rc && appsecConfig && !appsecConfig.
|
|
98
|
+
if (rc && appsecConfig && !appsecConfig.DD_APPSEC_RULES) {
|
|
97
99
|
// dirty require to make startup faster for serverless
|
|
98
100
|
const { ASM_WAF_PRODUCTS } = require('./rc-products')
|
|
99
101
|
const RuleManager = require('./rule_manager')
|
|
@@ -119,7 +121,7 @@ function enableWafUpdate (appsecConfig) {
|
|
|
119
121
|
rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true)
|
|
120
122
|
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXTENDED_DATA_COLLECTION, true)
|
|
121
123
|
|
|
122
|
-
if (appsecConfig.
|
|
124
|
+
if (appsecConfig.DD_APPSEC_RASP_ENABLED) {
|
|
123
125
|
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, true)
|
|
124
126
|
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SSRF, true)
|
|
125
127
|
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_LFI, true)
|
|
@@ -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 } = require('../util')
|
|
11
|
+
const { isEmpty, truncateString } = require('../util')
|
|
12
12
|
const { getActiveRequest } = require('./store')
|
|
13
13
|
const {
|
|
14
14
|
incrementWafInitMetric,
|
|
@@ -114,11 +114,15 @@ const NON_EXTENDED_REQUEST_HEADERS = new Set([...requestHeadersList, ...eventHea
|
|
|
114
114
|
const NON_EXTENDED_RESPONSE_HEADERS = new Set(responseHeaderList)
|
|
115
115
|
const REDACTED_HEADERS = new Set(redactedHeadersList)
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* @param {import('../config/config-types').ConfigProperties['appsec']} _config
|
|
119
|
+
* @param {boolean} [inferredProxyServicesEnabled]
|
|
120
|
+
*/
|
|
117
121
|
function init (_config, inferredProxyServicesEnabled) {
|
|
118
|
-
config.headersExtendedCollectionEnabled = _config.
|
|
119
|
-
config.maxHeadersCollected = _config.
|
|
120
|
-
config.headersRedaction = _config.
|
|
121
|
-
config.raspBodyCollection = _config.
|
|
122
|
+
config.headersExtendedCollectionEnabled = _config.DD_APPSEC_COLLECT_ALL_HEADERS
|
|
123
|
+
config.maxHeadersCollected = _config.DD_APPSEC_MAX_COLLECTED_HEADERS
|
|
124
|
+
config.headersRedaction = _config.DD_APPSEC_HEADER_COLLECTION_REDACTION_ENABLED
|
|
125
|
+
config.raspBodyCollection = _config.DD_APPSEC_RASP_COLLECT_REQUEST_BODY
|
|
122
126
|
config.inferredProxyServicesEnabled = inferredProxyServicesEnabled
|
|
123
127
|
}
|
|
124
128
|
|
|
@@ -431,7 +435,7 @@ function truncateRequestBody (target, depth = 0) {
|
|
|
431
435
|
switch (typeof target) {
|
|
432
436
|
case 'string':
|
|
433
437
|
if (target.length > COLLECTED_REQUEST_BODY_MAX_STRING_LENGTH) {
|
|
434
|
-
return { value: target
|
|
438
|
+
return { value: truncateString(target, COLLECTED_REQUEST_BODY_MAX_STRING_LENGTH), truncated: true }
|
|
435
439
|
}
|
|
436
440
|
return { value: target, truncated: false }
|
|
437
441
|
case 'object': {
|
|
@@ -20,15 +20,15 @@ let appliedActions = new Map()
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* @typedef {import('./waf').WAFConfig & {
|
|
23
|
+
* @typedef {import('./waf').WAFConfig & { DD_APPSEC_RULES?: string }} AppSecConfig
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* @param {AppSecConfig} config
|
|
28
28
|
*/
|
|
29
29
|
function loadRules (config) {
|
|
30
|
-
const defaultRules = config.
|
|
31
|
-
? JSON.parse(readFileSync(config.
|
|
30
|
+
const defaultRules = config.DD_APPSEC_RULES
|
|
31
|
+
? JSON.parse(readFileSync(config.DD_APPSEC_RULES, 'utf8'))
|
|
32
32
|
: require('./recommended.json')
|
|
33
33
|
|
|
34
34
|
waf.init(defaultRules, config)
|
|
@@ -14,7 +14,6 @@ const { getRootSpan } = require('./utils')
|
|
|
14
14
|
* @param {import('../../tracer')} tracer
|
|
15
15
|
* @param {import('../../../../../index').User} user
|
|
16
16
|
* @param {Record<string, string>} [metadata]
|
|
17
|
-
* @returns {void}
|
|
18
17
|
*/
|
|
19
18
|
function trackUserLoginSuccessEvent (tracer, user, metadata) {
|
|
20
19
|
// TODO: better user check here and in _setUser() ?
|
|
@@ -48,7 +47,6 @@ function trackUserLoginSuccessEvent (tracer, user, metadata) {
|
|
|
48
47
|
* @param {string} userId
|
|
49
48
|
* @param {boolean} exists
|
|
50
49
|
* @param {Record<string, string>} [metadata]
|
|
51
|
-
* @returns {void}
|
|
52
50
|
*/
|
|
53
51
|
function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
|
|
54
52
|
if (!userId || typeof userId !== 'string') {
|
|
@@ -25,7 +25,7 @@ let limiter = new Limiter(100)
|
|
|
25
25
|
let WAFManager = null
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* @typedef {import('./waf_manager').WAFManagerConfig & {
|
|
28
|
+
* @typedef {import('./waf_manager').WAFManagerConfig & { DD_APPSEC_TRACE_RATE_LIMIT: number }} WAFConfig
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
const waf = {
|
|
@@ -48,7 +48,7 @@ const waf = {
|
|
|
48
48
|
function init (rules, config) {
|
|
49
49
|
destroy()
|
|
50
50
|
|
|
51
|
-
limiter = new Limiter(config.
|
|
51
|
+
limiter = new Limiter(config.DD_APPSEC_TRACE_RATE_LIMIT)
|
|
52
52
|
|
|
53
53
|
// Lazy loading improves the startup time
|
|
54
54
|
WAFManager = require('./waf_manager')
|
|
@@ -8,9 +8,9 @@ const contexts = new WeakMap()
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {object} WAFManagerConfig
|
|
11
|
-
* @property {number}
|
|
12
|
-
* @property {string}
|
|
13
|
-
* @property {string}
|
|
11
|
+
* @property {number} DD_APPSEC_WAF_TIMEOUT - Maximum time in microseconds for WAF execution
|
|
12
|
+
* @property {string} DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP - Regex to redact sensitive data by key
|
|
13
|
+
* @property {string} DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP - Regex to redact sensitive data by value
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
class WAFManager {
|
|
@@ -22,7 +22,7 @@ class WAFManager {
|
|
|
22
22
|
*/
|
|
23
23
|
constructor (rules, config) {
|
|
24
24
|
this.config = config
|
|
25
|
-
this.wafTimeout = config.
|
|
25
|
+
this.wafTimeout = config.DD_APPSEC_WAF_TIMEOUT
|
|
26
26
|
this.ddwaf = this._loadDDWAF(rules)
|
|
27
27
|
this.rulesVersion = this.ddwaf.diagnostics.ruleset_version
|
|
28
28
|
this.defaultRules = rules
|
|
@@ -36,7 +36,10 @@ class WAFManager {
|
|
|
36
36
|
const { DDWAF } = require('@datadog/native-appsec')
|
|
37
37
|
this.ddwafVersion = DDWAF.version()
|
|
38
38
|
|
|
39
|
-
const {
|
|
39
|
+
const {
|
|
40
|
+
DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP: obfuscatorKeyRegex,
|
|
41
|
+
DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP: obfuscatorValueRegex,
|
|
42
|
+
} = this.config
|
|
40
43
|
return new DDWAF(rules, WAFManager.defaultWafConfigPath, { obfuscatorKeyRegex, obfuscatorValueRegex })
|
|
41
44
|
} catch (err) {
|
|
42
45
|
this.ddwafVersion ||= 'unknown'
|
|
@@ -81,7 +81,6 @@ function defineField (fieldName, headerName, read, operations) {
|
|
|
81
81
|
/**
|
|
82
82
|
* @param {Carrier} carrier
|
|
83
83
|
* @param {Value} value
|
|
84
|
-
* @returns {void}
|
|
85
84
|
*/
|
|
86
85
|
write (carrier, value) {
|
|
87
86
|
carrier[headerName] = value
|
|
@@ -89,7 +88,6 @@ function defineField (fieldName, headerName, read, operations) {
|
|
|
89
88
|
|
|
90
89
|
/**
|
|
91
90
|
* @param {Carrier} carrier
|
|
92
|
-
* @returns {boolean}
|
|
93
91
|
*/
|
|
94
92
|
has (carrier) {
|
|
95
93
|
return headerName in carrier
|
|
@@ -97,7 +95,6 @@ function defineField (fieldName, headerName, read, operations) {
|
|
|
97
95
|
|
|
98
96
|
/**
|
|
99
97
|
* @param {Carrier} carrier
|
|
100
|
-
* @returns {void}
|
|
101
98
|
*/
|
|
102
99
|
delete (carrier) {
|
|
103
100
|
delete carrier[headerName]
|
|
@@ -106,7 +103,6 @@ function defineField (fieldName, headerName, read, operations) {
|
|
|
106
103
|
/**
|
|
107
104
|
* @param {Carrier} carrier
|
|
108
105
|
* @param {Carrier} target
|
|
109
|
-
* @returns {void}
|
|
110
106
|
*/
|
|
111
107
|
copy (carrier, target) {
|
|
112
108
|
if (Object.hasOwn(carrier, headerName)) target[headerName] = carrier[headerName]
|
|
@@ -308,7 +304,6 @@ defineCapability('legacyBaggage', FIELD_READ | FIELD_WRITE, {
|
|
|
308
304
|
/**
|
|
309
305
|
* @param {Carrier} carrier
|
|
310
306
|
* @param {Record<string, string>} target
|
|
311
|
-
* @returns {void}
|
|
312
307
|
*/
|
|
313
308
|
read (carrier, target) {
|
|
314
309
|
for (const name of Object.keys(carrier)) {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../log')
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
retriesForDuration,
|
|
7
|
+
retryBucketIndexForDuration,
|
|
8
|
+
} = require('./efd-retry-policy')
|
|
9
|
+
|
|
10
|
+
const DYNAMIC_ATR_ENABLED_ENV = 'DD_CIVISIBILITY_DYNAMIC_ATR_ENABLED'
|
|
11
|
+
const DYNAMIC_ATR_BUCKETS_ENV = 'DD_CIVISIBILITY_DYNAMIC_ATR_BUCKETS'
|
|
12
|
+
|
|
13
|
+
const RETRY_BUCKET_COUNT = 5
|
|
14
|
+
const MAX_RETRIES_PER_BUCKET = 20
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns whether duration-based ATR retry budgets are enabled.
|
|
18
|
+
*
|
|
19
|
+
* @param {unknown} value A parsed test-optimization configuration value.
|
|
20
|
+
*/
|
|
21
|
+
function isDynamicAtrEnabled (value) {
|
|
22
|
+
return value === true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parses and validates custom ATR retry buckets from the parsed
|
|
27
|
+
* test-optimization configuration.
|
|
28
|
+
*
|
|
29
|
+
* Returns a frozen array of 5 positive integers in [1, 20], or `null`
|
|
30
|
+
* when the value is unset/empty or invalid (in which case the EFD retry
|
|
31
|
+
* settings from the backend are used).
|
|
32
|
+
*
|
|
33
|
+
* @param {unknown} value A parsed test-optimization configuration value.
|
|
34
|
+
* @returns {number[] | null}
|
|
35
|
+
*/
|
|
36
|
+
function getDynamicAtrBuckets (value) {
|
|
37
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const parts = value
|
|
42
|
+
const raw = parts.join(',')
|
|
43
|
+
if (parts.length !== RETRY_BUCKET_COUNT) {
|
|
44
|
+
log.warn(
|
|
45
|
+
'Invalid %s value %o; expected five comma-separated integers in [1, %d]',
|
|
46
|
+
DYNAMIC_ATR_BUCKETS_ENV, raw, MAX_RETRIES_PER_BUCKET
|
|
47
|
+
)
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const buckets = []
|
|
52
|
+
for (const part of parts) {
|
|
53
|
+
const trimmedPart = typeof part === 'string' ? part.trim() : ''
|
|
54
|
+
if (!/^\d+$/.test(trimmedPart)) {
|
|
55
|
+
log.warn(
|
|
56
|
+
'Invalid %s value %o; expected five comma-separated integers in [1, %d]',
|
|
57
|
+
DYNAMIC_ATR_BUCKETS_ENV, raw, MAX_RETRIES_PER_BUCKET
|
|
58
|
+
)
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
const value = Number(trimmedPart)
|
|
62
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_RETRIES_PER_BUCKET) {
|
|
63
|
+
log.warn(
|
|
64
|
+
'Invalid %s value %o; expected five comma-separated integers in [1, %d]',
|
|
65
|
+
DYNAMIC_ATR_BUCKETS_ENV, raw, MAX_RETRIES_PER_BUCKET
|
|
66
|
+
)
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
buckets.push(value)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return Object.freeze(buckets)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Computes the dynamic ATR retry count for a test based on its initial-attempt
|
|
77
|
+
* duration.
|
|
78
|
+
*
|
|
79
|
+
* When `customBuckets` is provided, the bucket at the duration index is used.
|
|
80
|
+
* Otherwise, the EFD retry policy's `retriesForDuration` is used.
|
|
81
|
+
*
|
|
82
|
+
* The result is clamped to a minimum of 1.
|
|
83
|
+
*
|
|
84
|
+
* @param {number} durationMs - Initial-attempt duration in milliseconds.
|
|
85
|
+
* @param {import('./efd-retry-policy').EfdRetryPolicy} efdRetryPolicy
|
|
86
|
+
* @param {number[] | null} customBuckets
|
|
87
|
+
*/
|
|
88
|
+
function getDynamicAtrRetryCount (durationMs, efdRetryPolicy, customBuckets) {
|
|
89
|
+
let retryCount
|
|
90
|
+
if (customBuckets) {
|
|
91
|
+
retryCount = customBuckets[retryBucketIndexForDuration(durationMs)]
|
|
92
|
+
} else {
|
|
93
|
+
retryCount = retriesForDuration(durationMs, efdRetryPolicy)
|
|
94
|
+
}
|
|
95
|
+
return Math.max(1, retryCount)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
DYNAMIC_ATR_BUCKETS_ENV,
|
|
100
|
+
DYNAMIC_ATR_ENABLED_ENV,
|
|
101
|
+
getDynamicAtrBuckets,
|
|
102
|
+
getDynamicAtrRetryCount,
|
|
103
|
+
isDynamicAtrEnabled,
|
|
104
|
+
}
|
|
@@ -52,7 +52,6 @@ const limits = {
|
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
54
|
* @param {object} value - Snapshot object or sub-object.
|
|
55
|
-
* @returns {boolean}
|
|
56
55
|
*/
|
|
57
56
|
function isCapturedValue (value) {
|
|
58
57
|
return typeof value.type === 'string'
|
|
@@ -62,7 +61,6 @@ function isCapturedValue (value) {
|
|
|
62
61
|
* Remove empty capture containers before sending snapshots through the Test Optimization logs path.
|
|
63
62
|
*
|
|
64
63
|
* @param {object} value - Snapshot object or sub-object.
|
|
65
|
-
* @returns {void}
|
|
66
64
|
*/
|
|
67
65
|
function removeEmptyCaptureProperties (value) {
|
|
68
66
|
const stack = [value]
|
|
@@ -23,12 +23,43 @@ const EARLY_FLAKE_DETECTION_RETRY_BUCKETS =
|
|
|
23
23
|
* @property {number} schedulingRetryCount
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Returns the zero-based dynamic ATR retry-bucket index for a test duration.
|
|
28
|
+
*
|
|
29
|
+
* Bucket boundaries (ms): 5 000, 10 000, 30 000, 300 000.
|
|
30
|
+
* Durations at a boundary remain in that bucket.
|
|
31
|
+
*
|
|
32
|
+
* @param {number} durationMs
|
|
33
|
+
*/
|
|
34
|
+
function retryBucketIndexForDuration (durationMs) {
|
|
35
|
+
for (let index = 0; index < EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS.length; index++) {
|
|
36
|
+
if (durationMs <= EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS[index].limitMs) {
|
|
37
|
+
return index
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS.length // > 5 m bucket
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns the backend retry budget using dynamic ATR's inclusive duration cutoffs.
|
|
45
|
+
*
|
|
46
|
+
* @param {number} durationMs
|
|
47
|
+
* @param {EfdRetryPolicy} retryPolicy
|
|
48
|
+
*/
|
|
49
|
+
function retriesForDuration (durationMs, retryPolicy) {
|
|
50
|
+
const index = retryBucketIndexForDuration(durationMs)
|
|
51
|
+
if (index < retryPolicy.durationRetryCounts.length) {
|
|
52
|
+
return retryPolicy.durationRetryCounts[index].retryCount
|
|
53
|
+
}
|
|
54
|
+
return 0
|
|
55
|
+
}
|
|
56
|
+
|
|
26
57
|
/**
|
|
27
58
|
* @param {number} durationMs
|
|
28
59
|
* @param {EfdRetryPolicy} retryPolicy
|
|
29
|
-
* @returns {number}
|
|
30
60
|
*/
|
|
31
61
|
function getEfdRetryCountForDuration (durationMs, retryPolicy) {
|
|
62
|
+
// EFD retains exclusive cutoffs, including no retries at exactly five minutes.
|
|
32
63
|
for (const { durationLimitMs, retryCount } of retryPolicy.durationRetryCounts) {
|
|
33
64
|
if (durationMs < durationLimitMs) {
|
|
34
65
|
return retryCount
|
|
@@ -62,7 +93,6 @@ function createEfdRetryPolicy (retriesByDuration = {}) {
|
|
|
62
93
|
|
|
63
94
|
/**
|
|
64
95
|
* @param {EfdRetryPolicy | undefined} retryPolicy
|
|
65
|
-
* @returns {boolean}
|
|
66
96
|
*/
|
|
67
97
|
function hasEfdRetries (retryPolicy) {
|
|
68
98
|
return (retryPolicy?.schedulingRetryCount ?? 0) > 0
|
|
@@ -71,7 +101,6 @@ function hasEfdRetries (retryPolicy) {
|
|
|
71
101
|
/**
|
|
72
102
|
* @param {number} retryIndex
|
|
73
103
|
* @param {number | undefined} retryCount
|
|
74
|
-
* @returns {boolean}
|
|
75
104
|
*/
|
|
76
105
|
function shouldSkipEfdRetry (retryIndex, retryCount) {
|
|
77
106
|
return retryCount !== undefined && retryIndex > retryCount
|
|
@@ -85,5 +114,7 @@ module.exports = {
|
|
|
85
114
|
createEfdRetryPolicy,
|
|
86
115
|
getEfdRetryCountForDuration,
|
|
87
116
|
hasEfdRetries,
|
|
117
|
+
retriesForDuration,
|
|
118
|
+
retryBucketIndexForDuration,
|
|
88
119
|
shouldSkipEfdRetry,
|
|
89
120
|
}
|
|
@@ -105,7 +105,6 @@ class CiValidationExporter extends CiVisibilityExporter {
|
|
|
105
105
|
/**
|
|
106
106
|
* Resolves the inherited git-upload gate without performing an upload.
|
|
107
107
|
*
|
|
108
|
-
* @returns {void}
|
|
109
108
|
*/
|
|
110
109
|
sendGitMetadata () {
|
|
111
110
|
this._resolveGit()
|
|
@@ -114,14 +113,12 @@ class CiValidationExporter extends CiVisibilityExporter {
|
|
|
114
113
|
/**
|
|
115
114
|
* Drops debugger logs in offline validation mode.
|
|
116
115
|
*
|
|
117
|
-
* @returns {void}
|
|
118
116
|
*/
|
|
119
117
|
exportDiLogs () {}
|
|
120
118
|
|
|
121
119
|
/**
|
|
122
120
|
* Reports that code coverage is outside the offline validator's scope.
|
|
123
121
|
*
|
|
124
|
-
* @returns {boolean} always false
|
|
125
122
|
*/
|
|
126
123
|
canReportCodeCoverage () {
|
|
127
124
|
return false
|
|
@@ -140,7 +137,6 @@ class CiValidationExporter extends CiVisibilityExporter {
|
|
|
140
137
|
/**
|
|
141
138
|
* Reports that screenshot upload is unavailable.
|
|
142
139
|
*
|
|
143
|
-
* @returns {boolean} always false
|
|
144
140
|
*/
|
|
145
141
|
canUploadTestScreenshots () {
|
|
146
142
|
return false
|
|
@@ -179,7 +179,6 @@ class CiValidationSink {
|
|
|
179
179
|
/**
|
|
180
180
|
* Atomically publishes this process's bounded completion evidence.
|
|
181
181
|
*
|
|
182
|
-
* @returns {boolean} whether the record was published
|
|
183
182
|
*/
|
|
184
183
|
#writeCompletionRecord () {
|
|
185
184
|
const directoryPath = path.join(this.#outputRoot, 'completions')
|
|
@@ -215,7 +214,6 @@ class CiValidationSink {
|
|
|
215
214
|
* Writes one completed JSON payload to a unique file.
|
|
216
215
|
*
|
|
217
216
|
* @param {Buffer} payload JSON payload
|
|
218
|
-
* @returns {boolean} whether the payload was written
|
|
219
217
|
*/
|
|
220
218
|
#writePayloadFile (payload) {
|
|
221
219
|
if (this.#fileCount >= MAX_OUTPUT_FILES) {
|