dd-trace 6.10.0 → 6.12.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/LICENSE-3rdparty.csv +5 -0
- package/README.md +0 -17
- package/index.d.ts +128 -6
- package/initialize.mjs +28 -17
- package/openfeature.js +2 -2
- package/package.json +27 -23
- package/packages/datadog-esbuild/index.js +0 -34
- package/packages/datadog-instrumentations/src/anthropic.js +210 -15
- package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
- package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
- package/packages/datadog-instrumentations/src/bunyan.js +3 -16
- package/packages/datadog-instrumentations/src/cucumber.js +30 -15
- package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
- package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
- package/packages/datadog-instrumentations/src/cypress.js +2 -0
- package/packages/datadog-instrumentations/src/fastify.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
- package/packages/datadog-instrumentations/src/jest.js +25 -17
- package/packages/datadog-instrumentations/src/mariadb.js +278 -21
- package/packages/datadog-instrumentations/src/mocha/main.js +539 -55
- package/packages/datadog-instrumentations/src/mocha/utils.js +135 -19
- package/packages/datadog-instrumentations/src/playwright-reporter.js +247 -0
- package/packages/datadog-instrumentations/src/playwright.js +182 -35
- package/packages/datadog-instrumentations/src/router.js +2 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +6 -8
- package/packages/datadog-instrumentations/src/vitest-main.js +11 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -8
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
- package/packages/datadog-plugin-bunyan/src/index.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +11 -0
- package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
- package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +81 -29
- package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
- package/packages/datadog-plugin-cypress/src/index.js +12 -6
- package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
- package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
- package/packages/datadog-plugin-electron/src/index.js +2 -0
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +6 -0
- package/packages/datadog-plugin-mocha/src/index.js +56 -1
- package/packages/datadog-plugin-nats/src/index.js +1 -1
- package/packages/datadog-plugin-openai/src/tracing.js +41 -30
- package/packages/datadog-plugin-openai-agents/src/integration.js +1 -0
- package/packages/datadog-plugin-playwright/src/index.js +46 -13
- package/packages/datadog-plugin-vitest/src/index.js +6 -0
- package/packages/datadog-webpack/index.js +0 -11
- package/packages/dd-trace/index.js +0 -1
- package/packages/dd-trace/src/agent/info.js +6 -5
- package/packages/dd-trace/src/aiguard/client.js +100 -1
- package/packages/dd-trace/src/aiguard/errors.js +41 -0
- package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
- package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
- package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
- package/packages/dd-trace/src/aiguard/sdk.js +22 -278
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
- package/packages/dd-trace/src/appsec/reporter.js +2 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +13 -0
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +16 -0
- package/packages/dd-trace/src/appsec/telemetry/waf.js +24 -0
- package/packages/dd-trace/src/carrier.js +107 -48
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +29 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +27 -9
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +26 -8
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +10 -4
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +5 -5
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
- package/packages/dd-trace/src/config/index.js +13 -2
- package/packages/dd-trace/src/config/major-overrides.js +7 -0
- package/packages/dd-trace/src/config/supported-configurations.json +14 -0
- package/packages/dd-trace/src/datastreams/index.js +2 -0
- package/packages/dd-trace/src/datastreams/manager.js +9 -2
- package/packages/dd-trace/src/datastreams/processor.js +15 -13
- package/packages/dd-trace/src/datastreams/size.js +5 -0
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/index.js +5 -11
- package/packages/dd-trace/src/debugger/index.js +4 -2
- package/packages/dd-trace/src/debugger/inspect-segment.js +154 -0
- package/packages/dd-trace/src/evp_proxy/constants.js +8 -0
- package/packages/dd-trace/src/evp_proxy/direct.js +64 -0
- package/packages/dd-trace/src/evp_proxy/discovery.js +133 -0
- package/packages/dd-trace/src/evp_proxy/path.js +22 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
- package/packages/dd-trace/src/exporters/common/request.js +5 -2
- package/packages/dd-trace/src/exporters/common/writer.js +11 -6
- package/packages/dd-trace/src/llmobs/experiments/client.js +167 -5
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +484 -92
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +302 -29
- package/packages/dd-trace/src/llmobs/experiments/index.js +75 -64
- package/packages/dd-trace/src/llmobs/experiments/noop.js +135 -7
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +101 -9
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
- package/packages/dd-trace/src/noop/proxy.js +3 -4
- package/packages/dd-trace/src/openfeature/constants/constants.js +0 -18
- package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
- package/packages/dd-trace/src/openfeature/index.js +7 -4
- package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/base.js +153 -11
- package/packages/dd-trace/src/openfeature/writers/exposures.js +62 -14
- package/packages/dd-trace/src/openfeature/writers/util.js +97 -15
- package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -13
- package/packages/dd-trace/src/opentracing/tracer.js +5 -2
- package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
- package/packages/dd-trace/src/plugin_manager.js +3 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/jest.js +4 -3
- package/packages/dd-trace/src/plugins/util/test.js +9 -9
- package/packages/dd-trace/src/plugins/util/web.js +3 -0
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
- package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
- package/packages/dd-trace/src/proxy.js +38 -29
- package/packages/dd-trace/src/ritm.js +9 -2
- package/packages/dd-trace/src/serverless.js +37 -0
- package/packages/dd-trace/src/span_format.js +1 -0
- package/packages/dd-trace/src/span_stats.js +30 -3
- package/packages/dd-trace/src/storage-channels.js +86 -0
- package/packages/dd-trace/src/telemetry/metrics.js +62 -8
- package/packages/dd-trace/src/telemetry/send-data.js +1 -0
- package/packages/dd-trace/src/tracer.js +9 -2
- package/packages/dd-trace/src/tracer_metadata.js +14 -1
- package/packages/dd-trace/src/web-tags-cache.js +132 -0
- package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/https-proxy-agent/LICENSE +22 -0
- package/vendor/dist/https-proxy-agent/index.js +4 -0
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/proxy-from-env/LICENSE +20 -0
- package/vendor/dist/proxy-from-env/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
- package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
- package/packages/dd-trace/src/feature-registry.js +0 -29
- package/packages/dd-trace/src/openfeature/register.js +0 -35
- package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
|
@@ -1,90 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
|
|
4
|
-
const { HTTP_CLIENT_IP, NETWORK_CLIENT_IP, HTTP_USERAGENT } = require('../../../../ext/tags')
|
|
5
|
-
const { USER_ID, USER_SESSION_ID } = require('../appsec/addresses')
|
|
6
|
-
const { getActiveRequest } = require('../appsec/store')
|
|
7
3
|
const log = require('../log')
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const { keepTrace } = require('../priority_sampler')
|
|
12
|
-
const { AI_GUARD } = require('../standalone/product')
|
|
4
|
+
const AIGuardClient = require('./client')
|
|
5
|
+
const { createEvaluationOutcome, EvaluationReporter } = require('./evaluation')
|
|
6
|
+
const { AIGuardAbortError } = require('./errors')
|
|
13
7
|
const NoopAIGuard = require('./noop')
|
|
14
|
-
const executeRequest = require('./client')
|
|
15
8
|
const TAGS = require('./tags')
|
|
16
9
|
|
|
17
|
-
const aiguardMetrics = telemetryMetrics.manager.namespace('ai_guard')
|
|
18
|
-
|
|
19
|
-
const ALLOW = 'ALLOW'
|
|
20
|
-
|
|
21
|
-
// Tags from the service entry span that must be mirrored onto every AI Guard span
|
|
22
|
-
// so anomaly detection pipelines can process each span independently.
|
|
23
|
-
const SERVICE_ENTRY_TAG_MAPPINGS = [
|
|
24
|
-
[HTTP_USERAGENT, TAGS.HTTP_USERAGENT_TAG_KEY],
|
|
25
|
-
[HTTP_CLIENT_IP, TAGS.HTTP_CLIENT_IP_TAG_KEY],
|
|
26
|
-
[NETWORK_CLIENT_IP, TAGS.NETWORK_CLIENT_IP_TAG_KEY],
|
|
27
|
-
[USER_ID, TAGS.USR_ID_TAG_KEY],
|
|
28
|
-
[USER_SESSION_ID, TAGS.USR_SESSION_ID_TAG_KEY],
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Reports a telemetry error
|
|
33
|
-
*
|
|
34
|
-
* @param {string} errorType - The error type constant (client_error, bad_status, bad_response)
|
|
35
|
-
* @param {{ source: string, integration: string }} telemetryTags - Source and integration tags
|
|
36
|
-
*/
|
|
37
|
-
function reportTelemetryError (errorType, telemetryTags) {
|
|
38
|
-
aiguardMetrics.count(TAGS.TELEMETRY_REQUESTS, { error: true, ...telemetryTags }).inc(1)
|
|
39
|
-
aiguardMetrics.count(TAGS.TELEMETRY_ERROR, { type: errorType, ...telemetryTags }).inc(1)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
class AIGuardAbortError extends Error {
|
|
43
|
-
constructor (reason, tags, tagProbs, sds) {
|
|
44
|
-
super(reason)
|
|
45
|
-
this.name = 'AIGuardAbortError'
|
|
46
|
-
this.reason = reason
|
|
47
|
-
this.tags = tags
|
|
48
|
-
this.tagProbabilities = tagProbs
|
|
49
|
-
this.sds = sds || []
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
class AIGuardClientError extends Error {
|
|
54
|
-
constructor (message, opts = {}) {
|
|
55
|
-
super(message)
|
|
56
|
-
this.name = 'AIGuardClientError'
|
|
57
|
-
if (opts.errors) {
|
|
58
|
-
this.errors = opts.errors
|
|
59
|
-
}
|
|
60
|
-
if (opts.cause) {
|
|
61
|
-
this.cause = opts.cause
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Resolves the AI Guard host for a given Datadog site. Sites with a single subdomain level
|
|
68
|
-
* (e.g. `datadoghq.com`, `ddog-gov.com`) are served from the `app.` subdomain, while regional
|
|
69
|
-
* sites (e.g. `us3.datadoghq.com`, `ap1.datadoghq.com`) are used as-is.
|
|
70
|
-
*
|
|
71
|
-
* @param {string} site - Datadog site (e.g. `datadoghq.com`, `us3.datadoghq.com`)
|
|
72
|
-
* @returns {string} The host to use for the AI Guard endpoint
|
|
73
|
-
*/
|
|
74
|
-
function aiGuardHost (site) {
|
|
75
|
-
return site.split('.').length === 2 ? `app.${site}` : site
|
|
76
|
-
}
|
|
77
|
-
|
|
78
10
|
class AIGuard extends NoopAIGuard {
|
|
79
11
|
#initialized
|
|
80
12
|
#tracer
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#timeout
|
|
84
|
-
#maxMessagesLength
|
|
85
|
-
#maxContentSize
|
|
13
|
+
#client
|
|
14
|
+
#reporter
|
|
86
15
|
#meta
|
|
87
|
-
#config
|
|
88
16
|
|
|
89
17
|
/**
|
|
90
18
|
* @param {import('../tracer')} tracer - Tracer instance
|
|
@@ -99,223 +27,39 @@ class AIGuard extends NoopAIGuard {
|
|
|
99
27
|
return
|
|
100
28
|
}
|
|
101
29
|
this.#tracer = tracer
|
|
102
|
-
this.#
|
|
103
|
-
|
|
104
|
-
'DD-APPLICATION-KEY': config.DD_APP_KEY,
|
|
105
|
-
'DD-AI-GUARD-VERSION': tracerVersion,
|
|
106
|
-
'DD-AI-GUARD-SOURCE': 'SDK',
|
|
107
|
-
'DD-AI-GUARD-LANGUAGE': 'nodejs',
|
|
108
|
-
}
|
|
109
|
-
const endpoint = config.experimental.aiguard.endpoint || `https://${aiGuardHost(config.site)}/api/v2/ai-guard`
|
|
110
|
-
this.#evaluateUrl = `${endpoint}/evaluate`
|
|
111
|
-
this.#timeout = config.experimental.aiguard.timeout
|
|
112
|
-
this.#maxMessagesLength = config.experimental.aiguard.maxMessagesLength
|
|
113
|
-
this.#maxContentSize = config.experimental.aiguard.maxContentSize
|
|
30
|
+
this.#client = new AIGuardClient(config)
|
|
31
|
+
this.#reporter = new EvaluationReporter(config)
|
|
114
32
|
this.#meta = { service: config.service, env: config.env }
|
|
115
|
-
this.#config = config
|
|
116
33
|
this.#initialized = true
|
|
117
34
|
}
|
|
118
35
|
|
|
119
|
-
/**
|
|
120
|
-
* Returns a safe copy of the messages to be serialized into the meta struct.
|
|
121
|
-
*
|
|
122
|
-
* - Clones each message so callers cannot mutate the data set in the meta struct.
|
|
123
|
-
* - Truncates the list of messages and `content` fields emitting metrics accordingly.
|
|
124
|
-
*
|
|
125
|
-
* @param {import('../../../../index').aiguard.Message[]} messages
|
|
126
|
-
* @param {{ source: string, integration: string }} telemetryTags
|
|
127
|
-
*/
|
|
128
|
-
#buildMessagesForMetaStruct (messages, telemetryTags) {
|
|
129
|
-
const size = Math.min(messages.length, this.#maxMessagesLength)
|
|
130
|
-
if (messages.length > size) {
|
|
131
|
-
aiguardMetrics.count(TAGS.TELEMETRY_TRUNCATED, { type: 'messages', ...telemetryTags }).inc(1)
|
|
132
|
-
}
|
|
133
|
-
const result = []
|
|
134
|
-
let contentTruncated = false
|
|
135
|
-
for (let i = messages.length - size; i < messages.length; i++) {
|
|
136
|
-
const message = rfdc(messages[i])
|
|
137
|
-
if (message.content?.length > this.#maxContentSize) {
|
|
138
|
-
contentTruncated = true
|
|
139
|
-
message.content = message.content.slice(0, this.#maxContentSize)
|
|
140
|
-
}
|
|
141
|
-
result.push(message)
|
|
142
|
-
}
|
|
143
|
-
if (contentTruncated) {
|
|
144
|
-
aiguardMetrics.count(TAGS.TELEMETRY_TRUNCATED, { type: 'content', ...telemetryTags }).inc(1)
|
|
145
|
-
}
|
|
146
|
-
return result
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
#isToolCall (message) {
|
|
150
|
-
return message.tool_calls || message.tool_call_id
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
#getToolName (message, history) {
|
|
154
|
-
// 1. assistant message with tool calls
|
|
155
|
-
if (message.tool_calls) {
|
|
156
|
-
const names = message.tool_calls.map((tool) => tool.function.name)
|
|
157
|
-
return names.length === 0 ? null : names.join(',')
|
|
158
|
-
}
|
|
159
|
-
// 2. assistant message with tool output (search the linked tool call in reverse order)
|
|
160
|
-
const id = message.tool_call_id
|
|
161
|
-
for (let i = history.length - 2; i >= 0; i--) {
|
|
162
|
-
const item = history[i]
|
|
163
|
-
if (item.tool_calls) {
|
|
164
|
-
for (const toolCall of item.tool_calls) {
|
|
165
|
-
if (toolCall.id === id) {
|
|
166
|
-
return toolCall.function.name
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return null
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
#setRootSpanClientIpTags (rootSpan) {
|
|
175
|
-
if (!rootSpan) return
|
|
176
|
-
|
|
177
|
-
const currentTags = rootSpan.context().getTags()
|
|
178
|
-
const needsHttpClientIp = !Object.hasOwn(currentTags, HTTP_CLIENT_IP)
|
|
179
|
-
const needsNetworkClientIp = !Object.hasOwn(currentTags, NETWORK_CLIENT_IP)
|
|
180
|
-
|
|
181
|
-
if (!needsHttpClientIp && !needsNetworkClientIp) return
|
|
182
|
-
|
|
183
|
-
const req = getActiveRequest()
|
|
184
|
-
|
|
185
|
-
if (!req) return
|
|
186
|
-
|
|
187
|
-
const newTags = {}
|
|
188
|
-
|
|
189
|
-
if (needsHttpClientIp) {
|
|
190
|
-
const clientIp = extractIp(this.#config, req)
|
|
191
|
-
|
|
192
|
-
if (clientIp) {
|
|
193
|
-
newTags[HTTP_CLIENT_IP] = clientIp
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (needsNetworkClientIp) {
|
|
198
|
-
const networkClientIp = req.socket?.remoteAddress
|
|
199
|
-
|
|
200
|
-
if (networkClientIp) {
|
|
201
|
-
newTags[NETWORK_CLIENT_IP] = networkClientIp
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (Object.keys(newTags).length > 0) {
|
|
206
|
-
rootSpan.addTags(newTags)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Copies service entry span tags needed by anomaly detection to the AI Guard span.
|
|
212
|
-
*
|
|
213
|
-
* @param {import('../opentracing/span')} guardSpan
|
|
214
|
-
* @param {import('../opentracing/span')} rootSpan
|
|
215
|
-
*/
|
|
216
|
-
#copyServiceEntryTagsToGuardSpan (guardSpan, rootSpan) {
|
|
217
|
-
const rootTags = rootSpan.context().getTags()
|
|
218
|
-
for (const [sourceTag, destTag] of SERVICE_ENTRY_TAG_MAPPINGS) {
|
|
219
|
-
const value = rootTags[sourceTag]
|
|
220
|
-
if (value !== undefined && value !== null) {
|
|
221
|
-
guardSpan.setTag(destTag, value)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
36
|
evaluate (messages, opts) {
|
|
227
37
|
if (!this.#initialized) {
|
|
228
38
|
return super.evaluate(messages, opts)
|
|
229
39
|
}
|
|
230
40
|
const { block = true, source = TAGS.SOURCE_SDK, integration = TAGS.INTEGRATION_NONE, childOf } = opts ?? {}
|
|
231
|
-
const telemetryTags = { source, integration }
|
|
232
41
|
// Only pass `childOf` when truthy so `tracer.trace`'s default (`scope().active()`)
|
|
233
42
|
// still applies for SDK callers that don't supply an explicit parent.
|
|
234
43
|
const traceOpts = childOf ? { childOf } : {}
|
|
235
44
|
return this.#tracer.trace(TAGS.RESOURCE, traceOpts, async (span) => {
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
span.setTag(TAGS.TARGET_TAG_KEY, target)
|
|
239
|
-
if (target === 'tool') {
|
|
240
|
-
const name = this.#getToolName(last, messages)
|
|
241
|
-
if (name) {
|
|
242
|
-
span.setTag(TAGS.TOOL_NAME_TAG_KEY, name)
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const metaStruct = {
|
|
246
|
-
messages: this.#buildMessagesForMetaStruct(messages, telemetryTags),
|
|
247
|
-
}
|
|
248
|
-
span.meta_struct = {
|
|
249
|
-
[TAGS.META_STRUCT_KEY]: metaStruct,
|
|
250
|
-
}
|
|
251
|
-
const rootSpan = span.context()?._trace?.started?.[0]
|
|
252
|
-
if (rootSpan) {
|
|
253
|
-
this.#setRootSpanClientIpTags(rootSpan)
|
|
254
|
-
this.#copyServiceEntryTagsToGuardSpan(span, rootSpan)
|
|
255
|
-
// keepTrace must be called before executeRequest so the sampling decision
|
|
256
|
-
// is propagated correctly to outgoing HTTP client calls.
|
|
257
|
-
keepTrace(rootSpan, AI_GUARD)
|
|
258
|
-
rootSpan.setTag(TAGS.EVENT_TAG_KEY, 'true')
|
|
259
|
-
}
|
|
260
|
-
let response
|
|
45
|
+
const report = this.#reporter.start(span, messages, { source, integration })
|
|
46
|
+
let evaluation
|
|
261
47
|
try {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
meta: this.#meta,
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
}
|
|
270
|
-
response = await executeRequest(
|
|
271
|
-
payload,
|
|
272
|
-
{ url: this.#evaluateUrl, headers: this.#headers, timeout: this.#timeout })
|
|
273
|
-
} catch (e) {
|
|
274
|
-
reportTelemetryError(TAGS.ERROR_TYPE_CLIENT, telemetryTags)
|
|
275
|
-
throw new AIGuardClientError(`Unexpected error calling AI Guard service: ${e.message}`, { cause: e })
|
|
276
|
-
}
|
|
277
|
-
if (response.status !== 200) {
|
|
278
|
-
reportTelemetryError(TAGS.ERROR_TYPE_STATUS, telemetryTags)
|
|
279
|
-
throw new AIGuardClientError(
|
|
280
|
-
`AI Guard service call failed, status ${response.status}`,
|
|
281
|
-
{ errors: response.body?.errors })
|
|
48
|
+
evaluation = await this.#client.evaluate(messages, this.#meta)
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.#reporter.fail(report, error.telemetryType ?? TAGS.ERROR_TYPE_CLIENT)
|
|
51
|
+
throw error
|
|
282
52
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const tags = attr.tags ?? []
|
|
291
|
-
if (tags.length > 0) {
|
|
292
|
-
metaStruct.attack_categories = tags
|
|
293
|
-
}
|
|
294
|
-
const sdsFindings = attr.sds_findings ?? []
|
|
295
|
-
if (sdsFindings.length > 0) {
|
|
296
|
-
metaStruct.sds = sdsFindings
|
|
297
|
-
}
|
|
298
|
-
const tagProbabilities = attr.tag_probs ?? {}
|
|
299
|
-
if (attr.tag_probs) {
|
|
300
|
-
metaStruct.tag_probs = tagProbabilities
|
|
301
|
-
}
|
|
302
|
-
const blockingEnabled = attr.is_blocking_enabled ?? false
|
|
303
|
-
const shouldBlock = block && blockingEnabled && action !== ALLOW
|
|
304
|
-
aiguardMetrics.count(TAGS.TELEMETRY_REQUESTS, {
|
|
305
|
-
action,
|
|
306
|
-
error: false,
|
|
307
|
-
block: shouldBlock,
|
|
308
|
-
...telemetryTags,
|
|
309
|
-
}).inc(1)
|
|
310
|
-
span.setTag(TAGS.ACTION_TAG_KEY, action)
|
|
311
|
-
if (reason) {
|
|
312
|
-
span.setTag(TAGS.REASON_TAG_KEY, reason)
|
|
313
|
-
}
|
|
314
|
-
if (shouldBlock) {
|
|
315
|
-
span.setTag(TAGS.BLOCKED_TAG_KEY, 'true')
|
|
316
|
-
throw new AIGuardAbortError(reason, tags, tagProbabilities, sdsFindings)
|
|
53
|
+
|
|
54
|
+
const outcome = createEvaluationOutcome(evaluation, block)
|
|
55
|
+
this.#reporter.finish(report, outcome)
|
|
56
|
+
|
|
57
|
+
if (outcome.shouldBlock) {
|
|
58
|
+
const { reason, tags, tagProbabilities, sds } = outcome.result
|
|
59
|
+
throw new AIGuardAbortError(reason, tags, tagProbabilities, sds)
|
|
317
60
|
}
|
|
318
|
-
|
|
61
|
+
|
|
62
|
+
return outcome.result
|
|
319
63
|
})
|
|
320
64
|
}
|
|
321
65
|
}
|
|
@@ -97,15 +97,14 @@ function getPrepareStackTraceAccessor () {
|
|
|
97
97
|
|
|
98
98
|
function getCompileMethodFn (compileMethod) {
|
|
99
99
|
let delegate = function (content, filename) {
|
|
100
|
+
if (isDdTrace(filename) || !isPrivateModule(filename) || !config.iast?.enabled) {
|
|
101
|
+
return compileMethod.apply(this, [content, filename])
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// TODO when we have CJS support for orchestrion and taint-tracking, add
|
|
105
|
+
// them here as appropriate
|
|
106
|
+
let rewrittenContent
|
|
100
107
|
try {
|
|
101
|
-
if (isDdTrace(filename)) {
|
|
102
|
-
return compileMethod.apply(this, [content, filename])
|
|
103
|
-
}
|
|
104
|
-
if (!isPrivateModule(filename) || !config.iast?.enabled) {
|
|
105
|
-
return compileMethod.apply(this, [content, filename])
|
|
106
|
-
}
|
|
107
|
-
// TODO when we have CJS support for orchestrion and taint-tracking, add
|
|
108
|
-
// them here as appropriate
|
|
109
108
|
const rewritten = rewriter.rewrite(content, filename, ['iast'])
|
|
110
109
|
|
|
111
110
|
incrementTelemetryIfNeeded(rewritten.metrics)
|
|
@@ -114,13 +113,11 @@ function getCompileMethodFn (compileMethod) {
|
|
|
114
113
|
hardcodedSecretCh.publish(rewritten.literalsResult)
|
|
115
114
|
}
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
return compileMethod.apply(this, [rewritten.content, filename])
|
|
119
|
-
}
|
|
116
|
+
rewrittenContent = rewritten?.content
|
|
120
117
|
} catch (e) {
|
|
121
118
|
log.error('Error rewriting file %s', filename, e)
|
|
122
119
|
}
|
|
123
|
-
return compileMethod.apply(this, [content, filename])
|
|
120
|
+
return compileMethod.apply(this, [rewrittenContent || content, filename])
|
|
124
121
|
}
|
|
125
122
|
|
|
126
123
|
const shim = function (...args) {
|
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
incrementWafUpdatesMetric,
|
|
16
16
|
incrementWafConfigErrorsMetric,
|
|
17
17
|
incrementWafRequestsMetric,
|
|
18
|
+
incrementRequestDurationMetrics,
|
|
18
19
|
updateWafRequestsMetricTags,
|
|
19
20
|
updateRaspRequestsMetricTags,
|
|
20
21
|
updateRaspRuleSkippedMetricTags,
|
|
@@ -608,6 +609,7 @@ function finishRequest (req, res, storedResponseHeaders, requestBody, rootSpan)
|
|
|
608
609
|
|
|
609
610
|
if (!req) return
|
|
610
611
|
|
|
612
|
+
incrementRequestDurationMetrics(req)
|
|
611
613
|
incrementWafRequestsMetric(req)
|
|
612
614
|
|
|
613
615
|
const tags = rootSpan.context().getTags()
|
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
trackRaspMetrics,
|
|
13
13
|
trackRaspRuleMatch,
|
|
14
14
|
trackRaspRuleSkipped,
|
|
15
|
+
incrementRaspDurationMetrics,
|
|
15
16
|
} = require('./rasp')
|
|
16
17
|
const {
|
|
17
18
|
addWafRequestMetrics,
|
|
@@ -20,6 +21,7 @@ const {
|
|
|
20
21
|
incrementWafUpdates,
|
|
21
22
|
incrementWafConfigErrors,
|
|
22
23
|
incrementWafRequests,
|
|
24
|
+
incrementWafDurationMetrics,
|
|
23
25
|
} = require('./waf')
|
|
24
26
|
|
|
25
27
|
const metricsStoreMap = new WeakMap()
|
|
@@ -142,6 +144,16 @@ function incrementWafRequestsMetric (req) {
|
|
|
142
144
|
metricsStoreMap.delete(req)
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
function incrementRequestDurationMetrics (req) {
|
|
148
|
+
if (!req || !enabled) return
|
|
149
|
+
|
|
150
|
+
const store = getStore(req)
|
|
151
|
+
const requestMetrics = store[DD_TELEMETRY_REQUEST_METRICS]
|
|
152
|
+
|
|
153
|
+
incrementWafDurationMetrics(requestMetrics)
|
|
154
|
+
incrementRaspDurationMetrics(requestMetrics)
|
|
155
|
+
}
|
|
156
|
+
|
|
145
157
|
function incrementMissingUserLoginMetric (framework, eventType) {
|
|
146
158
|
if (!enabled) return
|
|
147
159
|
|
|
@@ -199,6 +211,7 @@ module.exports = {
|
|
|
199
211
|
incrementWafUpdatesMetric,
|
|
200
212
|
incrementWafConfigErrorsMetric,
|
|
201
213
|
incrementWafRequestsMetric,
|
|
214
|
+
incrementRequestDurationMetrics,
|
|
202
215
|
incrementMissingUserLoginMetric,
|
|
203
216
|
incrementMissingUserIdMetric,
|
|
204
217
|
incrementSdkEventMetric,
|
|
@@ -77,6 +77,21 @@ function trackRaspRuleMatch (store, raspRule, blockTriggered, blocked) {
|
|
|
77
77
|
appsecMetrics.count('rasp.rule.match', tags).inc(1)
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
function incrementRaspDurationMetrics (requestMetrics) {
|
|
81
|
+
const { raspDuration, raspDurationExt, wafVersion, rulesVersion } = requestMetrics
|
|
82
|
+
if (!raspDuration && !raspDurationExt) return
|
|
83
|
+
|
|
84
|
+
const versionsTags = getVersionsTags(wafVersion, rulesVersion)
|
|
85
|
+
|
|
86
|
+
if (raspDuration) {
|
|
87
|
+
appsecMetrics.distribution('rasp.duration', versionsTags).track(raspDuration)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (raspDurationExt) {
|
|
91
|
+
appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(raspDurationExt)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
80
95
|
function trackRaspRuleSkipped (raspRule, reason) {
|
|
81
96
|
const tags = { reason, rule_type: raspRule.type }
|
|
82
97
|
|
|
@@ -100,4 +115,5 @@ module.exports = {
|
|
|
100
115
|
trackRaspMetrics,
|
|
101
116
|
trackRaspRuleMatch,
|
|
102
117
|
trackRaspRuleSkipped,
|
|
118
|
+
incrementRaspDurationMetrics,
|
|
103
119
|
}
|
|
@@ -34,6 +34,14 @@ function addWafRequestMetrics (store, { duration, durationExt, wafTimeout, error
|
|
|
34
34
|
function trackWafMetrics (store, metrics) {
|
|
35
35
|
const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion)
|
|
36
36
|
|
|
37
|
+
const requestMetrics = store[DD_TELEMETRY_REQUEST_METRICS]
|
|
38
|
+
if (metrics.wafVersion) {
|
|
39
|
+
requestMetrics.wafVersion = metrics.wafVersion
|
|
40
|
+
}
|
|
41
|
+
if (metrics.rulesVersion) {
|
|
42
|
+
requestMetrics.rulesVersion = metrics.rulesVersion
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
const metricTags = getOrCreateMetricTags(store, versionsTags)
|
|
38
46
|
|
|
39
47
|
if (metrics.blockFailed) {
|
|
@@ -118,6 +126,21 @@ function incrementWafRequests (store) {
|
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
|
|
129
|
+
function incrementWafDurationMetrics (requestMetrics) {
|
|
130
|
+
const { duration, durationExt, wafVersion, rulesVersion } = requestMetrics
|
|
131
|
+
if (!duration && !durationExt) return
|
|
132
|
+
|
|
133
|
+
const versionsTags = getVersionsTags(wafVersion, rulesVersion)
|
|
134
|
+
|
|
135
|
+
if (duration) {
|
|
136
|
+
appsecMetrics.distribution('waf.duration', versionsTags).track(duration)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (durationExt) {
|
|
140
|
+
appsecMetrics.distribution('waf.duration_ext', versionsTags).track(durationExt)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
121
144
|
function incrementTruncatedMetrics (metrics, truncationReason) {
|
|
122
145
|
const truncationTags = { truncation_reason: truncationReason }
|
|
123
146
|
appsecMetrics.count('waf.input_truncated', truncationTags).inc(1)
|
|
@@ -140,4 +163,5 @@ module.exports = {
|
|
|
140
163
|
incrementWafUpdates,
|
|
141
164
|
incrementWafConfigErrors,
|
|
142
165
|
incrementWafRequests,
|
|
166
|
+
incrementWafDurationMetrics,
|
|
143
167
|
}
|