dd-trace 6.7.0 → 6.9.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 +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +14 -8
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +47 -37
- package/ci/test-optimization-validation/generated-test-contract.js +9 -7
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +41 -21
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +377 -84
- package/index.d.ts +175 -14
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +12 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +17 -2
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
- package/packages/datadog-instrumentations/src/cucumber.js +131 -51
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +986 -246
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
- package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/pg.js +180 -6
- package/packages/datadog-instrumentations/src/playwright.js +176 -81
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
- package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
- package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
- package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +3 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -21
- package/packages/datadog-plugin-jest/src/util.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +342 -6
- package/packages/datadog-plugin-next/src/index.js +57 -9
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-pg/src/index.js +65 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +179 -18
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +31 -5
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +13 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +152 -78
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -6
- package/packages/dd-trace/src/plugins/util/git.js +7 -5
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +356 -86
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +24 -2
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +10 -20
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -7,10 +7,10 @@ const { environmentNamesEqual, setEnvironmentValue } = require('./environment')
|
|
|
7
7
|
|
|
8
8
|
const RUNNER_OPTIONS = {
|
|
9
9
|
cucumber: {
|
|
10
|
-
flags: new Set(),
|
|
10
|
+
flags: new Set(['--backtrace', '--fail-fast', '--no-strict', '--strict']),
|
|
11
11
|
values: new Set([
|
|
12
12
|
'-p', '--config', '--import', '--language', '--loader', '--profile', '--require', '--require-module',
|
|
13
|
-
'--world-parameters',
|
|
13
|
+
'--parallel', '--world-parameters',
|
|
14
14
|
]),
|
|
15
15
|
},
|
|
16
16
|
cypress: {
|
|
@@ -18,7 +18,7 @@ const RUNNER_OPTIONS = {
|
|
|
18
18
|
values: new Set(['--browser', '--config-file']),
|
|
19
19
|
},
|
|
20
20
|
jest: {
|
|
21
|
-
flags: new Set(['--detectLeaks']),
|
|
21
|
+
flags: new Set(['--color', '--colors', '--detectLeaks']),
|
|
22
22
|
values: new Set(['-c', '--config', '--env', '--runner', '--testEnvironment']),
|
|
23
23
|
},
|
|
24
24
|
mocha: {
|
|
@@ -128,17 +128,6 @@ function getRunnerContract (framework, command, projectRoot, repositoryRoot, pla
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
const omittedOptions = getOmittedRunnerOptions(framework, invocation)
|
|
131
|
-
if (framework === 'cucumber') {
|
|
132
|
-
const language = getOptionValue(invocation, '--language')
|
|
133
|
-
if (language && language !== 'en') {
|
|
134
|
-
return {
|
|
135
|
-
environment: {},
|
|
136
|
-
error: `--language ${language} is not supported by the validator-generated English scenarios`,
|
|
137
|
-
inputFiles: [],
|
|
138
|
-
runnerArgs: [],
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
131
|
|
|
143
132
|
const environment = getRunnerEnvironment(invocation, platform)
|
|
144
133
|
const environmentError = getRunnerEnvironmentError(environment, platform)
|
|
@@ -167,6 +156,23 @@ function getRunnerContract (framework, command, projectRoot, repositoryRoot, pla
|
|
|
167
156
|
}
|
|
168
157
|
}
|
|
169
158
|
|
|
159
|
+
function getRunnerConfigurationContract (framework, runnerArgs, environment, projectRoot, repositoryRoot) {
|
|
160
|
+
const runnerArgsError = getRunnerArgsError(framework, runnerArgs)
|
|
161
|
+
if (runnerArgsError) {
|
|
162
|
+
return {
|
|
163
|
+
environment: {},
|
|
164
|
+
error: `runner arguments ${runnerArgsError}`,
|
|
165
|
+
inputFiles: [],
|
|
166
|
+
runnerArgs: [],
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const inputs = getRunnerInputs(runnerArgs, environment, projectRoot, repositoryRoot)
|
|
170
|
+
if (inputs.error) {
|
|
171
|
+
return { environment: {}, error: inputs.error, inputFiles: [], runnerArgs: [] }
|
|
172
|
+
}
|
|
173
|
+
return { environment, inputFiles: inputs.files, runnerArgs }
|
|
174
|
+
}
|
|
175
|
+
|
|
170
176
|
/**
|
|
171
177
|
* Rejects shell-expanded allowlisted environment assignments before command tokenization.
|
|
172
178
|
*
|
|
@@ -239,7 +245,7 @@ function getRunnerSearchRoots (framework, command, projectRoot, repositoryRoot)
|
|
|
239
245
|
*/
|
|
240
246
|
function addRunnerSearchRoot (roots, value, projectRoot, repositoryRoot, directory) {
|
|
241
247
|
if (typeof value !== 'string' || !value) return
|
|
242
|
-
const literal = value.split(/[*?{[]/, 1)[0].replace(/[\\/]+$/, '')
|
|
248
|
+
const literal = value.split(/[*?{[]/, 1)[0].replace(/(?<![\\/])[\\/]+$/, '')
|
|
243
249
|
if (!literal) return
|
|
244
250
|
const candidate = path.resolve(projectRoot, literal)
|
|
245
251
|
const searchRoot = directory || !path.extname(candidate) ? candidate : path.dirname(candidate)
|
|
@@ -305,17 +311,24 @@ function getUnknownRunnerOption (framework, invocation) {
|
|
|
305
311
|
|
|
306
312
|
function getOmittedRunnerOptions (framework, invocation) {
|
|
307
313
|
const omitted = OMITTED_RUNNER_OPTIONS[framework] || new Set()
|
|
314
|
+
const ignored = IGNORED_RUNNER_OPTIONS[framework] || { flags: new Set(), values: new Set() }
|
|
308
315
|
return [...new Set(invocation.tokens
|
|
309
316
|
.slice(invocation.runnerIndex + 1)
|
|
310
|
-
.filter(token =>
|
|
317
|
+
.filter(token => {
|
|
318
|
+
if (!token.startsWith('-')) return false
|
|
319
|
+
const option = token.split('=', 1)[0]
|
|
320
|
+
return omitted.has(option) || ignored.flags.has(option) || ignored.values.has(option)
|
|
321
|
+
})
|
|
322
|
+
.map(token => token.split('=', 1)[0]))]
|
|
311
323
|
}
|
|
312
324
|
|
|
313
|
-
function
|
|
314
|
-
const
|
|
315
|
-
for (let index = 0; index <
|
|
316
|
-
if (
|
|
317
|
-
|
|
325
|
+
function getArgumentOptionValues (args, expected) {
|
|
326
|
+
const values = []
|
|
327
|
+
for (let index = 0; index < args.length; index++) {
|
|
328
|
+
if (args[index].split('=', 1)[0] !== expected) continue
|
|
329
|
+
values.push(args[index].includes('=') ? args[index].slice(args[index].indexOf('=') + 1) : args[index + 1])
|
|
318
330
|
}
|
|
331
|
+
return values
|
|
319
332
|
}
|
|
320
333
|
|
|
321
334
|
/**
|
|
@@ -361,7 +374,8 @@ function getRunnerArgsError (framework, args) {
|
|
|
361
374
|
}
|
|
362
375
|
const option = token.split('=', 1)[0]
|
|
363
376
|
if (options.flags.has(option)) {
|
|
364
|
-
if (token !== option &&
|
|
377
|
+
if (token !== option &&
|
|
378
|
+
!/^--(?:color|colors|detectLeaks)=(?:true|false)$/.test(token)) {
|
|
365
379
|
return `contain an invalid value for ${option}`
|
|
366
380
|
}
|
|
367
381
|
continue
|
|
@@ -376,6 +390,13 @@ function getRunnerArgsError (framework, args) {
|
|
|
376
390
|
return `contain a missing or unsafe value for ${option}`
|
|
377
391
|
}
|
|
378
392
|
}
|
|
393
|
+
|
|
394
|
+
if (framework === 'cucumber') {
|
|
395
|
+
const language = getArgumentOptionValues(args, '--language').find(value => value !== 'en')
|
|
396
|
+
if (language) {
|
|
397
|
+
return `--language ${language} is not supported by the validator-generated English scenarios`
|
|
398
|
+
}
|
|
399
|
+
}
|
|
379
400
|
}
|
|
380
401
|
|
|
381
402
|
/**
|
|
@@ -411,10 +432,12 @@ function getRunnerInputError (args, environment, projectRoot, repositoryRoot, co
|
|
|
411
432
|
if (inputs.error) return inputs.error
|
|
412
433
|
|
|
413
434
|
const approved = new Set()
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
435
|
+
if (configFiles) {
|
|
436
|
+
for (const filename of configFiles) {
|
|
437
|
+
try {
|
|
438
|
+
approved.add(fs.realpathSync(filename))
|
|
439
|
+
} catch {}
|
|
440
|
+
}
|
|
418
441
|
}
|
|
419
442
|
const unbound = inputs.files.find(filename => !approved.has(filename))
|
|
420
443
|
if (unbound) return `references an input that is not approval-bound: ${unbound}`
|
|
@@ -439,26 +462,34 @@ function getFrameworkInvocation (command, framework) {
|
|
|
439
462
|
})
|
|
440
463
|
if (runnerIndex === -1) return
|
|
441
464
|
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
for (const token of prefix) {
|
|
452
|
-
if (RUNNER_LAUNCHERS.has(path.basename(token).toLowerCase())) continue
|
|
465
|
+
const prefixError = getRunnerPrefixError(tokens.slice(0, runnerIndex))
|
|
466
|
+
if (prefixError) return { error: prefixError, runnerIndex, tokens }
|
|
467
|
+
return { runnerIndex, tokens }
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function getRunnerPrefixError (prefix) {
|
|
471
|
+
let coverageLauncher = false
|
|
472
|
+
for (let index = 0; index < prefix.length; index++) {
|
|
473
|
+
const token = prefix[index]
|
|
453
474
|
if (/^[A-Za-z_][A-Za-z0-9_]*=[^;&|`]*$/.test(token)) continue
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
475
|
+
|
|
476
|
+
const basename = path.basename(token).toLowerCase()
|
|
477
|
+
if (RUNNER_LAUNCHERS.has(basename)) {
|
|
478
|
+
coverageLauncher = basename === 'c8' || basename === 'nyc'
|
|
479
|
+
continue
|
|
459
480
|
}
|
|
481
|
+
if (coverageLauncher && /^(?:-r|--reporter)=\S+$/.test(token)) continue
|
|
482
|
+
if (coverageLauncher && /^(?:-r|--reporter)$/.test(token) &&
|
|
483
|
+
prefix[index + 1] && !prefix[index + 1].startsWith('-')) {
|
|
484
|
+
index++
|
|
485
|
+
continue
|
|
486
|
+
}
|
|
487
|
+
if (!prefix.some(candidate => RUNNER_LAUNCHERS.has(path.basename(candidate).toLowerCase()))) {
|
|
488
|
+
return `runner launch wrapper ${path.basename(token)} is not allowlisted`
|
|
489
|
+
}
|
|
490
|
+
return 'runner launch wrapper contains options or positional arguments whose semantics the validator does not ' +
|
|
491
|
+
'preserve'
|
|
460
492
|
}
|
|
461
|
-
return { runnerIndex, tokens }
|
|
462
493
|
}
|
|
463
494
|
|
|
464
495
|
/**
|
|
@@ -612,6 +643,10 @@ function resolveInputFile (input, projectRoot) {
|
|
|
612
643
|
if (!input.module || path.isAbsolute(input.value) || input.value.startsWith('.')) {
|
|
613
644
|
return path.resolve(projectRoot, input.value)
|
|
614
645
|
}
|
|
646
|
+
const projectRelative = path.resolve(projectRoot, input.value)
|
|
647
|
+
try {
|
|
648
|
+
return require.resolve(projectRelative)
|
|
649
|
+
} catch {}
|
|
615
650
|
try {
|
|
616
651
|
return require.resolve(input.value, { paths: [projectRoot] })
|
|
617
652
|
} catch {}
|
|
@@ -657,6 +692,7 @@ function isPathInside (root, filename) {
|
|
|
657
692
|
module.exports = {
|
|
658
693
|
getProjectNodeRunner,
|
|
659
694
|
getRunnerArgsError,
|
|
695
|
+
getRunnerConfigurationContract,
|
|
660
696
|
getRunnerContract,
|
|
661
697
|
getRunnerEnvironmentError,
|
|
662
698
|
getRunnerInputError,
|
|
@@ -129,10 +129,10 @@ function openAndWrite (root, filename, data, label, creationFlag) {
|
|
|
129
129
|
*
|
|
130
130
|
* @param {string} directory directory path
|
|
131
131
|
* @param {string} label customer-facing path label
|
|
132
|
-
* @returns {{dev:
|
|
132
|
+
* @returns {{dev: bigint, ino: bigint}} directory identity
|
|
133
133
|
*/
|
|
134
134
|
function getDirectoryIdentity (directory, label) {
|
|
135
|
-
const stat = fs.lstatSync(directory)
|
|
135
|
+
const stat = fs.lstatSync(directory, { bigint: true })
|
|
136
136
|
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
137
137
|
throw new Error(`Refusing ${label} because its parent is not a regular directory: ${directory}`)
|
|
138
138
|
}
|
|
@@ -143,7 +143,7 @@ function getDirectoryIdentity (directory, label) {
|
|
|
143
143
|
* Refuses replacement of a parent directory between safe creation and publication.
|
|
144
144
|
*
|
|
145
145
|
* @param {string} directory directory path
|
|
146
|
-
* @param {{dev:
|
|
146
|
+
* @param {{dev: bigint, ino: bigint}} expected expected identity
|
|
147
147
|
* @param {string} label customer-facing path label
|
|
148
148
|
*/
|
|
149
149
|
function assertDirectoryIdentity (directory, expected, label) {
|
|
@@ -158,7 +158,7 @@ function assertDirectoryIdentity (directory, expected, label) {
|
|
|
158
158
|
*
|
|
159
159
|
* @param {string} filename temporary filename
|
|
160
160
|
* @param {string} parent expected parent directory
|
|
161
|
-
* @param {{dev:
|
|
161
|
+
* @param {{dev: bigint, ino: bigint}} parentIdentity expected parent identity
|
|
162
162
|
*/
|
|
163
163
|
function removeTemporaryFile (filename, parent, parentIdentity) {
|
|
164
164
|
try {
|
|
@@ -58,7 +58,7 @@ async function runBasicReporting ({ framework, out, options }) {
|
|
|
58
58
|
selector,
|
|
59
59
|
settingsLoadedFromCache: run.offline.inputs.settings?.status === 'loaded',
|
|
60
60
|
}
|
|
61
|
-
evidence.foundationalReportingEstablished
|
|
61
|
+
evidence.foundationalReportingEstablished &&= selector.verified
|
|
62
62
|
|
|
63
63
|
if (run.result.timedOut) {
|
|
64
64
|
return inconclusive(
|
|
@@ -111,7 +111,7 @@ async function runBasicReporting ({ framework, out, options }) {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
if (!run.offline.initialized || !evidence.settingsLoadedFromCache) {
|
|
114
|
-
return
|
|
114
|
+
return failBasicWithDebugRerun({
|
|
115
115
|
command,
|
|
116
116
|
diagnosis: run.offline.initialized
|
|
117
117
|
? 'The clean test passed, but Test Optimization did not load the validator-owned offline settings.'
|
|
@@ -131,7 +131,7 @@ async function runBasicReporting ({ framework, out, options }) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
if (run.result.exitCode !== 0) {
|
|
134
|
-
evidence.commandFailure = classifyFailure(framework, run.result)
|
|
134
|
+
evidence.commandFailure = classifyFailure(framework, run.result, run.events)
|
|
135
135
|
const confirmation = await runCleanConfirmation({ command, framework, options, out })
|
|
136
136
|
evidence.cleanConfirmation = confirmation.evidence
|
|
137
137
|
if (!confirmation.evidence.matchesPreflight) {
|
|
@@ -144,7 +144,7 @@ async function runBasicReporting ({ framework, out, options }) {
|
|
|
144
144
|
confirmation.artifacts
|
|
145
145
|
)
|
|
146
146
|
}
|
|
147
|
-
const result = await
|
|
147
|
+
const result = await failBasicWithDebugRerun({
|
|
148
148
|
command,
|
|
149
149
|
diagnosis: complete
|
|
150
150
|
? `The test passed twice without Datadog but exited ${run.result.exitCode} when initialized, after ` +
|
|
@@ -169,7 +169,7 @@ async function runBasicReporting ({ framework, out, options }) {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
const missing = getMissingLevels(evidence)
|
|
172
|
-
return
|
|
172
|
+
return failBasicWithDebugRerun({
|
|
173
173
|
command,
|
|
174
174
|
diagnosis: 'The direct test passed cleanly and while initialized, but no complete Test Optimization event ' +
|
|
175
175
|
`hierarchy was captured. Missing levels: ${missing.join(', ')}. This is a possible dd-trace adapter bug.`,
|
|
@@ -194,6 +194,50 @@ async function runBasicReporting ({ framework, out, options }) {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
async function failBasicWithDebugRerun (input) {
|
|
198
|
+
const result = await failWithDebugRerun(input)
|
|
199
|
+
const debug = result.evidence?.debugRerun
|
|
200
|
+
if (!isSuccessfulDebugRerun(debug, result.evidence?.selector)) return result
|
|
201
|
+
|
|
202
|
+
const initialDiagnosis = result.diagnosis
|
|
203
|
+
delete result.evidence.possibleLibraryBug
|
|
204
|
+
result.status = 'error'
|
|
205
|
+
result.diagnosis = 'The first initialized run failed, but the unchanged DD_TRACE_DEBUG=1 rerun exited cleanly ' +
|
|
206
|
+
'and emitted the complete event hierarchy. Basic Reporting is intermittent, so no library-bug conclusion ' +
|
|
207
|
+
'was reached.'
|
|
208
|
+
result.evidence.initialInstrumentedDiagnosis = initialDiagnosis
|
|
209
|
+
result.evidence.intermittentInstrumentedResult = true
|
|
210
|
+
result.evidence.recommendation = 'Repeat the approved initialized command without changing its test selection. ' +
|
|
211
|
+
'If the failure recurs, send both initialized runs and the clean confirmations to engineering.'
|
|
212
|
+
result.evidence.validationIncomplete = true
|
|
213
|
+
return result
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isSuccessfulDebugRerun (debug, selector) {
|
|
217
|
+
return isDebugSelectorVerified(debug, selector) &&
|
|
218
|
+
debug?.ran === true &&
|
|
219
|
+
debug.commandExitCode === 0 &&
|
|
220
|
+
debug.commandTimedOut === false &&
|
|
221
|
+
debug.offlineExporterInitialized === true &&
|
|
222
|
+
debug.settingsLoadedFromCache === true &&
|
|
223
|
+
debug.testSessionEvents > 0 &&
|
|
224
|
+
debug.testModuleEvents > 0 &&
|
|
225
|
+
debug.testSuiteEvents > 0 &&
|
|
226
|
+
debug.testEvents > 0
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// A wrapper rerun is comparable only when events identify the approved representative and no other file.
|
|
230
|
+
function isDebugSelectorVerified (debug, selector) {
|
|
231
|
+
if (selector?.verified !== true) return false
|
|
232
|
+
if (selector.mode === 'bounded_direct_runner') return true
|
|
233
|
+
if (selector.mode !== 'instrumented_event_identity' ||
|
|
234
|
+
typeof selector.expectedTestFile !== 'string' ||
|
|
235
|
+
debug?.testEventsWithoutSourceFile !== 0 ||
|
|
236
|
+
debug?.testSourceFileCount !== 1 ||
|
|
237
|
+
debug?.testSourceFiles?.length !== 1) return false
|
|
238
|
+
return sourceFilesMatch(debug.testSourceFiles[0], selector.expectedTestFile)
|
|
239
|
+
}
|
|
240
|
+
|
|
197
241
|
/**
|
|
198
242
|
* Repeats the direct clean command after an initialized-only failure.
|
|
199
243
|
*
|
|
@@ -234,10 +278,17 @@ async function runCleanConfirmation ({ command, framework, options, out }) {
|
|
|
234
278
|
*/
|
|
235
279
|
function summarizePreflight (preflight = {}) {
|
|
236
280
|
return {
|
|
281
|
+
attempts: (preflight.attempts || []).map(attempt => ({
|
|
282
|
+
exitCode: attempt.exitCode,
|
|
283
|
+
observedTestCount: attempt.observedTestCount,
|
|
284
|
+
testFile: attempt.testFile,
|
|
285
|
+
timedOut: attempt.timedOut === true,
|
|
286
|
+
})),
|
|
237
287
|
durationMs: preflight.durationMs,
|
|
238
288
|
exitCode: preflight.exitCode,
|
|
239
289
|
observedTestCount: preflight.observedTestCount,
|
|
240
290
|
ran: preflight.ran === true,
|
|
291
|
+
selectedTestFile: preflight.selectedTestFile,
|
|
241
292
|
selectorVerification: preflight.selectorVerification,
|
|
242
293
|
timedOut: preflight.timedOut === true,
|
|
243
294
|
}
|
|
@@ -312,12 +363,15 @@ function normalizeSourceFile (filename) {
|
|
|
312
363
|
*
|
|
313
364
|
* @param {object} framework framework entry
|
|
314
365
|
* @param {object} result command result
|
|
366
|
+
* @param {object[]} [events] normalized captured events
|
|
315
367
|
* @returns {object|undefined} blocker
|
|
316
368
|
*/
|
|
317
|
-
function classifyFailure (framework, result) {
|
|
369
|
+
function classifyFailure (framework, result, events = []) {
|
|
318
370
|
return getCommandBlocker(result, {
|
|
319
371
|
browserRequired: framework.browserRequired,
|
|
320
372
|
framework: framework.framework,
|
|
373
|
+
packageJson: framework.project?.packageJson,
|
|
374
|
+
testsRan: eventsOfType(events, 'test').length > 0,
|
|
321
375
|
})
|
|
322
376
|
}
|
|
323
377
|
|