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
|
@@ -29,9 +29,10 @@ const RUNNER_PATTERNS = {
|
|
|
29
29
|
* @param {object} input audit inputs
|
|
30
30
|
* @param {object} input.manifest validation manifest
|
|
31
31
|
* @param {object} input.framework framework entry
|
|
32
|
+
* @param {Map<string, Buffer|undefined>} [input.projectFileSources] approval-bound project sources
|
|
32
33
|
* @returns {object} CI audit result
|
|
33
34
|
*/
|
|
34
|
-
function runCiWiring ({ manifest, framework }) {
|
|
35
|
+
function runCiWiring ({ manifest, framework, projectFileSources }) {
|
|
35
36
|
const contradiction = getFrameworkCiDiscoveryContradiction(framework, manifest)
|
|
36
37
|
if (contradiction) {
|
|
37
38
|
return getIncomplete(framework, contradiction.reason, {
|
|
@@ -47,6 +48,32 @@ function runCiWiring ({ manifest, framework }) {
|
|
|
47
48
|
domain: 'ci_configuration',
|
|
48
49
|
evidenceStrength: 'unknown',
|
|
49
50
|
}
|
|
51
|
+
if (hasNoSupportedCiConfiguration(manifest, ci)) {
|
|
52
|
+
return getIncomplete(
|
|
53
|
+
framework,
|
|
54
|
+
'No supported CI configuration file was found by bounded repository discovery. The CI audit is incomplete; ' +
|
|
55
|
+
'this does not prove that the repository has no external CI configuration.',
|
|
56
|
+
{
|
|
57
|
+
...evidence,
|
|
58
|
+
reasonCode: 'no-supported-ci-configuration',
|
|
59
|
+
recommendation: 'Identify the CI system and one repository-controlled test job. If CI is configured outside ' +
|
|
60
|
+
'this repository, review that configuration separately.',
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
if (hasUnavailableRemoteCiCommand(ci)) {
|
|
65
|
+
return getIncomplete(
|
|
66
|
+
framework,
|
|
67
|
+
'The selected CI path delegates test execution to a remote action or reusable workflow whose command is not ' +
|
|
68
|
+
'available in this repository. The CI audit is incomplete.',
|
|
69
|
+
{
|
|
70
|
+
...evidence,
|
|
71
|
+
reasonCode: 'remote-ci-command-unavailable',
|
|
72
|
+
recommendation: 'Review the referenced action or reusable workflow at its pinned revision. Keep the result ' +
|
|
73
|
+
'incomplete when its final test command and effective environment cannot be bound statically.',
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
}
|
|
50
77
|
const missing = getMissingReviewFields(ci)
|
|
51
78
|
if (missing.length > 0) {
|
|
52
79
|
return getIncomplete(
|
|
@@ -63,7 +90,7 @@ function runCiWiring ({ manifest, framework }) {
|
|
|
63
90
|
)
|
|
64
91
|
}
|
|
65
92
|
|
|
66
|
-
const source =
|
|
93
|
+
const source = readProjectSource(ci.configFile, projectFileSources)
|
|
67
94
|
if (!source) {
|
|
68
95
|
return getIncomplete(framework, 'The recorded CI configuration file is unavailable or too large to verify.', {
|
|
69
96
|
...evidence,
|
|
@@ -87,7 +114,7 @@ function runCiWiring ({ manifest, framework }) {
|
|
|
87
114
|
}
|
|
88
115
|
|
|
89
116
|
const command = ci.command.trim()
|
|
90
|
-
const resolution = getRunnerResolution(command, framework, ci)
|
|
117
|
+
const resolution = getRunnerResolution(command, framework, ci, projectFileSources)
|
|
91
118
|
const normalizedSource = jobSource.replaceAll('\\', '/')
|
|
92
119
|
const hasInitialization = /dd-trace\/ci\/init(?:\.js)?\b/.test(normalizedSource)
|
|
93
120
|
const matrixRelevant = matrixAffectsCiFacts(jobSource, command)
|
|
@@ -138,12 +165,16 @@ function runCiWiring ({ manifest, framework }) {
|
|
|
138
165
|
if (initialization.status === 'missing' &&
|
|
139
166
|
resolution.status === 'confirmed' &&
|
|
140
167
|
unresolved.relevant.length === 0) {
|
|
168
|
+
const transportMissing = ciFacts.transport.status === 'missing'
|
|
141
169
|
return getFailure(
|
|
142
170
|
framework,
|
|
143
171
|
'The checksum-bound CI job reaches the selected test framework through a bounded static command path, but ' +
|
|
144
|
-
|
|
172
|
+
`does not configure the dd-trace/ci/init preload${
|
|
173
|
+
transportMissing ? ' and declares no visible Datadog Agent or agentless reporting transport' : ''
|
|
174
|
+
}. Test Optimization is not configured in that job.`,
|
|
145
175
|
{
|
|
146
176
|
...evidence,
|
|
177
|
+
ciConfigurationStatus: 'not_configured',
|
|
147
178
|
ciRemediation: remediation,
|
|
148
179
|
conclusion: 'confirmed_misconfigured',
|
|
149
180
|
evidenceStrength: 'confirmed_static',
|
|
@@ -153,17 +184,25 @@ function runCiWiring ({ manifest, framework }) {
|
|
|
153
184
|
}
|
|
154
185
|
|
|
155
186
|
if (resolution.status !== 'confirmed') {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
const visibleFacts = []
|
|
188
|
+
if (initialization.status === 'missing') {
|
|
189
|
+
visibleFacts.push('The selected job has no visible dd-trace/ci/init preload.')
|
|
190
|
+
}
|
|
191
|
+
if (ciFacts.transport.status === 'missing') {
|
|
192
|
+
visibleFacts.push('The recorded review found no visible Datadog Agent or agentless reporting transport.')
|
|
193
|
+
}
|
|
194
|
+
const recommendation = /working directory/i.test(resolution.reason)
|
|
195
|
+
? 'Keep the CI job\'s actual working directory. Resolve the repository-root wrapper to the selected test ' +
|
|
196
|
+
'runner statically; do not substitute the framework package directory merely to make the audit conclusive.'
|
|
197
|
+
: 'Resolve the remaining wrapper or dynamic command statically, or confirm the effective NODE_OPTIONS value ' +
|
|
198
|
+
'in the final test process with DD_TRACE_DEBUG=1.'
|
|
159
199
|
return getIncomplete(
|
|
160
200
|
framework,
|
|
161
|
-
|
|
162
|
-
`${framework.framework} runner: ${resolution.reason}
|
|
201
|
+
'The CI audit remains incomplete because the selected command could not be resolved to the ' +
|
|
202
|
+
`${framework.framework} runner: ${resolution.reason}. ${visibleFacts.join(' ')}`.trim(),
|
|
163
203
|
{
|
|
164
204
|
...evidence,
|
|
165
|
-
recommendation
|
|
166
|
-
'NODE_OPTIONS value in the final test process with DD_TRACE_DEBUG=1.',
|
|
205
|
+
recommendation,
|
|
167
206
|
}
|
|
168
207
|
)
|
|
169
208
|
}
|
|
@@ -244,9 +283,10 @@ function getEffectiveNodeOptionsOverride (commandPath = []) {
|
|
|
244
283
|
* @param {string} command selected CI command
|
|
245
284
|
* @param {object} framework framework manifest entry
|
|
246
285
|
* @param {object} ci selected CI evidence
|
|
286
|
+
* @param {Map<string, Buffer|undefined>} [projectFileSources] approval-bound project sources
|
|
247
287
|
* @returns {object} static runner resolution
|
|
248
288
|
*/
|
|
249
|
-
function getRunnerResolution (command, framework, ci) {
|
|
289
|
+
function getRunnerResolution (command, framework, ci, projectFileSources) {
|
|
250
290
|
if (getDirectRunner(command, framework.framework)) {
|
|
251
291
|
return {
|
|
252
292
|
commandPath: [command],
|
|
@@ -266,7 +306,7 @@ function getRunnerResolution (command, framework, ci) {
|
|
|
266
306
|
status: 'unresolved',
|
|
267
307
|
}
|
|
268
308
|
}
|
|
269
|
-
const scripts = readProjectScripts(framework.project.packageJson)
|
|
309
|
+
const scripts = readProjectScripts(framework.project.packageJson, projectFileSources)
|
|
270
310
|
if (!scripts) {
|
|
271
311
|
return {
|
|
272
312
|
reason: 'the approval-bound project package.json is unavailable or invalid',
|
|
@@ -283,10 +323,10 @@ function getRunnerResolution (command, framework, ci) {
|
|
|
283
323
|
status: 'unresolved',
|
|
284
324
|
}
|
|
285
325
|
}
|
|
286
|
-
const
|
|
326
|
+
const candidates = expansion.terminals.filter(terminal => {
|
|
287
327
|
return getDirectRunner(terminal.command, framework.framework)
|
|
288
328
|
})
|
|
289
|
-
if (
|
|
329
|
+
if (candidates.length === 0) {
|
|
290
330
|
return {
|
|
291
331
|
lifecycleScripts: expansion.lifecycleScripts,
|
|
292
332
|
reason: 'no bounded local package-script path reaches the selected framework runner',
|
|
@@ -294,6 +334,15 @@ function getRunnerResolution (command, framework, ci) {
|
|
|
294
334
|
status: 'unresolved',
|
|
295
335
|
}
|
|
296
336
|
}
|
|
337
|
+
if (candidates.length > 1) {
|
|
338
|
+
return {
|
|
339
|
+
lifecycleScripts: expansion.lifecycleScripts,
|
|
340
|
+
reason: 'more than one bounded local package-script path reaches the selected framework runner',
|
|
341
|
+
source: 'unresolved_wrapper',
|
|
342
|
+
status: 'unresolved',
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const candidate = candidates[0]
|
|
297
346
|
return {
|
|
298
347
|
commandPath: candidate.path,
|
|
299
348
|
lifecycleScripts: expansion.lifecycleScripts,
|
|
@@ -303,11 +352,11 @@ function getRunnerResolution (command, framework, ci) {
|
|
|
303
352
|
}
|
|
304
353
|
}
|
|
305
354
|
|
|
306
|
-
function readProjectScripts (filename) {
|
|
355
|
+
function readProjectScripts (filename, projectFileSources) {
|
|
307
356
|
try {
|
|
308
|
-
const
|
|
309
|
-
if (
|
|
310
|
-
const packageJson = JSON.parse(
|
|
357
|
+
const source = readProjectSource(filename, projectFileSources)
|
|
358
|
+
if (source === undefined) return
|
|
359
|
+
const packageJson = JSON.parse(source)
|
|
311
360
|
if (!packageJson.scripts || typeof packageJson.scripts !== 'object' ||
|
|
312
361
|
Array.isArray(packageJson.scripts)) return {}
|
|
313
362
|
return packageJson.scripts
|
|
@@ -346,18 +395,19 @@ function classifyUnresolved (ci, resolution, matrixRelevant, jobSource) {
|
|
|
346
395
|
const ignored = []
|
|
347
396
|
const unresolved = Array.isArray(ci.unresolved) ? ci.unresolved : []
|
|
348
397
|
const githubHosted = /[/\\]\.github[/\\]workflows[/\\]/.test(ci.configFile) &&
|
|
349
|
-
|
|
398
|
+
/^[ \t]*runs-on:[ \t]*(?:ubuntu|windows|macos)-/mi.test(jobSource)
|
|
350
399
|
|
|
351
400
|
for (const item of unresolved) {
|
|
352
401
|
const isMatrix = /\bmatrix\b/i.test(item)
|
|
353
|
-
const isResolvedPackagePath = resolution.
|
|
354
|
-
|
|
402
|
+
const isResolvedPackagePath = resolution.status === 'confirmed' &&
|
|
403
|
+
resolution.source === 'local_package_script' &&
|
|
404
|
+
/\b(?:bun|lifecycle|npm|package script|pnpm|pretest|posttest|yarn)\b/i.test(item)
|
|
355
405
|
const isAmbientGithubSettings = githubHosted &&
|
|
356
|
-
/\b(?:repository|organization|environment)[-\s,\w]
|
|
406
|
+
/\b(?:repository|organization|environment)[-\s,\w]+\b(?:secrets?|variables?)\b/i.test(item) &&
|
|
357
407
|
/\b(?:inject|inherit|outside)\b/i.test(item)
|
|
358
408
|
const isOtherJob = /^Other jobs?\b/i.test(item) ||
|
|
359
|
-
/\bsecond\b
|
|
360
|
-
/\brelease\b
|
|
409
|
+
/\bsecond\b.+\bjob\b.+\bonly\b.+\bselected\b/i.test(item) ||
|
|
410
|
+
/\brelease\b.+\bcontains no test job\b/i.test(item)
|
|
361
411
|
if ((isMatrix && !matrixRelevant) ||
|
|
362
412
|
isResolvedPackagePath ||
|
|
363
413
|
isAmbientGithubSettings ||
|
|
@@ -373,6 +423,29 @@ function classifyUnresolved (ci, resolution, matrixRelevant, jobSource) {
|
|
|
373
423
|
return { ignored, relevant }
|
|
374
424
|
}
|
|
375
425
|
|
|
426
|
+
function hasNoSupportedCiConfiguration (manifest, ci) {
|
|
427
|
+
if (ci.configFile || ci.job || ci.command) return false
|
|
428
|
+
const unresolved = Array.isArray(ci.unresolved) ? ci.unresolved : []
|
|
429
|
+
return manifest.ciDiscovery?.found?.length === 0 ||
|
|
430
|
+
unresolved.some(item => /No supported CI configuration file was found/i.test(item))
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function hasUnavailableRemoteCiCommand (ci) {
|
|
434
|
+
if (ci.command) return false
|
|
435
|
+
const evidence = [
|
|
436
|
+
ci.step,
|
|
437
|
+
...(Array.isArray(ci.unresolved) ? ci.unresolved : []),
|
|
438
|
+
].filter(Boolean)
|
|
439
|
+
if (evidence.some(item => {
|
|
440
|
+
return /\b(?:remote|external|third-party)\s+(?:action|workflow)\b/i.test(item)
|
|
441
|
+
})) return true
|
|
442
|
+
|
|
443
|
+
return evidence.some(item => {
|
|
444
|
+
const reference = /^\s*uses:\s*["']?([^"'\s]+)["']?\s*$/im.exec(item)?.[1]
|
|
445
|
+
return reference && !reference.startsWith('./')
|
|
446
|
+
})
|
|
447
|
+
}
|
|
448
|
+
|
|
376
449
|
function matrixAffectsCiFacts (jobSource, command) {
|
|
377
450
|
const matrixReference = /\bmatrix\s*[.[]/
|
|
378
451
|
if (!matrixReference.test(jobSource)) return false
|
|
@@ -407,6 +480,8 @@ function normalizeDirectCommand (command) {
|
|
|
407
480
|
assignments.push(...crossEnv.assignments)
|
|
408
481
|
source = source.slice(crossEnv.length)
|
|
409
482
|
}
|
|
483
|
+
source = source.replace(/^(?:(?:bunx|npx)(?:\.cmd)?|(?:pnpm|yarn)(?:\.cmd)?\s+exec)\s+/, '')
|
|
484
|
+
.replace(/^bun x\s+/, '')
|
|
410
485
|
return { assignments, index: prefix.length, source }
|
|
411
486
|
}
|
|
412
487
|
|
|
@@ -446,7 +521,7 @@ function getSelectedJobSource (source, ci) {
|
|
|
446
521
|
|
|
447
522
|
function getYamlKeyEntry (line, index) {
|
|
448
523
|
if (!line || /^\s*(?:#|$)/.test(line) || /^\s/.test(line) && line.includes('\t')) return
|
|
449
|
-
const match = /^(\s*)(?:"([^"]+)"|'([^']+)'|([
|
|
524
|
+
const match = /^(\s*)(?:"([^"]+)"|'([^']+)'|([^\s:#][^:]*)):\s*(?:#.*)?$/.exec(line)
|
|
450
525
|
if (!match) return
|
|
451
526
|
return {
|
|
452
527
|
indent: match[1].length,
|
|
@@ -491,16 +566,23 @@ function getMissingReviewFields (ci) {
|
|
|
491
566
|
}
|
|
492
567
|
|
|
493
568
|
/**
|
|
494
|
-
* Reads one bounded regular
|
|
569
|
+
* Reads one bounded regular project file or its approval-bound snapshot.
|
|
495
570
|
*
|
|
496
|
-
* @param {string} filename
|
|
571
|
+
* @param {string} filename project file
|
|
572
|
+
* @param {Map<string, Buffer|undefined>} [projectFileSources] approval-bound project sources
|
|
497
573
|
* @returns {string|undefined} source
|
|
498
574
|
*/
|
|
499
|
-
function
|
|
575
|
+
function readProjectSource (filename, projectFileSources) {
|
|
576
|
+
if (typeof filename !== 'string') return
|
|
577
|
+
const resolved = path.resolve(filename)
|
|
578
|
+
if (projectFileSources) {
|
|
579
|
+
if (!projectFileSources.has(resolved)) return
|
|
580
|
+
return projectFileSources.get(resolved)?.toString('utf8')
|
|
581
|
+
}
|
|
500
582
|
try {
|
|
501
|
-
const stat = fs.lstatSync(
|
|
583
|
+
const stat = fs.lstatSync(resolved)
|
|
502
584
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_CI_FILE_BYTES) return
|
|
503
|
-
return fs.readFileSync(
|
|
585
|
+
return fs.readFileSync(resolved, 'utf8')
|
|
504
586
|
} catch {}
|
|
505
587
|
}
|
|
506
588
|
|
|
@@ -519,11 +601,35 @@ function containsLiteral (source, value) {
|
|
|
519
601
|
|
|
520
602
|
function containsExecutionCommand (source, value) {
|
|
521
603
|
const command = String(value).replaceAll('\r\n', '\n').trim()
|
|
522
|
-
if (!command
|
|
523
|
-
|
|
604
|
+
if (!command) return false
|
|
605
|
+
const lines = source.replaceAll('\r\n', '\n').split('\n')
|
|
606
|
+
return lines.some((line, index) => {
|
|
524
607
|
if (/^\s*#/.test(line)) return false
|
|
525
|
-
const match = /^\s*(?:-\s*)?(?:run|script)
|
|
526
|
-
|
|
608
|
+
const match = /^\s*(?:-\s*)?(?:run|script):(.*)$/.exec(line)
|
|
609
|
+
if (!match) return false
|
|
610
|
+
const scalar = match[1].trim()
|
|
611
|
+
if (!/^\|[+-]?$/.test(scalar)) return scalar === command
|
|
612
|
+
|
|
613
|
+
const indicatorIndent = /^\s*/.exec(line)[0].length
|
|
614
|
+
const block = []
|
|
615
|
+
let contentIndent
|
|
616
|
+
for (let next = index + 1; next < lines.length; next++) {
|
|
617
|
+
if (!lines[next].trim()) {
|
|
618
|
+
block.push('')
|
|
619
|
+
continue
|
|
620
|
+
}
|
|
621
|
+
const nextIndent = /^\s*/.exec(lines[next])[0].length
|
|
622
|
+
if (contentIndent === undefined) {
|
|
623
|
+
if (nextIndent <= indicatorIndent) break
|
|
624
|
+
contentIndent = nextIndent
|
|
625
|
+
} else if (nextIndent < contentIndent) {
|
|
626
|
+
break
|
|
627
|
+
}
|
|
628
|
+
block.push(lines[next])
|
|
629
|
+
}
|
|
630
|
+
if (contentIndent === undefined) return false
|
|
631
|
+
const blockCommand = block.map(candidate => candidate.slice(contentIndent)).join('\n').trim()
|
|
632
|
+
return blockCommand === command
|
|
527
633
|
})
|
|
528
634
|
}
|
|
529
635
|
|
|
@@ -4,6 +4,7 @@ const fs = require('node:fs')
|
|
|
4
4
|
const path = require('path')
|
|
5
5
|
|
|
6
6
|
const { getArtifactId } = require('../artifact-id')
|
|
7
|
+
const { BLOCKER_CATEGORIES } = require('../blocker-category')
|
|
7
8
|
const { buildDatadogEnv, buildOfflineCaptureEnv, runCommand } = require('../command-runner')
|
|
8
9
|
const {
|
|
9
10
|
cleanupGeneratedRuntimeFiles,
|
|
@@ -19,8 +20,10 @@ const { readOfflineOutput } = require('../offline-output')
|
|
|
19
20
|
const { sanitizeForReport, sanitizeString } = require('../redaction')
|
|
20
21
|
const { getGeneratedCommand } = require('../runner-command')
|
|
21
22
|
const { ensureSafeDirectory, writeFileSafely } = require('../safe-files')
|
|
23
|
+
const { getValidationBlockerEvidence } = require('../validation-blocker')
|
|
22
24
|
|
|
23
|
-
const ANSI_PATTERN =
|
|
25
|
+
const ANSI_PATTERN =
|
|
26
|
+
new RegExp(`${String.fromCharCode(27)}${String.raw`\[[\u0030-\u003F]*[\u0020-\u002F]*[\u0040-\u007E]`}`, 'g')
|
|
24
27
|
|
|
25
28
|
function frameworkOutDir (out, framework, scenario) {
|
|
26
29
|
return path.join(out, 'runs', getArtifactId(framework.id), scenario)
|
|
@@ -193,10 +196,11 @@ async function prepareGeneratedScenario (framework, scenarioId) {
|
|
|
193
196
|
function requireGeneratedScenario (framework, scenarioId, scenarioName) {
|
|
194
197
|
const strategy = framework.generatedTestStrategy
|
|
195
198
|
if (strategy?.status === 'not_possible') {
|
|
196
|
-
return
|
|
199
|
+
return incomplete(
|
|
197
200
|
framework,
|
|
198
201
|
scenarioName,
|
|
199
|
-
`
|
|
202
|
+
`The validator cannot create a collectible test for this advanced feature: ${strategy.reason} ` +
|
|
203
|
+
'No conclusion was reached for this advanced feature.',
|
|
200
204
|
getGeneratedStrategySkipEvidence(framework, scenarioName, scenarioId)
|
|
201
205
|
)
|
|
202
206
|
}
|
|
@@ -254,9 +258,9 @@ function getGeneratedStrategySkipEvidence (framework, scenarioName, scenarioId)
|
|
|
254
258
|
reasonCode = 'generated-test-strategy-not-verified'
|
|
255
259
|
}
|
|
256
260
|
|
|
257
|
-
|
|
261
|
+
const evidence = {
|
|
258
262
|
featureEligibility: {
|
|
259
|
-
eligible: false,
|
|
263
|
+
...(reasonCode === 'generated-test-strategy-not-possible' ? {} : { eligible: false }),
|
|
260
264
|
blockedBy: 'generated-test-strategy',
|
|
261
265
|
reason: strategy?.reason,
|
|
262
266
|
reasonCode,
|
|
@@ -265,6 +269,12 @@ function getGeneratedStrategySkipEvidence (framework, scenarioName, scenarioId)
|
|
|
265
269
|
requiredGeneratedScenario: scenarioId,
|
|
266
270
|
},
|
|
267
271
|
}
|
|
272
|
+
if (reasonCode === 'generated-test-strategy-not-possible') {
|
|
273
|
+
evidence.blockerCategory = BLOCKER_CATEGORIES.VALIDATOR_LIMITATION
|
|
274
|
+
evidence.recommendation = 'Report that the selected runner configuration cannot collect validator-generated ' +
|
|
275
|
+
'tests to validator engineering. Basic Reporting remains valid; project setup changes are not required.'
|
|
276
|
+
}
|
|
277
|
+
return evidence
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
function basicEventEvidence (events) {
|
|
@@ -442,6 +452,8 @@ function copy (target, source, key) {
|
|
|
442
452
|
|
|
443
453
|
function summarizeDebugRerun ({ result, events, offline, outDir }) {
|
|
444
454
|
const output = `${result.stdout}\n${result.stderr}`
|
|
455
|
+
const testEvents = eventsOfType(events, 'test')
|
|
456
|
+
const sourceFiles = new Set(testEvents.map(test => test.testSourceFile).filter(Boolean))
|
|
445
457
|
|
|
446
458
|
return {
|
|
447
459
|
ran: true,
|
|
@@ -449,8 +461,12 @@ function summarizeDebugRerun ({ result, events, offline, outDir }) {
|
|
|
449
461
|
commandTimedOut: result.timedOut,
|
|
450
462
|
debugCommandFailed: result.exitCode !== 0 || result.timedOut === true,
|
|
451
463
|
offlineExporterInitialized: offline.initialized,
|
|
464
|
+
settingsLoadedFromCache: offline.inputs.settings?.status === 'loaded',
|
|
452
465
|
artifactDirectory: outDir,
|
|
453
466
|
...basicEventEvidence(events),
|
|
467
|
+
testEventsWithoutSourceFile: testEvents.length - testEvents.filter(test => test.testSourceFile).length,
|
|
468
|
+
testSourceFileCount: sourceFiles.size,
|
|
469
|
+
testSourceFiles: [...sourceFiles].slice(0, 5),
|
|
454
470
|
debugLines: findInterestingLines(output, [
|
|
455
471
|
/dd-trace/i,
|
|
456
472
|
/test optimization/i,
|
|
@@ -541,7 +557,15 @@ function inconclusive (framework, scenario, diagnosis, evidence = {}, outDir, ex
|
|
|
541
557
|
}
|
|
542
558
|
|
|
543
559
|
function error (framework, scenario, err, outDir = err?.artifactDirectory) {
|
|
544
|
-
|
|
560
|
+
const blockerEvidence = getValidationBlockerEvidence(err)
|
|
561
|
+
return result(
|
|
562
|
+
framework,
|
|
563
|
+
scenario,
|
|
564
|
+
blockerEvidence ? 'blocked' : 'error',
|
|
565
|
+
blockerEvidence ? err.message : (err && err.stack ? err.stack : String(err)),
|
|
566
|
+
blockerEvidence || {},
|
|
567
|
+
outDir
|
|
568
|
+
)
|
|
545
569
|
}
|
|
546
570
|
|
|
547
571
|
function result (framework, scenario, status, diagnosis, evidence, outDir, extraArtifacts) {
|
|
@@ -149,7 +149,7 @@ function buildQuarantinedResponse (framework, scenario, discoveredIdentities = [
|
|
|
149
149
|
for (const identity of identities) {
|
|
150
150
|
for (const suite of getSuiteCandidates(identity, scenario)) {
|
|
151
151
|
for (const name of getNameCandidates(identity)) {
|
|
152
|
-
suites[suite]
|
|
152
|
+
suites[suite] ||= { tests: {} }
|
|
153
153
|
suites[suite].tests[name] = {
|
|
154
154
|
properties: {
|
|
155
155
|
quarantined: true,
|
|
@@ -210,7 +210,7 @@ function summarizeManagedTests (testManagementTests) {
|
|
|
210
210
|
}
|
|
211
211
|
summary.set(displaySuite, testNames)
|
|
212
212
|
}
|
|
213
|
-
return [...summary
|
|
213
|
+
return [...summary].slice(0, 5).map(([suite, tests]) => ({
|
|
214
214
|
suite,
|
|
215
215
|
tests: [...tests].slice(0, 5),
|
|
216
216
|
}))
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
getFrameworkDefinitions,
|
|
9
9
|
runDiagnosis,
|
|
10
10
|
} = require('../diagnose')
|
|
11
|
+
const { BLOCKER_CATEGORIES } = require('./blocker-category')
|
|
11
12
|
const { sanitizeForReport } = require('./redaction')
|
|
12
13
|
const { writeFileSafely } = require('./safe-files')
|
|
13
14
|
|
|
@@ -45,6 +46,7 @@ function runStaticDiagnosis ({ manifest, out }) {
|
|
|
45
46
|
function getStaticBlocker (framework, diagnosis) {
|
|
46
47
|
if (!SUPPORTED_FRAMEWORKS.has(framework.framework)) {
|
|
47
48
|
return {
|
|
49
|
+
blockerCategory: BLOCKER_CATEGORIES.VALIDATOR_LIMITATION,
|
|
48
50
|
reason: `Unsupported test framework detected: ${getUnsupportedFrameworkName(framework)}.`,
|
|
49
51
|
recommendation: 'Choose Jest, Mocha, Cucumber, Cypress, Playwright, or Vitest for live validation.',
|
|
50
52
|
}
|
|
@@ -56,6 +58,7 @@ function getStaticBlocker (framework, diagnosis) {
|
|
|
56
58
|
const version = parseVersion(framework.frameworkVersion)
|
|
57
59
|
if (version && !satisfies(version, definition.supportedRange)) {
|
|
58
60
|
return {
|
|
61
|
+
blockerCategory: BLOCKER_CATEGORIES.UNSUPPORTED_VERSION,
|
|
59
62
|
reason:
|
|
60
63
|
`${definition.name} ${version} is not supported. Supported range is ${definition.supportedRange}.`,
|
|
61
64
|
recommendation: definition.recommendation,
|
|
@@ -65,6 +68,7 @@ function getStaticBlocker (framework, diagnosis) {
|
|
|
65
68
|
const staticVersionError = findStaticVersionError(definition, diagnosis, framework, version)
|
|
66
69
|
if (staticVersionError) {
|
|
67
70
|
return {
|
|
71
|
+
blockerCategory: BLOCKER_CATEGORIES.UNSUPPORTED_VERSION,
|
|
68
72
|
reason: staticVersionError.title,
|
|
69
73
|
recommendation: staticVersionError.recommendation || staticVersionError.message,
|
|
70
74
|
}
|
|
@@ -117,8 +121,11 @@ function getExactFrameworkLocations (diagnosis, framework) {
|
|
|
117
121
|
const locations = new Set()
|
|
118
122
|
addRelativeFrameworkLocation(locations, diagnosis, framework.project?.packageJson)
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
const configFiles = framework.project?.configFiles
|
|
125
|
+
if (configFiles) {
|
|
126
|
+
for (const configFile of configFiles) {
|
|
127
|
+
addRelativeFrameworkLocation(locations, diagnosis, configFile)
|
|
128
|
+
}
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
return locations
|
|
@@ -149,7 +156,7 @@ function normalizeRelativePath (location) {
|
|
|
149
156
|
|
|
150
157
|
function parseVersion (rawVersion) {
|
|
151
158
|
if (typeof rawVersion !== 'string') return null
|
|
152
|
-
const match = rawVersion.match(
|
|
159
|
+
const match = rawVersion.match(/(?<!\d)\d+\.\d+\.\d+/)
|
|
153
160
|
return match ? match[0] : null
|
|
154
161
|
}
|
|
155
162
|
|
|
@@ -4,7 +4,8 @@ const cypressAdapter = require('./framework-adapters/cypress')
|
|
|
4
4
|
const cucumberAdapter = require('./framework-adapters/cucumber')
|
|
5
5
|
const playwrightAdapter = require('./framework-adapters/playwright')
|
|
6
6
|
|
|
7
|
-
const ANSI_PATTERN =
|
|
7
|
+
const ANSI_PATTERN =
|
|
8
|
+
new RegExp(`${String.fromCharCode(27)}${String.raw`\[[\u0030-\u003F]*[\u0020-\u002F]*[\u0040-\u007E]`}`, 'g')
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Extracts the final test count from common JavaScript test-runner summaries.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function createValidationBlocker (message, { kind, recommendation, suppressReport = false }) {
|
|
4
|
+
const error = new Error(message)
|
|
5
|
+
error.validationBlocker = { kind, recommendation }
|
|
6
|
+
error.validationExitCode = 2
|
|
7
|
+
error.suppressReport = suppressReport
|
|
8
|
+
return error
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getValidationBlockerEvidence (error) {
|
|
12
|
+
if (!error?.validationBlocker) return
|
|
13
|
+
return {
|
|
14
|
+
blockerKind: error.validationBlocker.kind,
|
|
15
|
+
domain: 'validator_state',
|
|
16
|
+
recommendation: error.validationBlocker.recommendation,
|
|
17
|
+
validationIncomplete: true,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = { createValidationBlocker, getValidationBlockerEvidence }
|