8000 Create metric: appsec.rasp.rule.skipped (#8618) · DataDog/dd-trace-java@a7d732d · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit a7d732d

Browse files
authored
Create metric: appsec.rasp.rule.skipped (#8618)
What Does This Do Crate the appsec.rasp.rule.skipped metric that counts the number of times that waf call is skipped due to the WAF context is closed Additional Notes Although the metric reason tag supports after-request and before-request only the first one is implemented, as there are no use cases in java tracer for the before-request
1 parent 05ccd9a commit a7d732d

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ public void onDataAvailable(
417417

418418
if (reqCtx.isAdditiveClosed()) {
419419
log.debug("Skipped; the WAF context is closed");
4 8000 20+
if (gwCtx.isRasp) {
421+
WafMetricCollector.get().raspRuleSkipped(gwCtx.raspRuleType);
422+
}
420423
return;
421424
}
422425

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFModuleSpecification.groovy

Lines changed: 24 additions & 0 deletions
10000
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,30 @@ class PowerWAFModuleSpecification extends DDSpecification {
17311731
0 * _
17321732
}
17331733

1734+
void 'raspRuleSkipped if rasp available and WAF context is closed'() {
1735+
setup:
1736+
ChangeableFlow flow = Mock()
1737+
GatewayContext gwCtxMock = new GatewayContext(false, RuleType.SQL_INJECTION)
1738+
1739+
when:
1740+
setupWithStubConfigService('rules_with_data_config.json')
1741+
dataListener = pwafModule.dataSubscriptions.first()
1742+
1743+
def bundle = MapDataBundle.of(
1744+
KnownAddresses.USER_ID,
1745+
'legit-user'
1746+
)
1747+
ctx.closeAdditive()
1748+
dataListener.onDataAvailable(flow, ctx, bundle, gwCtxMock)
1749+
1750+
then:
1751+
1 * ctx.closeAdditive()
1752+
1 * ctx.isAdditiveClosed() >> true
1753+
1 * wafMetricCollector.wafInit(Powerwaf.LIB_VERSION, _, true)
1754+
1 * wafMetricCollector.raspRuleSkipped(RuleType.SQL_INJECTION)
1755+
0 * _
1756+
}
1757+
17341758
private Map<String, Object> getDefaultConfig() {
17351759
def service = new StubAppSecConfigService()
17361760
service.init()

internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ private WafMetricCollector() {
4747
new AtomicLongArray(WafTruncatedType.values().length);
4848
private static final AtomicLongArray raspRuleEvalCounter =
4949
new AtomicLongArray(RuleType.getNumValues());
50+
private static final AtomicLongArray raspRuleSkippedCounter =
51+
new AtomicLongArray(RuleType.getNumValues());
5052
private static final AtomicLongArray raspRuleMatchCounter =
5153
new AtomicLongArray(RuleType.getNumValues());
5254
private static final AtomicLongArray raspTimeoutCounter =
@@ -135,6 +137,10 @@ public void raspRuleEval(final RuleType ruleType) {
135137
raspRuleEvalCounter.incrementAndGet(ruleType.ordinal());
136138
}
137139

140+
public void raspRuleSkipped(final RuleType ruleType) {
141+
raspRuleSkippedCounter.incrementAndGet(ruleType.ordinal());
142+
}
143+
138144
public void raspRuleMatch(final RuleType ruleType) {
139145
raspRuleMatchCounter.incrementAndGet(ruleType.ordinal());
140146
}
@@ -347,6 +353,16 @@ public void prepareMetrics() {
347353
}
348354
}
349355
}
356+
357+
// RASP rule skipped per rule type for after-request reason
358+
for (RuleType ruleType : RuleType.values()) {
359+
long counter = raspRuleSkippedCounter.getAndSet(ruleType.ordinal(), 0);
360+
if (counter > 0) {
361+
if (!rawMetricsQueue.offer(new AfterRequestRaspRuleSkipped(counter, ruleType))) {
362+
return;
363+
}
364+
}
365+
}
350366
}
351367

352368
public abstract static class WafMetric extends MetricCollector.Metric {
@@ -451,6 +467,22 @@ public RaspRuleEval(final long counter, final RuleType ruleType, final String wa
451467
}
452468
}
453469

470+
// Although rasp.rule.skipped reason could be before-request, there is no real case scenario
471+
public static class AfterRequestRaspRuleSkipped extends WafMetric {
472+
public AfterRequestRaspRuleSkipped(final long counter, final RuleType ruleType) {
473+
super(
474+
"rasp.rule.skipped",
475+
counter,
476+
ruleType.variant != null
477+
? new String[] {
478+
"rule_type:" + ruleType.type,
479+
"rule_variant:" + ruleType.variant,
480+
"reason:" + "after-request"
481+
}
482+
: new String[] {"rule_type:" + ruleType.type, "reason:" + "after-request"});
483+
}
484+
}
485+
454486
public static class RaspRuleMatch extends WafMetric {
455487
public RaspRuleMatch(final long counter, final RuleType ruleType, final String wafVersion) {
456488
super(

internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class WafMetricCollectorTest extends DDSpecification {
4343
WafMetricCollector.get().wafErrorCode(RuleType.SHELL_INJECTION, DD_WAF_RUN_INTERNAL_ERROR)
4444
WafMetricCollector.get().raspErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
4545
WafMetricCollector.get().wafErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
46+
WafMetricCollector.get().raspRuleSkipped(RuleType.SQL_INJECTION)
4647

4748
WafMetricCollector.get().prepareMetrics()
4849

@@ -224,6 +225,13 @@ class WafMetricCollectorTest extends DDSpecification {
224225
'waf_version:waf_ver1',
225226
'waf_error:'+DD_WAF_RUN_INVALID_OBJECT_ERROR
226227
].toSet()
228+
229+
def raspRuleSkipped = (WafMetricCollector.AfterRequestRaspRuleSkipped)metrics[15]
230+
raspRuleSkipped.type == 'count'
231+
raspRuleSkipped.value == 1
232+
raspRuleSkipped.namespace == 'appsec'
233+
raspRuleSkipped.metricName == 'rasp.rule.skipped'
234+
raspRuleSkipped.tags.toSet() == ['rule_type:sql_injection', 'reason:after-request',].toSet()
227235
}
228236

229237
def "overflowing WafMetricCollector does not crash"() {
@@ -399,6 +407,7 @@ class WafMetricCollectorTest extends DDSpecification {
399407
WafMetricCollector.get().raspTimeout(ruleType)
400408
WafMetricCollector.get().raspErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
401409
WafMetricCollector.get().wafErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
410+
WafMetricCollector.get().raspRuleSkipped(ruleType)
402411
WafMetricCollector.get().prepareMetrics()
403412

404413
then:
@@ -466,6 +475,17 @@ class WafMetricCollectorTest extends DDSpecification {
466475
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
467476
].toSet()
468477

478+
def raspRuleSkipped = (WafMetricCollector.AfterRequestRaspRuleSkipped)metrics[6]
479+
raspRuleSkipped.type == 'count'
480+
raspRuleSkipped.value == 1
481+
raspRuleSkipped.namespace == 'appsec'
482+
raspRuleSkipped.metricName == 'rasp.rule.skipped'
483+
raspRuleSkipped.tags.toSet() == [
484+
'rule_type:command_injection',
485+
'rule_variant:'+ruleType.variant,
486+
'reason:after-request',
487+
].toSet()
488+
469489
where:
470490
ruleType << [RuleType.COMMAND_INJECTION, RuleType.SHELL_INJECTION]
471491
}

0 commit comments

Comments
 (0)
0