dd-trace 6.4.0 → 6.6.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/README.electron.md +7 -0
- package/README.md +17 -0
- package/ci/diagnose.js +2100 -0
- package/ci/init.js +23 -2
- package/ci/runbook.md +198 -0
- package/ci/test-optimization-validation/approval-artifacts.js +143 -0
- package/ci/test-optimization-validation/approval.js +299 -0
- package/ci/test-optimization-validation/artifact-id.js +20 -0
- package/ci/test-optimization-validation/bounded-json.js +121 -0
- package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
- package/ci/test-optimization-validation/ci-discovery.js +181 -0
- package/ci/test-optimization-validation/ci-remediation.js +210 -0
- package/ci/test-optimization-validation/cli.js +903 -0
- package/ci/test-optimization-validation/command-blocker.js +81 -0
- package/ci/test-optimization-validation/command-output-policy.js +206 -0
- package/ci/test-optimization-validation/command-runner.js +707 -0
- package/ci/test-optimization-validation/command-suitability.js +471 -0
- package/ci/test-optimization-validation/executable-approval.js +48 -0
- package/ci/test-optimization-validation/executable.js +480 -0
- package/ci/test-optimization-validation/generated-file-policy.js +63 -0
- package/ci/test-optimization-validation/generated-files.js +351 -0
- package/ci/test-optimization-validation/generated-verifier.js +196 -0
- package/ci/test-optimization-validation/init-probe-preload.js +163 -0
- package/ci/test-optimization-validation/init-probe.js +246 -0
- package/ci/test-optimization-validation/late-initialization.js +63 -0
- package/ci/test-optimization-validation/local-command.js +163 -0
- package/ci/test-optimization-validation/manifest-loader.js +133 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
- package/ci/test-optimization-validation/manifest-schema.js +862 -0
- package/ci/test-optimization-validation/offline-fixtures.js +327 -0
- package/ci/test-optimization-validation/offline-output.js +406 -0
- package/ci/test-optimization-validation/payload-normalizer.js +72 -0
- package/ci/test-optimization-validation/plan-writer.js +1120 -0
- package/ci/test-optimization-validation/preflight-runner.js +114 -0
- package/ci/test-optimization-validation/redaction.js +331 -0
- package/ci/test-optimization-validation/report-writer.js +1508 -0
- package/ci/test-optimization-validation/safe-files.js +203 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
- package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
- package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
- package/ci/test-optimization-validation/setup-runner.js +97 -0
- package/ci/test-optimization-validation/static-diagnosis.js +159 -0
- package/ci/test-optimization-validation/test-output.js +129 -0
- package/ci/test-optimization-validation-manifest.schema.json +1 -0
- package/ci/validate-test-optimization.js +3 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +121 -8
- package/init.js +18 -0
- package/initialize.mjs +1 -1
- package/loader-hook.mjs +28 -18
- package/openfeature.d.ts +1 -0
- package/openfeature.js +4 -0
- package/package.json +11 -8
- package/packages/datadog-instrumentations/src/ai.js +8 -2
- package/packages/datadog-instrumentations/src/child_process.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
- package/packages/datadog-instrumentations/src/cucumber.js +31 -19
- package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
- package/packages/datadog-instrumentations/src/fastify.js +7 -11
- package/packages/datadog-instrumentations/src/helpers/channel.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
- package/packages/datadog-instrumentations/src/jest.js +44 -17
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +79 -32
- package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
- package/packages/datadog-instrumentations/src/mongodb.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +3 -3
- package/packages/datadog-instrumentations/src/mquery.js +2 -2
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +24 -0
- package/packages/datadog-instrumentations/src/nyc.js +0 -2
- package/packages/datadog-instrumentations/src/oracledb.js +2 -2
- package/packages/datadog-instrumentations/src/pg.js +2 -2
- package/packages/datadog-instrumentations/src/playwright.js +162 -46
- package/packages/datadog-instrumentations/src/process.js +3 -0
- package/packages/datadog-instrumentations/src/router.js +18 -8
- package/packages/datadog-instrumentations/src/selenium.js +52 -26
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +3 -3
- package/packages/datadog-instrumentations/src/vitest-main.js +14 -28
- package/packages/datadog-instrumentations/src/vitest-util.js +0 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +5 -8
- package/packages/datadog-instrumentations/src/ws.js +2 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
- package/packages/datadog-plugin-cucumber/src/index.js +3 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -57
- package/packages/datadog-plugin-cypress/src/index.js +6 -1
- package/packages/datadog-plugin-cypress/src/support.js +92 -26
- package/packages/datadog-plugin-electron/src/ipc.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +87 -45
- package/packages/datadog-plugin-graphql/src/validate.js +2 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
- package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +2 -1
- package/packages/datadog-plugin-playwright/src/index.js +181 -65
- package/packages/datadog-plugin-router/src/index.js +11 -2
- package/packages/datadog-plugin-selenium/src/index.js +5 -36
- package/packages/datadog-plugin-vitest/src/index.js +5 -5
- package/packages/datadog-plugin-ws/src/close.js +2 -1
- package/packages/datadog-plugin-ws/src/producer.js +2 -1
- package/packages/datadog-plugin-ws/src/receiver.js +2 -1
- package/packages/datadog-plugin-ws/src/server.js +2 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
- package/packages/dd-trace/src/azure_metadata.js +2 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +41 -3
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +1 -1
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
- package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +168 -8
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +16 -0
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +10 -0
- package/packages/dd-trace/src/config/supported-configurations.json +66 -0
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
- package/packages/dd-trace/src/exporters/common/request.js +59 -30
- package/packages/dd-trace/src/exporters/common/url.js +15 -1
- package/packages/dd-trace/src/feature-registry.js +10 -3
- package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
- package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
- package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
- package/packages/dd-trace/src/llmobs/noop.js +6 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
- package/packages/dd-trace/src/llmobs/sdk.js +17 -0
- package/packages/dd-trace/src/llmobs/tagger.js +68 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/llmobs/util.js +32 -0
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
- package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
- package/packages/dd-trace/src/openfeature/index.js +0 -2
- package/packages/dd-trace/src/openfeature/noop.js +1 -28
- package/packages/dd-trace/src/openfeature/register.js +16 -27
- package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
- package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
- package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
- package/packages/dd-trace/src/plugins/util/git.js +3 -2
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
- package/packages/dd-trace/src/plugins/util/test.js +56 -4
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/proxy.js +84 -7
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/standalone/index.js +0 -14
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/packages/dd-trace/src/util.js +26 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
|
@@ -4,27 +4,12 @@ const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
|
4
4
|
const { storage } = require('../../datadog-core')
|
|
5
5
|
|
|
6
6
|
const {
|
|
7
|
-
|
|
7
|
+
setRumTestCorrelation,
|
|
8
8
|
TEST_BROWSER_DRIVER,
|
|
9
9
|
TEST_BROWSER_DRIVER_VERSION,
|
|
10
10
|
TEST_BROWSER_NAME,
|
|
11
|
-
TEST_BROWSER_VERSION,
|
|
12
11
|
TEST_TYPE,
|
|
13
12
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
14
|
-
const { SPAN_TYPE } = require('../../../ext/tags')
|
|
15
|
-
|
|
16
|
-
function isTestSpan (span) {
|
|
17
|
-
return span.context().getTag(SPAN_TYPE) === 'test'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function getTestSpanFromTrace (trace) {
|
|
21
|
-
for (const span of trace.started) {
|
|
22
|
-
if (isTestSpan(span)) {
|
|
23
|
-
return span
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return null
|
|
27
|
-
}
|
|
28
13
|
|
|
29
14
|
class SeleniumPlugin extends CiPlugin {
|
|
30
15
|
static id = 'selenium'
|
|
@@ -32,32 +17,16 @@ class SeleniumPlugin extends CiPlugin {
|
|
|
32
17
|
constructor (...args) {
|
|
33
18
|
super(...args)
|
|
34
19
|
|
|
35
|
-
this.addSub('ci:selenium:driver:get', ({
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
browserVersion,
|
|
40
|
-
isRumActive,
|
|
41
|
-
}) => {
|
|
42
|
-
const store = storage('legacy').getStore()
|
|
43
|
-
const span = store?.span
|
|
44
|
-
if (!span) {
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
const testSpan = isTestSpan(span) ? span : getTestSpanFromTrace(span.context()._trace)
|
|
20
|
+
this.addSub('ci:selenium:driver:get', (ctx) => {
|
|
21
|
+
const { seleniumVersion, browserName } = ctx
|
|
22
|
+
const activeSpan = storage('legacy').getStore()?.span
|
|
23
|
+
const testSpan = setRumTestCorrelation(ctx, activeSpan)
|
|
48
24
|
if (!testSpan) {
|
|
49
25
|
return
|
|
50
26
|
}
|
|
51
|
-
if (setTraceId) {
|
|
52
|
-
setTraceId(testSpan.context().toTraceId())
|
|
53
|
-
}
|
|
54
|
-
if (isRumActive) {
|
|
55
|
-
testSpan.setTag(TEST_IS_RUM_ACTIVE, 'true')
|
|
56
|
-
}
|
|
57
27
|
testSpan.setTag(TEST_BROWSER_DRIVER, 'selenium')
|
|
58
28
|
testSpan.setTag(TEST_BROWSER_DRIVER_VERSION, seleniumVersion)
|
|
59
29
|
testSpan.setTag(TEST_BROWSER_NAME, browserName)
|
|
60
|
-
testSpan.setTag(TEST_BROWSER_VERSION, browserVersion)
|
|
61
30
|
testSpan.setTag(TEST_TYPE, 'browser')
|
|
62
31
|
})
|
|
63
32
|
}
|
|
@@ -400,7 +400,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
400
400
|
return ctx.currentStore
|
|
401
401
|
})
|
|
402
402
|
|
|
403
|
-
this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush,
|
|
403
|
+
this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush, onDone }) => {
|
|
404
404
|
if (testSuiteSpan) {
|
|
405
405
|
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
406
406
|
testSuiteSpan.finish()
|
|
@@ -408,10 +408,10 @@ class VitestPlugin extends CiPlugin {
|
|
|
408
408
|
}
|
|
409
409
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
410
410
|
if (deferFlush) {
|
|
411
|
-
|
|
411
|
+
onDone()
|
|
412
412
|
return
|
|
413
413
|
}
|
|
414
|
-
this.tracer._exporter.flush(
|
|
414
|
+
this.tracer._exporter.flush(onDone)
|
|
415
415
|
if (this.runningTestProbe) {
|
|
416
416
|
this.removeDiProbe(this.runningTestProbe)
|
|
417
417
|
}
|
|
@@ -442,7 +442,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
442
442
|
requestErrorTags,
|
|
443
443
|
vitestPool,
|
|
444
444
|
isVitestNoWorkerInitActive,
|
|
445
|
-
|
|
445
|
+
onDone,
|
|
446
446
|
}) => {
|
|
447
447
|
for (const [tag, value] of Object.entries(requestErrorTags || {})) {
|
|
448
448
|
this.testSessionSpan.setTag(tag, value)
|
|
@@ -481,7 +481,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
481
481
|
provider: this.ciProviderName,
|
|
482
482
|
autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
483
483
|
})
|
|
484
|
-
this.tracer._exporter.flush(
|
|
484
|
+
this.tracer._exporter.flush(onDone)
|
|
485
485
|
})
|
|
486
486
|
|
|
487
487
|
this.addSub('ci:vitest:coverage-report', ({ rootDir, onDone }) => {
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
SPAN_POINTER_DIRECTION,
|
|
7
7
|
SPAN_POINTER_DIRECTION_NAME,
|
|
8
8
|
} = require('../../dd-trace/src/constants')
|
|
9
|
+
const { getSegment } = require('../../dd-trace/src/util')
|
|
9
10
|
const {
|
|
10
11
|
incrementWebSocketCounter,
|
|
11
12
|
buildWebSocketSpanPointerHash,
|
|
@@ -29,7 +30,7 @@ class WSClosePlugin extends TracingPlugin {
|
|
|
29
30
|
|
|
30
31
|
const spanKind = isPeerClose ? 'consumer' : 'producer'
|
|
31
32
|
const spanTags = socket.spanTags
|
|
32
|
-
const path = spanTags['resource.name']
|
|
33
|
+
const path = getSegment(spanTags['resource.name'], ' ', 1)
|
|
33
34
|
const service = this.serviceName({ pluginConfig: this.config })
|
|
34
35
|
const span = this.startSpan(this.operationName(), {
|
|
35
36
|
service,
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
SPAN_POINTER_DIRECTION,
|
|
7
7
|
SPAN_POINTER_DIRECTION_NAME,
|
|
8
8
|
} = require('../../dd-trace/src/constants')
|
|
9
|
+
const { getSegment } = require('../../dd-trace/src/util')
|
|
9
10
|
const {
|
|
10
11
|
incrementWebSocketCounter,
|
|
11
12
|
buildWebSocketSpanPointerHash,
|
|
@@ -23,7 +24,7 @@ class WSProducerPlugin extends TracingPlugin {
|
|
|
23
24
|
if (!socket.spanContext) return
|
|
24
25
|
|
|
25
26
|
const spanTags = socket.spanTags
|
|
26
|
-
const path = spanTags['resource.name']
|
|
27
|
+
const path = getSegment(spanTags['resource.name'], ' ', 1)
|
|
27
28
|
const opCode = binary ? 'binary' : 'text'
|
|
28
29
|
const service = this.serviceName({ pluginConfig: this.config })
|
|
29
30
|
const span = this.startSpan(this.operationName(), {
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
SPAN_POINTER_DIRECTION,
|
|
7
7
|
SPAN_POINTER_DIRECTION_NAME,
|
|
8
8
|
} = require('../../dd-trace/src/constants')
|
|
9
|
+
const { getSegment } = require('../../dd-trace/src/util')
|
|
9
10
|
const {
|
|
10
11
|
incrementWebSocketCounter,
|
|
11
12
|
buildWebSocketSpanPointerHash,
|
|
@@ -28,7 +29,7 @@ class WSReceiverPlugin extends TracingPlugin {
|
|
|
28
29
|
if (!socket.spanContext) return
|
|
29
30
|
|
|
30
31
|
const spanTags = socket.spanTags
|
|
31
|
-
const path = spanTags['resource.name']
|
|
32
|
+
const path = getSegment(spanTags['resource.name'], ' ', 1)
|
|
32
33
|
const opCode = binary ? 'binary' : 'text'
|
|
33
34
|
|
|
34
35
|
const service = this.serviceName({ pluginConfig: this.config })
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const TracingPlugin = require('../../dd-trace/src/plugins/tracing.js')
|
|
4
4
|
const tags = require('../../../ext/tags.js')
|
|
5
5
|
const { HTTP_HEADERS } = require('../../../ext/formats')
|
|
6
|
+
const { getSegment } = require('../../dd-trace/src/util')
|
|
6
7
|
const {
|
|
7
8
|
createWebSocketSpanContext,
|
|
8
9
|
hasTraceHeaders,
|
|
@@ -94,7 +95,7 @@ function getRequestProtocol (req, fallback = 'ws') {
|
|
|
94
95
|
|
|
95
96
|
// 2. Check for a trusted header set by a proxy
|
|
96
97
|
if (req.headers && req.headers['x-forwarded-proto']) {
|
|
97
|
-
const proto = req.headers['x-forwarded-proto']
|
|
98
|
+
const proto = getSegment(req.headers['x-forwarded-proto'], ',', 0).trim()
|
|
98
99
|
if (proto === 'https') return 'wss'
|
|
99
100
|
if (proto === 'http') return 'ws'
|
|
100
101
|
}
|
|
@@ -230,7 +230,7 @@ class AIGuard extends NoopAIGuard {
|
|
|
230
230
|
// still applies for SDK callers that don't supply an explicit parent.
|
|
231
231
|
const traceOpts = childOf ? { childOf } : {}
|
|
232
232
|
return this.#tracer.trace(TAGS.RESOURCE, traceOpts, async (span) => {
|
|
233
|
-
const last = messages
|
|
233
|
+
const last = messages.at(-1)
|
|
234
234
|
const target = this.#isToolCall(last) ? 'tool' : 'prompt'
|
|
235
235
|
span.setTag(TAGS.TARGET_TAG_KEY, target)
|
|
236
236
|
if (target === 'tool') {
|
|
@@ -190,7 +190,7 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
addURLParsingSubscriptions () {
|
|
193
|
-
const urlResultTaintedProperties = ['host', 'origin', 'hostname']
|
|
193
|
+
const urlResultTaintedProperties = new Set(['host', 'origin', 'hostname'])
|
|
194
194
|
this.addSub(
|
|
195
195
|
{ channelName: 'datadog:url:parse:finish' },
|
|
196
196
|
({ input, base, parsed, isURL }) => {
|
|
@@ -212,7 +212,7 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
212
212
|
this.addSub(
|
|
213
213
|
{ channelName: 'datadog:url:getter:finish' },
|
|
214
214
|
(context) => {
|
|
215
|
-
if (!urlResultTaintedProperties.
|
|
215
|
+
if (!urlResultTaintedProperties.has(context.property)) return
|
|
216
216
|
|
|
217
217
|
const origRange = this._taintedURLs.get(context.urlObject)
|
|
218
218
|
if (!origRange) return
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { getSegment } = require('../../../util')
|
|
4
|
+
|
|
3
5
|
function addMetricsToSpan (rootSpan, metrics, tagPrefix) {
|
|
4
6
|
if (!rootSpan?.addTags || !metrics) return
|
|
5
7
|
|
|
@@ -44,7 +46,7 @@ function filterTags (tags) {
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
function processTagValue (tags) {
|
|
47
|
-
return tags.map(tag => tag.includes(':') ? tag
|
|
49
|
+
return tags.map(tag => tag.includes(':') ? getSegment(tag, ':', 1) : tag)
|
|
48
50
|
.join('_').replaceAll('.', '_')
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -6,10 +6,11 @@ const os = require('os')
|
|
|
6
6
|
const getConfig = require('./config')
|
|
7
7
|
const { getEnvironmentVariable } = require('./config/helper')
|
|
8
8
|
const { getIsAzureFunction } = require('./serverless')
|
|
9
|
+
const { getSegment } = require('./util')
|
|
9
10
|
|
|
10
11
|
function extractSubscriptionID (ownerName) {
|
|
11
12
|
if (ownerName !== undefined) {
|
|
12
|
-
const subId = ownerName
|
|
13
|
+
const subId = getSegment(ownerName, '+', 0).trim()
|
|
13
14
|
if (subId.length > 0) {
|
|
14
15
|
return subId
|
|
15
16
|
}
|
|
@@ -7,11 +7,25 @@ const log = require('../../log')
|
|
|
7
7
|
const { getEnvironmentVariables } = require('../../config/helper')
|
|
8
8
|
const getDebuggerConfig = require('../../debugger/config')
|
|
9
9
|
|
|
10
|
-
const probeIdToResolveBreakpointSet = new Map()
|
|
11
|
-
const probeIdToResolveBreakpointRemove = new Map()
|
|
12
10
|
const drainRequestIdToResolveBreakpointHit = new Map()
|
|
13
11
|
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {object} ProbeState
|
|
14
|
+
* @property {string} locationKey
|
|
15
|
+
* @property {(breakpoint: object) => void} onHitBreakpoint
|
|
16
|
+
* @property {Promise<void>|undefined} removePromise
|
|
17
|
+
* @property {(() => void)|undefined} resolveRemove
|
|
18
|
+
* @property {(() => void)|undefined} resolveSet
|
|
19
|
+
* @property {Promise<void>} setPromise
|
|
20
|
+
* @property {boolean} setPosted
|
|
21
|
+
*/
|
|
22
|
+
|
|
14
23
|
class TestVisDynamicInstrumentation {
|
|
24
|
+
/** @type {Map<string, Promise<void>>} */
|
|
25
|
+
#pendingProbeRemovalByLocation = new Map()
|
|
26
|
+
/** @type {Map<string, ProbeState>} */
|
|
27
|
+
#probeStateById = new Map()
|
|
28
|
+
|
|
15
29
|
/**
|
|
16
30
|
* @param {import('../../config/config-base')} config - Tracer configuration
|
|
17
31
|
*/
|
|
@@ -24,37 +38,88 @@ class TestVisDynamicInstrumentation {
|
|
|
24
38
|
this.breakpointSetChannel = new MessageChannel()
|
|
25
39
|
this.breakpointHitChannel = new MessageChannel()
|
|
26
40
|
this.breakpointRemoveChannel = new MessageChannel()
|
|
27
|
-
this.onHitBreakpointByProbeId = new Map()
|
|
28
41
|
}
|
|
29
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @param {string|undefined} probeId
|
|
45
|
+
*/
|
|
30
46
|
removeProbe (probeId) {
|
|
31
|
-
|
|
32
|
-
|
|
47
|
+
const probeState = probeId === undefined ? undefined : this.#probeStateById.get(probeId)
|
|
48
|
+
if (!probeState) return Promise.resolve()
|
|
49
|
+
if (probeState.removePromise) return probeState.removePromise
|
|
50
|
+
|
|
51
|
+
if (!probeState.setPosted) {
|
|
52
|
+
this.#probeStateById.delete(probeId)
|
|
53
|
+
probeState.resolveSet?.()
|
|
54
|
+
probeState.resolveSet = undefined
|
|
55
|
+
return Promise.resolve()
|
|
56
|
+
}
|
|
33
57
|
|
|
34
|
-
|
|
58
|
+
const postRemoval = () => new Promise(resolve => {
|
|
59
|
+
probeState.resolveRemove = resolve
|
|
60
|
+
this.breakpointRemoveChannel.port2.postMessage(probeId)
|
|
61
|
+
})
|
|
62
|
+
const removeAcknowledgedPromise = probeState.setPromise.then(postRemoval)
|
|
63
|
+
const removePromise = removeAcknowledgedPromise.then(() => this.waitForInFlightBreakpointHits())
|
|
64
|
+
probeState.removePromise = removePromise
|
|
65
|
+
this.#pendingProbeRemovalByLocation.set(probeState.locationKey, removeAcknowledgedPromise)
|
|
66
|
+
removeAcknowledgedPromise.then(() => {
|
|
67
|
+
if (this.#pendingProbeRemovalByLocation.get(probeState.locationKey) === removeAcknowledgedPromise) {
|
|
68
|
+
this.#pendingProbeRemovalByLocation.delete(probeState.locationKey)
|
|
69
|
+
}
|
|
35
70
|
})
|
|
71
|
+
removePromise.then(() => {
|
|
72
|
+
if (this.#probeStateById.get(probeId) === probeState) {
|
|
73
|
+
this.#probeStateById.delete(probeId)
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
return removePromise
|
|
36
77
|
}
|
|
37
78
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
79
|
+
/**
|
|
80
|
+
* @param {{ file: string, line: number }} location
|
|
81
|
+
* @param {(breakpoint: object) => void} onHitBreakpoint
|
|
82
|
+
*/
|
|
41
83
|
addLineProbe ({ file, line }, onHitBreakpoint) {
|
|
42
84
|
if (!this.worker) { // not init yet
|
|
43
85
|
this.start()
|
|
44
86
|
}
|
|
45
87
|
const probeId = randomUUID()
|
|
88
|
+
const locationKey = `${file}:${line}`
|
|
89
|
+
const pendingRemoval = this.#pendingProbeRemovalByLocation.get(locationKey)
|
|
46
90
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
91
|
+
let resolveSet
|
|
92
|
+
const setProbePromise = new Promise(resolve => {
|
|
93
|
+
resolveSet = resolve
|
|
94
|
+
})
|
|
95
|
+
const probeState = {
|
|
96
|
+
locationKey,
|
|
97
|
+
onHitBreakpoint,
|
|
98
|
+
removePromise: undefined,
|
|
99
|
+
resolveRemove: undefined,
|
|
100
|
+
resolveSet,
|
|
101
|
+
setPromise: setProbePromise,
|
|
102
|
+
setPosted: false,
|
|
103
|
+
}
|
|
104
|
+
this.#probeStateById.set(probeId, probeState)
|
|
105
|
+
|
|
106
|
+
const setProbe = () => {
|
|
107
|
+
if (this.#probeStateById.get(probeId) === probeState) {
|
|
108
|
+
probeState.setPosted = true
|
|
109
|
+
this.breakpointSetChannel.port2.postMessage(
|
|
110
|
+
{ id: probeId, file, line }
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (pendingRemoval) {
|
|
115
|
+
pendingRemoval.then(setProbe)
|
|
116
|
+
} else {
|
|
117
|
+
setProbe()
|
|
118
|
+
}
|
|
52
119
|
|
|
53
120
|
return [
|
|
54
121
|
probeId,
|
|
55
|
-
|
|
56
|
-
probeIdToResolveBreakpointSet.set(probeId, resolve)
|
|
57
|
-
}),
|
|
122
|
+
setProbePromise,
|
|
58
123
|
]
|
|
59
124
|
}
|
|
60
125
|
|
|
@@ -139,10 +204,10 @@ class TestVisDynamicInstrumentation {
|
|
|
139
204
|
this.worker.unref?.()
|
|
140
205
|
|
|
141
206
|
this.breakpointSetChannel.port2.on('message', (probeId) => {
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
207
|
+
const probeState = this.#probeStateById.get(probeId)
|
|
208
|
+
if (probeState?.resolveSet) {
|
|
209
|
+
probeState.resolveSet()
|
|
210
|
+
probeState.resolveSet = undefined
|
|
146
211
|
}
|
|
147
212
|
}).unref?.()
|
|
148
213
|
|
|
@@ -157,19 +222,19 @@ class TestVisDynamicInstrumentation {
|
|
|
157
222
|
}
|
|
158
223
|
|
|
159
224
|
const { probe: { id: probeId } } = snapshot
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
162
|
-
|
|
225
|
+
const probeState = this.#probeStateById.get(probeId)
|
|
226
|
+
if (probeState) {
|
|
227
|
+
probeState.onHitBreakpoint({ snapshot })
|
|
163
228
|
} else {
|
|
164
229
|
log.warn('Received a breakpoint hit for an unknown probe')
|
|
165
230
|
}
|
|
166
231
|
}).unref?.()
|
|
167
232
|
|
|
168
233
|
this.breakpointRemoveChannel.port2.on('message', (probeId) => {
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
234
|
+
const probeState = this.#probeStateById.get(probeId)
|
|
235
|
+
if (probeState?.resolveRemove) {
|
|
236
|
+
probeState.resolveRemove()
|
|
237
|
+
probeState.resolveRemove = undefined
|
|
173
238
|
}
|
|
174
239
|
}).unref?.()
|
|
175
240
|
}
|
|
@@ -60,7 +60,7 @@ function parseJsonResponse (rawJson) {
|
|
|
60
60
|
function parseKnownTestsResponse (rawJson, options = {}) {
|
|
61
61
|
const parsedResponse = parseJsonResponse(rawJson)
|
|
62
62
|
if (options.validateRequiredFields) {
|
|
63
|
-
validateKnownTestsResponse(parsedResponse)
|
|
63
|
+
validateKnownTestsResponse(parsedResponse, options)
|
|
64
64
|
}
|
|
65
65
|
const { data: { attributes: { tests } } } = parsedResponse
|
|
66
66
|
return tests
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint-disable eslint-rules/eslint-process-env */
|
|
4
|
+
|
|
5
|
+
const TestOptimizationHttpCache = require('../../test-optimization-http-cache').TestOptimizationHttpCache
|
|
6
|
+
const CiVisibilityExporter = require('../ci-visibility-exporter')
|
|
7
|
+
const { CiValidationSink } = require('./sink')
|
|
8
|
+
const CiValidationWriter = require('./writer')
|
|
9
|
+
|
|
10
|
+
const VALIDATION_MANIFEST_ENV = '_DD_TEST_OPTIMIZATION_VALIDATION_MANIFEST_FILE'
|
|
11
|
+
const VALIDATION_OUTPUT_ENV = '_DD_TEST_OPTIMIZATION_VALIDATION_OUTPUT_DIR'
|
|
12
|
+
const VALIDATION_CAPTURE_MODE_ENV = '_DD_TEST_OPTIMIZATION_VALIDATION_CAPTURE_MODE'
|
|
13
|
+
|
|
14
|
+
class CiValidationExporter extends CiVisibilityExporter {
|
|
15
|
+
/**
|
|
16
|
+
* Creates an immediately available cache-only Test Optimization exporter.
|
|
17
|
+
*
|
|
18
|
+
* @param {object} config tracer configuration
|
|
19
|
+
*/
|
|
20
|
+
constructor (config) {
|
|
21
|
+
const validationManifestPath = process.env[VALIDATION_MANIFEST_ENV]
|
|
22
|
+
const validationOutputRoot = process.env[VALIDATION_OUTPUT_ENV]
|
|
23
|
+
if (!validationManifestPath) {
|
|
24
|
+
throw new Error('Offline Test Optimization validation requires an explicit private manifest path.')
|
|
25
|
+
}
|
|
26
|
+
if (!validationOutputRoot) {
|
|
27
|
+
throw new Error('Offline Test Optimization validation requires an explicit private output root.')
|
|
28
|
+
}
|
|
29
|
+
const cache = new TestOptimizationHttpCache({
|
|
30
|
+
validationManifestPath,
|
|
31
|
+
})
|
|
32
|
+
super(config, { cacheOnly: true, testOptimizationHttpCache: cache })
|
|
33
|
+
|
|
34
|
+
this._sink = new CiValidationSink(validationOutputRoot, {
|
|
35
|
+
captureMode: process.env[VALIDATION_CAPTURE_MODE_ENV] || 'strict',
|
|
36
|
+
})
|
|
37
|
+
this._writer = new CiValidationWriter({ sink: this._sink, tags: config.tags })
|
|
38
|
+
this._isInitialized = true
|
|
39
|
+
this._isGzipCompatible = false
|
|
40
|
+
this._resolveCanUseCiVisProtocol(true)
|
|
41
|
+
this._resolveGit()
|
|
42
|
+
this.exportUncodedTraces()
|
|
43
|
+
|
|
44
|
+
this._finalizeValidation = () => this.flush(() => this._sink.writeSummary())
|
|
45
|
+
globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(this._finalizeValidation)
|
|
46
|
+
process.once('exit', this._finalizeValidation)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Loads library settings from the validator-controlled cache.
|
|
51
|
+
*
|
|
52
|
+
* @param {object} testConfiguration test configuration identity
|
|
53
|
+
* @param {Function} callback completion callback
|
|
54
|
+
*/
|
|
55
|
+
getLibraryConfiguration (testConfiguration, callback) {
|
|
56
|
+
super.getLibraryConfiguration(testConfiguration, (err, configuration) => {
|
|
57
|
+
this._sink.writeInputResult('settings', err)
|
|
58
|
+
if (err) process.exitCode = 1
|
|
59
|
+
callback(err, configuration)
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Loads known tests from the validator-controlled cache.
|
|
65
|
+
*
|
|
66
|
+
* @param {object} testConfiguration test configuration identity
|
|
67
|
+
* @param {Function} callback completion callback
|
|
68
|
+
*/
|
|
69
|
+
getKnownTests (testConfiguration, callback) {
|
|
70
|
+
super.getKnownTests(testConfiguration, (err, tests) => {
|
|
71
|
+
this._sink.writeInputResult('known_tests', err)
|
|
72
|
+
if (err) process.exitCode = 1
|
|
73
|
+
callback(err, tests)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Loads skippable suites from the validator-controlled cache.
|
|
79
|
+
*
|
|
80
|
+
* @param {object} testConfiguration test configuration identity
|
|
81
|
+
* @param {Function} callback completion callback
|
|
82
|
+
*/
|
|
83
|
+
getSkippableSuites (testConfiguration, callback) {
|
|
84
|
+
super.getSkippableSuites(testConfiguration, (err, suites, correlationId, coverage) => {
|
|
85
|
+
this._sink.writeInputResult('skippable_tests', err)
|
|
86
|
+
if (err) process.exitCode = 1
|
|
87
|
+
callback(err, suites, correlationId, coverage)
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Loads managed tests from the validator-controlled cache.
|
|
93
|
+
*
|
|
94
|
+
* @param {object} testConfiguration test configuration identity
|
|
95
|
+
* @param {Function} callback completion callback
|
|
96
|
+
*/
|
|
97
|
+
getTestManagementTests (testConfiguration, callback) {
|
|
98
|
+
super.getTestManagementTests(testConfiguration, (err, tests) => {
|
|
99
|
+
this._sink.writeInputResult('test_management', err)
|
|
100
|
+
if (err) process.exitCode = 1
|
|
101
|
+
callback(err, tests)
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resolves the inherited git-upload gate without performing an upload.
|
|
107
|
+
*
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
sendGitMetadata () {
|
|
111
|
+
this._resolveGit()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Drops debugger logs in offline validation mode.
|
|
116
|
+
*
|
|
117
|
+
* @returns {void}
|
|
118
|
+
*/
|
|
119
|
+
exportDiLogs () {}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Reports that code coverage is outside the offline validator's scope.
|
|
123
|
+
*
|
|
124
|
+
* @returns {boolean} always false
|
|
125
|
+
*/
|
|
126
|
+
canReportCodeCoverage () {
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Rejects coverage report upload in offline validation mode.
|
|
132
|
+
*
|
|
133
|
+
* @param {object} options ignored upload options
|
|
134
|
+
* @param {Function} callback completion callback
|
|
135
|
+
*/
|
|
136
|
+
uploadCoverageReport (options, callback) {
|
|
137
|
+
callback(new Error('Coverage report upload is disabled during offline Test Optimization validation.'))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Reports that screenshot upload is unavailable.
|
|
142
|
+
*
|
|
143
|
+
* @returns {boolean} always false
|
|
144
|
+
*/
|
|
145
|
+
canUploadTestScreenshots () {
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Rejects screenshot upload in offline validation mode.
|
|
151
|
+
*
|
|
152
|
+
* @param {object} options ignored upload options
|
|
153
|
+
* @param {Function} callback completion callback
|
|
154
|
+
*/
|
|
155
|
+
uploadTestScreenshot (options, callback) {
|
|
156
|
+
callback(new Error('Screenshot upload is disabled during offline Test Optimization validation.'))
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = CiValidationExporter
|