dd-trace 6.16.0 → 6.18.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 +208 -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 +77 -12
- package/packages/datadog-instrumentations/src/cypress-config.js +27 -38
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +6 -0
- package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -6
- 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 +24 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +111 -26
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +41 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +55 -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/instrumentations/webdriverio.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +28 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +20 -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 +165 -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 +25 -26
- 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 +6 -20
- package/packages/datadog-instrumentations/src/playwright.js +280 -56
- package/packages/datadog-instrumentations/src/{azure-cosmos.js → postgres.js} +1 -1
- 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/undici.js +7 -3
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
- package/packages/datadog-instrumentations/src/vitest-main.js +121 -30
- 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 +44 -47
- package/packages/datadog-instrumentations/src/ws.js +41 -2
- 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 +9 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +211 -85
- package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
- package/packages/datadog-plugin-cypress/src/index.js +3 -1
- 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 +12 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
- package/packages/datadog-plugin-mocha/src/index.js +38 -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 +81 -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 +9 -0
- package/packages/datadog-plugin-ws/src/producer.js +1 -1
- package/packages/datadog-plugin-ws/src/util.js +0 -4
- package/packages/datadog-shimmer/src/shimmer.js +14 -10
- package/packages/datadog-turbopack/index.js +4 -7
- package/packages/datadog-turbopack/src/loader.js +6 -18
- package/packages/datadog-webpack/src/loader.js +0 -1
- package/packages/dd-trace/src/agent/info.js +5 -4
- 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 +88 -82
- package/packages/dd-trace/src/config/helper.js +0 -1
- package/packages/dd-trace/src/config/index.js +31 -30
- 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 +150 -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 +4 -1
- 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 +41 -15
- 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/redaction.js +5 -3
- package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +21 -7
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
- package/packages/dd-trace/src/debugger/index.js +51 -3
- 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/constants.js +2 -0
- package/packages/dd-trace/src/evp_proxy/direct.js +17 -13
- package/packages/dd-trace/src/evp_proxy/discovery.js +14 -11
- package/packages/dd-trace/src/evp_proxy/path.js +21 -9
- 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 +33 -4
- 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 +647 -0
- package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +158 -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 +39 -11
- 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/configuration_source.js +4 -1
- 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/flagging_provider.js +3 -3
- package/packages/dd-trace/src/openfeature/index.js +6 -6
- 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 +90 -23
- package/packages/dd-trace/src/openfeature/writers/exposures.js +4 -5
- package/packages/dd-trace/src/openfeature/writers/util.js +104 -37
- 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/opentracing/tracer.js +3 -3
- 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/plugin_manager.js +27 -8
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -2
- 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 +26 -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 +23 -47
- 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/send-data.js +2 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
- package/packages/dd-trace/src/tracer.js +5 -4
- package/packages/dd-trace/src/util.js +13 -1
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/packages/datadog-instrumentations/src/bullmq.js +0 -11
- package/packages/datadog-instrumentations/src/langchain.js +0 -7
- package/packages/datadog-instrumentations/src/langgraph.js +0 -7
- package/packages/datadog-instrumentations/src/mercurius.js +0 -11
|
@@ -114,11 +114,10 @@ function digitRunEnd (value, from, length) {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
|
-
*
|
|
117
|
+
* Returns the end of a plain integer or decimal literal, or `-1` to delegate exponents and radix literals to `NUMERIC`.
|
|
118
118
|
* @param {string} value
|
|
119
119
|
* @param {number} intEnd Index after the integer digit run measured by the caller.
|
|
120
120
|
* @param {number} length
|
|
121
|
-
* @returns {number} Index after the literal, or `-1` to defer to the `NUMERIC` regex.
|
|
122
121
|
*/
|
|
123
122
|
function scanPlainNumber (value, intEnd, length) {
|
|
124
123
|
// A digit run touching `x`/`b` is a radix prefix (`0x`, `0b`) — let the regex own it.
|
|
@@ -177,7 +176,6 @@ const FALL_THROUGH = -2 // not a literal start -> advance one character and reco
|
|
|
177
176
|
* @param {string} value
|
|
178
177
|
* @param {number} from
|
|
179
178
|
* @param {number} length
|
|
180
|
-
* @returns {number} Index of the first line terminator at or after `from`, else `length`.
|
|
181
179
|
*/
|
|
182
180
|
function lineEnd (value, from, length) {
|
|
183
181
|
for (let i = from; i < length; i++) {
|
|
@@ -196,7 +194,6 @@ function lineEnd (value, from, length) {
|
|
|
196
194
|
* @param {number} quote Char code of the opening delimiter, `'` or `"`.
|
|
197
195
|
* @param {boolean} conservativeBackslash Whether an odd backslash before a closing quote makes the
|
|
198
196
|
* remainder ambiguous and therefore unterminated.
|
|
199
|
-
* @returns {number} Index after the closing quote, or `UNTERMINATED`.
|
|
200
197
|
*/
|
|
201
198
|
function scanQuotedDoubled (value, start, length, quote, conservativeBackslash) {
|
|
202
199
|
let backslashCount = 0
|
|
@@ -229,7 +226,6 @@ function scanQuotedDoubled (value, start, length, quote, conservativeBackslash)
|
|
|
229
226
|
* @param {number} length
|
|
230
227
|
* @param {number} quote Char code of the opening delimiter, `'` or `"`.
|
|
231
228
|
* @param {boolean} doubled Whether two adjacent quotes escape each other.
|
|
232
|
-
* @returns {number} Index after the closing quote, or `UNTERMINATED`.
|
|
233
229
|
*/
|
|
234
230
|
function scanQuotedBackslash (value, start, length, quote, doubled) {
|
|
235
231
|
for (let i = start + 1; i < length; i++) {
|
|
@@ -269,12 +265,13 @@ function isPostgresEscapeString (value, quoteIndex) {
|
|
|
269
265
|
/**
|
|
270
266
|
* Oracle `q'X…X'`: `X` is one of `< ( { [` (closed by its mirror) or any other char (closed by
|
|
271
267
|
* itself). The body may span line terminators.
|
|
268
|
+
* The result is the index after the closing `X'`.
|
|
269
|
+
* It is `FALL_THROUGH` when `q'` ends the value or is followed by a line terminator.
|
|
270
|
+
* Oracle forbids whitespace as the delimiter, so this case is a plain string instead of a quote opener.
|
|
271
|
+
* It is `UNTERMINATED` when no closing delimiter exists.
|
|
272
272
|
* @param {string} value
|
|
273
273
|
* @param {number} start
|
|
274
274
|
* @param {number} length
|
|
275
|
-
* @returns {number} Index after the closing `X'`; `FALL_THROUGH` when `q'` is at the end of the value
|
|
276
|
-
* or followed by a line terminator — Oracle forbids whitespace as the delimiter, so that `'` is a
|
|
277
|
-
* plain string, not a quote opener; or `UNTERMINATED`.
|
|
278
275
|
*/
|
|
279
276
|
function scanOracleQuote (value, start, length) {
|
|
280
277
|
const delimiter = value.charCodeAt(start + 2)
|
|
@@ -294,11 +291,12 @@ function scanOracleQuote (value, start, length) {
|
|
|
294
291
|
* Postgres `$tag$ … $tag$`, where `tag` is empty or an identifier. The body may span line
|
|
295
292
|
* terminators — PL/pgSQL function bodies routinely do, and treating a newline as the end of the
|
|
296
293
|
* literal would leave the rest of a multi-line body unredacted.
|
|
294
|
+
* The result is the index after the closing tag.
|
|
295
|
+
* It is `FALL_THROUGH` when no second `$` exists.
|
|
296
|
+
* It is `UNTERMINATED` when the opening tag is malformed or has no close.
|
|
297
297
|
* @param {string} value
|
|
298
298
|
* @param {number} start
|
|
299
299
|
* @param {number} length
|
|
300
|
-
* @returns {number} Index after the closing tag; `FALL_THROUGH` when no second `$` exists; or
|
|
301
|
-
* `UNTERMINATED` when the opening tag is malformed or has no close.
|
|
302
300
|
*/
|
|
303
301
|
function scanDollarQuote (value, start, length) {
|
|
304
302
|
const tagEnd = value.indexOf('$', start + 1)
|
|
@@ -24,8 +24,8 @@ const MAX_EVIDENCE_LENGTH = 32_768
|
|
|
24
24
|
|
|
25
25
|
class SensitiveHandler {
|
|
26
26
|
constructor () {
|
|
27
|
-
this._namePattern = new RegExp(/** @type {string} */ (defaults['iast.
|
|
28
|
-
this._valuePattern = new RegExp(/** @type {string} */ (defaults['iast.
|
|
27
|
+
this._namePattern = new RegExp(/** @type {string} */ (defaults['iast.DD_IAST_REDACTION_NAME_PATTERN']), 'gmi')
|
|
28
|
+
this._valuePattern = new RegExp(/** @type {string} */ (defaults['iast.DD_IAST_REDACTION_VALUE_PATTERN']), 'gmi')
|
|
29
29
|
|
|
30
30
|
this._sensitiveAnalyzers = new Map()
|
|
31
31
|
this._sensitiveAnalyzers.set(vulnerabilities.CODE_INJECTION, taintedRangeBasedSensitiveAnalyzer)
|
|
@@ -13,7 +13,10 @@ const REGEX_FOR_STRINGIFY_SENSITIVE_NOT_STRING = new RegExp(String.raw`"${STRING
|
|
|
13
13
|
const REGEX_FOR_STRINGIFY_SENSITIVE = new RegExp(String.raw`${STRINGIFY_SENSITIVE_KEY}_\d+_(\d+)_`)
|
|
14
14
|
const REGEX_FOR_STRINGIFY_RANGE = new RegExp(String.raw`(${STRINGIFY_RANGE_KEY}_\d+_)`)
|
|
15
15
|
|
|
16
|
-
const sensitiveValueRegex = new RegExp(
|
|
16
|
+
const sensitiveValueRegex = new RegExp(
|
|
17
|
+
/** @type {string} */ (defaults['iast.DD_IAST_REDACTION_VALUE_PATTERN']),
|
|
18
|
+
'gmi'
|
|
19
|
+
)
|
|
17
20
|
|
|
18
21
|
function iterateObject (target, fn, levelKeys = [], depth = 10, visited = new Set()) {
|
|
19
22
|
for (const key of Object.keys(target)) {
|
|
@@ -138,15 +138,15 @@ function replaceCallSiteFromSourceMap (callsite) {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
function start (config, _tracer) {
|
|
141
|
-
deduplicationEnabled = config.iast.
|
|
142
|
-
stackTraceEnabled = config.iast.
|
|
143
|
-
stackTraceMaxDepth = config.appsec.
|
|
144
|
-
maxStackTraces = config.appsec.
|
|
141
|
+
deduplicationEnabled = config.iast.DD_IAST_DEDUPLICATION_ENABLED
|
|
142
|
+
stackTraceEnabled = config.iast.DD_IAST_STACK_TRACE_ENABLED
|
|
143
|
+
stackTraceMaxDepth = config.appsec.DD_APPSEC_MAX_STACK_TRACE_DEPTH
|
|
144
|
+
maxStackTraces = config.appsec.DD_APPSEC_MAX_STACK_TRACES
|
|
145
145
|
|
|
146
146
|
vulnerabilitiesFormatter.setRedactVulnerabilities(
|
|
147
|
-
config.iast.
|
|
148
|
-
config.iast.
|
|
149
|
-
config.iast.
|
|
147
|
+
config.iast.DD_IAST_REDACTION_ENABLED,
|
|
148
|
+
config.iast.DD_IAST_REDACTION_NAME_PATTERN,
|
|
149
|
+
config.iast.DD_IAST_REDACTION_VALUE_PATTERN
|
|
150
150
|
)
|
|
151
151
|
if (deduplicationEnabled) {
|
|
152
152
|
startClearCacheTimer()
|
|
@@ -87,7 +87,7 @@ function enable (_config) {
|
|
|
87
87
|
appsecTelemetry.enable(_config)
|
|
88
88
|
graphql.enable()
|
|
89
89
|
|
|
90
|
-
if (_config.appsec.
|
|
90
|
+
if (_config.appsec.DD_APPSEC_RASP_ENABLED) {
|
|
91
91
|
rasp.enable(_config)
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -101,7 +101,7 @@ function enable (_config) {
|
|
|
101
101
|
|
|
102
102
|
apiSecurity.configure(_config)
|
|
103
103
|
|
|
104
|
-
UserTracking.setCollectionMode(_config.appsec.
|
|
104
|
+
UserTracking.setCollectionMode(_config.appsec.DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE, false)
|
|
105
105
|
|
|
106
106
|
httpRequest.setConfig(_config)
|
|
107
107
|
|
|
@@ -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
|
}
|