8000 Create metric: appsec.rasp.rule.skipped by jandro996 · Pull Request #8618 · DataDog/dd-trace-java · GitHub
[go: up one dir, main page]

Skip to content

Create metric: appsec.rasp.rule.skipped #8618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add appsec.rasp.rule.skipped RASP Metric
  • Loading branch information
jandro996 committed Mar 25, 2025
commit 78d28d69cf9890ecfe00bbfe04e58b72a9e3b1b8
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public class AppSecRequestContext implements DataBundle, Closeable {
private volatile int raspInternalErrors;
private volatile int raspInvalidObjectErrors;
private volatile int raspInvalidArgumentErrors;
private volatile int raspRuleSkipped;
private volatile int wafInternalErrors;
private volatile int wafInvalidObjectErrors;
private volatile int wafInvalidArgumentErrors;
Expand Down Expand Up @@ -159,6 +160,8 @@ public class AppSecRequestContext implements DataBundle, Closeable {
RASP_INVALID_ARGUMENT_ERRORS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(
AppSecRequestContext.class, "raspInvalidArgumentErrors");
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> RASP_RULE_SKIPPED_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "raspRuleSkipped");

private static final AtomicIntegerFieldUpdater<AppSecRequestContext> WAF_INTERNAL_ERRORS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "wafInternalErrors");
Expand Down Expand Up @@ -220,6 +223,10 @@ public void increaseRaspTimeouts() {
RASP_TIMEOUTS_UPDATER.incrementAndGet(this);
}

public void increaseRuleSkipped() {
RASP_RULE_SKIPPED_UPDATER.incrementAndGet(this);
}

public void increaseRaspErrorCode(int code) {
switch (code) {
case DD_WAF_RUN_INTERNAL_ERROR:
Expand Down Expand Up @@ -260,6 +267,10 @@ public int getRaspTimeouts() {
return raspTimeouts;
}

public int getRaspRuleSkipped() {
return raspRuleSkipped;
}

public int getRaspError(int code) {
switch (code) {
case DD_WAF_RUN_INTERNAL_ERROR:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ public void onDataAvailable(

if (reqCtx.isAdditiveClosed()) {
log.debug("Skipped; the WAF context is closed");
if (gwCtx.isRasp) {
WafMetricCollector.get().raspRuleSkipped(gwCtx.raspRuleType);
}
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import io.sqreen.powerwaf.Additive
import io.sqreen.powerwaf.Powerwaf
import io.sqreen.powerwaf.PowerwafContext

class AppSecRequestContextSpecification extends DDSpecification {
class AppSecRequestContextSpecification extends DDSpecification {

AppSecRequestContext ctx = new AppSecRequestContext()

Expand Down Expand Up @@ -319,6 +319,15 @@ class AppSecRequestContextSpecification extends DDSpecification {
ctx.getWafError(0) == 0
}

def "test increase and get raspRuleSkipped"() {
when:
ctx.increaseRuleSkipped()
ctx.increaseRuleSkipped()

then:
ctx.getRaspRuleSkipped() == 2
}

void 'close logs if request end was not called'() {
given:
TestLogCollector.enable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1731,6 +1731,30 @@ class PowerWAFModuleSpecification extends DDSpecification {
0 * _
}

void 'raspRuleSkipped if rasp available and WAF context is closed'() {
setup:
ChangeableFlow flow = Mock()
GatewayContext gwCtxMock = new GatewayContext(false, RuleType.SQL_INJECTION)

when:
setupWithStubConfigService('rules_with_data_config.json')
dataListener = pwafModule.dataSubscriptions.first()

def bundle = MapDataBundle.of(
KnownAddresses.USER_ID,
'legit-user'
8000 )
ctx.closeAdditive()
dataListener.onDataAvailable(flow, ctx, bundle, gwCtxMock)

then:
1 * ctx.closeAdditive()
1 * ctx.isAdditiveClosed() >> true
1 * wafMetricCollector.wafInit(Powerwaf.LIB_VERSION, _, true)
1 * wafMetricCollector.raspRuleSkipped(RuleType.SQL_INJECTION)
0 * _
}

private Map<String, Object> getDefaultConfig() {
def service = new StubAppSecConfigService()
service.init()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ private WafMetricCollector() {
new AtomicLongArray(WafTruncatedType.values().length);
private static final AtomicLongArray raspRuleEvalCounter =
new AtomicLongArray(RuleType.getNumValues());
private static final AtomicLongArray raspRuleSkippedCounter =
new AtomicLongArray(RuleType.getNumValues());
private static final AtomicLongArray raspRuleMatchCounter =
new AtomicLongArray(RuleType.getNumValues());
private static final AtomicLongArray raspTimeoutCounter =
Expand Down Expand Up @@ -135,6 +137,10 @@ public void raspRuleEval(final RuleType ruleType) {
raspRuleEvalCounter.incrementAndGet(ruleType.ordinal());
}

public void raspRuleSkipped(final RuleType ruleType) {
raspRuleSkippedCounter.incrementAndGet(ruleType.ordinal());
}

public void raspRuleMatch(final RuleType ruleType) {
raspRuleMatchCounter.incrementAndGet(ruleType.ordinal());
}
Expand Down Expand Up @@ -347,6 +353,16 @@ public void prepareMetrics() {
}
}
}

// RASP rule skipped per rule type for after-request reason
for (RuleType ruleType : RuleType.values()) {
long counter = raspRuleSkippedCounter.getAndSet(ruleType.ordinal(), 0);
if (counter > 0) {
if (!rawMetricsQueue.offer(new AfterRequestRaspRuleSkipped(counter, ruleType))) {
return;
}
}
}
}

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

// Although rasp.rule.skipped reason could be before-request, there is no real case scenario
public static class AfterRequestRaspRuleSkipped extends WafMetric {
public AfterRequestRaspRuleSkipped(final long counter, final RuleType ruleType) {
super(
"rasp.rule.skipped",
counter,
ruleType.variant != null
? new String[] {
"rule_type:" + ruleType.type,
"rule_variant:" + ruleType.variant,
"reason:" + "after-request"
}
: new String[] {"rule_type:" + ruleType.type, "reason:" + "after-request"});
}
}

public static class RaspRuleMatch extends WafMetric {
public RaspRuleMatch(final long counter, final RuleType ruleType, final String wafVersion) {
super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class WafMetricCollectorTest extends DDSpecification {
WafMetricCollector.get().wafErrorCode(RuleType.SHELL_INJECTION, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().raspErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
WafMetricCollector.get().wafErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
WafMetricCollector.get().raspRuleSkipped(RuleType.SQL_INJECTION)

WafMetricCollector.get().prepareMetrics()

Expand Down Expand Up @@ -224,6 +225,13 @@ class WafMetricCollectorTest extends DDSpecification {
'waf_version:waf_ver1',
'waf_error:'+DD_WAF_RUN_INVA BBC2 LID_OBJECT_ERROR
].toSet()

def raspRuleSkipped = (WafMetricCollector.AfterRequestRaspRuleSkipped)metrics[15]
raspRuleSkipped.type == 'count'
raspRuleSkipped.value == 1
raspRuleSkipped.namespace == 'appsec'
raspRuleSkipped.metricName == 'rasp.rule.skipped'
raspRuleSkipped.tags.toSet() == ['rule_type:sql_injection', 'reason:after-request',].toSet()
}

def "overflowing WafMetricCollector does not crash"() {
Expand Down Expand Up @@ -399,6 +407,7 @@ class WafMetricCollectorTest extends DDSpecification {
WafMetricCollector.get().raspTimeout(ruleType)
WafMetricCollector.get().raspErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().wafErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().raspRuleSkipped(ruleType)
WafMetricCollector.get().prepareMetrics()

then:
Expand Down Expand Up @@ -466,6 +475,17 @@ class WafMetricCollectorTest extends DDSpecification {
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
].toSet()

def raspRuleSkipped = (WafMetricCollector.AfterRequestRaspRuleSkipped)metrics[6]
raspRuleSkipped.type == 'count'
raspRuleSkipped.value == 1
raspRuleSkipped.namespace == 'appsec'
raspRuleSkipped.metricName == 'rasp.rule.skipped'
raspRuleSkipped.tags.toSet() == [
'rule_type:command_injection',
'rule_variant:'+ruleType.variant,
'reason:after-request',
].toSet()

where:
ruleType << [RuleType.COMMAND_INJECTION, RuleType.SHELL_INJECTION]
}
Expand Down
Loading
0