Skip to content

Commit b7b187b

Browse files
authored
Merge branch 'master' into szegedi/update-profiler
2 parents 6d913f5 + 010910f commit b7b187b

File tree

7 files changed

+277
-13
lines changed

7 files changed

+277
-13
lines changed

integration-tests/opentelemetry.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ describe('opentelemetry', () => {
6060
'@opentelemetry/api@1.8.0',
6161
'@opentelemetry/instrumentation',
6262
'@opentelemetry/instrumentation-http',
63-
'@opentelemetry/instrumentation-express',
63+
'@opentelemetry/instrumentation-express@0.47.1',
6464
'express'
6565
]
6666
if (satisfies(process.version.slice(1), '>=14')) {

packages/dd-trace/src/appsec/telemetry/common.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ const tags = {
77
RULE_TRIGGERED: 'rule_triggered',
88
WAF_TIMEOUT: 'waf_timeout',
99
WAF_VERSION: 'waf_version',
10-
EVENT_RULES_VERSION: 'event_rules_version'
10+
EVENT_RULES_VERSION: 'event_rules_version',
11+
INPUT_TRUNCATED: 'input_truncated'
1112
}
1213

1314
function getVersionsTags (wafVersion, rulesVersion) {

packages/dd-trace/src/appsec/telemetry/waf.js

+46
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
77

88
const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags')
99

10+
const TRUNCATION_FLAGS = {
11+
STRING: 1,
12+
CONTAINER_SIZE: 2,
13+
CONTAINER_DEPTH: 4
14+
}
15+
1016
function addWafRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) {
1117
store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0
1218
store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0
@@ -58,6 +64,12 @@ function trackWafMetrics (store, metrics) {
5864
metricTags[tags.WAF_TIMEOUT] = true
5965
}
6066

67+
const truncationReason = getTruncationReason(metrics)
68+
if (truncationReason > 0) {
69+
metricTags[tags.INPUT_TRUNCATED] = true
70+
incrementTruncatedMetrics(metrics, truncationReason)
71+
}
72+
6173
return metricTags
6274
}
6375

@@ -69,6 +81,7 @@ function getOrCreateMetricTags (store, versionsTags) {
6981
[tags.REQUEST_BLOCKED]: false,
7082
[tags.RULE_TRIGGERED]: false,
7183
[tags.WAF_TIMEOUT]: false,
84+
[tags.INPUT_TRUNCATED]: false,
7285

7386
...versionsTags
7487
}
@@ -98,6 +111,39 @@ function incrementWafRequests (store) {
98111
}
99112
}
100113

114+
function incrementTruncatedMetrics (metrics, truncationReason) {
115+
const truncationTags = { truncation_reason: truncationReason }
116+
appsecMetrics.count('waf.input_truncated', truncationTags).inc(1)
117+
118+
if (metrics?.maxTruncatedString) {
119+
appsecMetrics.distribution('waf.truncated_value_size', {
120+
truncation_reason: TRUNCATION_FLAGS.STRING
121+
}).track(metrics.maxTruncatedString)
122+
}
123+
124+
if (metrics?.maxTruncatedContainerSize) {
125+
appsecMetrics.distribution('waf.truncated_value_size', {
126+
truncation_reason: TRUNCATION_FLAGS.CONTAINER_SIZE
127+
}).track(metrics.maxTruncatedContainerSize)
128+
}
129+
130+
if (metrics?.maxTruncatedContainerDepth) {
131+
appsecMetrics.distribution('waf.truncated_value_size', {
132+
truncation_reason: TRUNCATION_FLAGS.CONTAINER_DEPTH
133+
}).track(metrics.maxTruncatedContainerDepth)
134+
}
135+
}
136+
137+
function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) {
138+
let reason = 0
139+
140+
if (maxTruncatedString) reason |= TRUNCATION_FLAGS.STRING
141+
if (maxTruncatedContainerSize) reason |= TRUNCATION_FLAGS.CONTAINER_SIZE
142+
if (maxTruncatedContainerDepth) reason |= TRUNCATION_FLAGS.CONTAINER_DEPTH
143+
144+
return reason
145+
}
146+
101147
module.exports = {
102148
addWafRequestMetrics,
103149
trackWafMetrics,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict'
2+
3+
const tracer = require('dd-trace')
4+
tracer.init({
5+
flushInterval: 1
6+
})
7+
8+
const express = require('express')
9+
const body = require('body-parser')
10+
11+
const app = express()
12+
app.use(body.json())
13+
const port = process.env.APP_PORT || 3000
14+
15+
app.post('/', async (req, res) => {
16+
res.end('OK')
17+
})
18+
19+
app.listen(port, () => {
20+
process.send({ port })
21+
})

packages/dd-trace/test/appsec/telemetry/rasp.spec.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ describe('Appsec Rasp Telemetry metrics', () => {
129129
blockTriggered: true,
130130
ruleTriggered: true,
131131
wafTimeout: true,
132+
input_truncated: true,
132133
wafVersion,
133134
rulesVersion
134135
}, req, { type: 'rule-type' })
@@ -141,7 +142,8 @@ describe('Appsec Rasp Telemetry metrics', () => {
141142
rule_triggered: false,
142143
waf_timeout: false,
143144
waf_version: wafVersion,
144-
event_rules_version: rulesVersion
145+
event_rules_version: rulesVersion,
146+
input_truncated: false
145147
})
146148
})
147149
})

packages/dd-trace/test/appsec/telemetry/waf.spec.js

+74-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ describe('Appsec Waf Telemetry metrics', () => {
3030
afterEach(sinon.restore)
3131

3232
describe('if enabled', () => {
33+
const metrics = {
34+
wafVersion,
35+
rulesVersion
36+
}
37+
3338
beforeEach(() => {
3439
appsecTelemetry.enable({
3540
enabled: true,
@@ -38,11 +43,6 @@ describe('Appsec Waf Telemetry metrics', () => {
3843
})
3944

4045
describe('updateWafRequestsMetricTags', () => {
41-
const metrics = {
42-
wafVersion,
43-
rulesVersion
44-
}
45-
4646
it('should skip update if no request is provided', () => {
4747
const result = appsecTelemetry.updateWafRequestsMetricTags(metrics)
4848

@@ -57,7 +57,8 @@ describe('Appsec Waf Telemetry metrics', () => {
5757
event_rules_version: rulesVersion,
5858
request_blocked: false,
5959
rule_triggered: false,
60-
waf_timeout: false
60+
waf_timeout: false,
61+
input_truncated: false
6162
})
6263
})
6364

@@ -66,6 +67,7 @@ describe('Appsec Waf Telemetry metrics', () => {
6667
blockTriggered: true,
6768
ruleTriggered: true,
6869
wafTimeout: true,
70+
maxTruncatedString: 5000,
6971
...metrics
7072
}, req)
7173

@@ -74,7 +76,8 @@ describe('Appsec Waf Telemetry metrics', () => {
7476
event_rules_version: rulesVersion,
7577
request_blocked: true,
7678
rule_triggered: true,
77-
waf_timeout: true
79+
waf_timeout: true,
80+
input_truncated: true
7881
})
7982
})
8083

@@ -93,7 +96,8 @@ describe('Appsec Waf Telemetry metrics', () => {
9396
event_rules_version: rulesVersion,
9497
request_blocked: false,
9598
rule_triggered: true,
96-
waf_timeout: false
99+
waf_timeout: false,
100+
input_truncated: false
97101
})
98102
})
99103

@@ -102,6 +106,7 @@ describe('Appsec Waf Telemetry metrics', () => {
102106
blockTriggered: true,
103107
ruleTriggered: true,
104108
wafTimeout: true,
109+
maxTruncatedContainerSize: 300,
105110
...metrics
106111
}, req)
107112

@@ -120,7 +125,8 @@ describe('Appsec Waf Telemetry metrics', () => {
120125
event_rules_version: rulesVersion,
121126
request_blocked: true,
122127
rule_triggered: true,
123-
waf_timeout: true
128+
waf_timeout: true,
129+
input_truncated: true
124130
})
125131
})
126132

@@ -250,7 +256,8 @@ describe('Appsec Waf Telemetry metrics', () => {
250256
rule_triggered: false,
251257
waf_timeout: true,
252258
waf_version: wafVersion,
253-
event_rules_version: rulesVersion
259+
event_rules_version: rulesVersion,
260+
input_truncated: false
254261
})
255262
})
256263

@@ -260,6 +267,63 @@ describe('Appsec Waf Telemetry metrics', () => {
260267
expect(count).to.not.have.been.called
261268
})
262269
})
270+
271+
describe('WAF Truncation metrics', () => {
272+
it('should report truncated string metrics', () => {
273+
const result = appsecTelemetry.updateWafRequestsMetricTags({ maxTruncatedString: 5000 }, req)
274+
expect(result).to.have.property('input_truncated', true)
275+
276+
expect(count).to.have.been.calledWith('waf.input_truncated', { truncation_reason: 1 })
277+
expect(inc).to.have.been.calledWith(1)
278+
279+
expect(distribution).to.have.been.calledWith('waf.truncated_value_size', { truncation_reason: 1 })
280+
expect(track).to.have.been.calledWith(5000)
281+
})
282+
283+
it('should report truncated container size metrics', () => {
284+
const result = appsecTelemetry.updateWafRequestsMetricTags({ maxTruncatedContainerSize: 300 }, req)
285+
expect(result).to.have.property('input_truncated', true)
286+
287+
expect(count).to.have.been.calledWith('waf.input_truncated', { truncation_reason: 2 })
288+
expect(inc).to.have.been.calledWith(1)
289+
290+
expect(distribution).to.have.been.calledWith('waf.truncated_value_size', { truncation_reason: 2 })
291+
expect(track).to.have.been.calledWith(300)
292+
})
293+
294+
it('should report truncated container depth metrics', () => {
295+
const result = appsecTelemetry.updateWafRequestsMetricTags({ maxTruncatedContainerDepth: 20 }, req)
296+
expect(result).to.have.property('input_truncated', true)
297+
298+
expect(count).to.have.been.calledWith('waf.input_truncated', { truncation_reason: 4 })
299+
expect(inc).to.have.been.calledWith(1)
300+
301+
expect(distribution).to.have.been.calledWith('waf.truncated_value_size', { truncation_reason: 4 })
302+
expect(track).to.have.been.calledWith(20)
303+
})
304+
305+
it('should combine truncation reasons when multiple truncations occur', () => {
306+
const result = appsecTelemetry.updateWafRequestsMetricTags({
307+
maxTruncatedString: 5000,
308+
maxTruncatedContainerSize: 300,
309+
maxTruncatedContainerDepth: 20
310+
}, req)
311+
expect(result).to.have.property('input_truncated', true)
312+
313+
expect(count).to.have.been.calledWith('waf.input_truncated', { truncation_reason: 7 })
314+
expect(distribution).to.have.been.calledWith('waf.truncated_value_size', { truncation_reason: 1 })
315+
expect(distribution).to.have.been.calledWith('waf.truncated_value_size', { truncation_reason: 2 })
316+
expect(distribution).to.have.been.calledWith('waf.truncated_value_size', { truncation_reason: 4 })
317+
})
318+
319+
it('should not report truncation metrics when no truncation occurs', () => {
320+
const result = appsecTelemetry.updateWafRequestsMetricTags(metrics, req)
321+
expect(result).to.have.property('input_truncated', false)
322+
323+
expect(count).to.not.have.been.calledWith('waf.input_truncated')
324+
expect(distribution).to.not.have.been.calledWith('waf.truncated_value_size')
325+
})
326+
})
263327
})
264328

265329
describe('if disabled', () => {

0 commit comments

Comments
 (0)