From 4c9d8416f33ec20ad84e639622f68a6fd7fee2db Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 2 Sep 2025 14:42:19 +0200 Subject: [PATCH 01/13] Waf upgrade to 1.28.0 Signed-off-by: sezen.leblay --- dd-java-agent/appsec/build.gradle | 2 +- .../config/AppSecConfigServiceImpl.java | 31 +--- .../com/datadog/appsec/ddwaf/WAFModule.java | 21 +-- .../appsec/gateway/AppSecRequestContext.java | 19 +- .../datadog/appsec/gateway/GatewayBridge.java | 11 +- ...SecConfigServiceImplJsonAdapterTest.groovy | 86 --------- .../ddwaf/WAFModuleSpecification.groovy | 167 ++++++++++++++---- .../appsec/TraceTaggingSmokeTest.groovy | 69 ++++++++ .../java/datadog/trace/api/gateway/Flow.java | 4 +- 9 files changed, 232 insertions(+), 178 deletions(-) delete mode 100644 dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplJsonAdapterTest.groovy diff --git a/dd-java-agent/appsec/build.gradle b/dd-java-agent/appsec/build.gradle index 84242bd8756..eb0157ec3cf 100644 --- a/dd-java-agent/appsec/build.gradle +++ b/dd-java-agent/appsec/build.gradle @@ -15,7 +15,7 @@ dependencies { implementation project(':internal-api') implementation project(':communication') implementation project(':telemetry') - implementation group: 'io.sqreen', name: 'libsqreen', version: '16.0.0' + implementation group: 'io.sqreen', name: 'libsqreen', version: '17.1.0' implementation libs.moshi testImplementation libs.bytebuddy diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java index 4cdefeb85c2..c73d6e24669 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java @@ -39,9 +39,8 @@ import com.datadog.ddwaf.exception.InvalidRuleSetException; import com.datadog.ddwaf.exception.UnclassifiedWafException; import com.squareup.moshi.JsonAdapter; -import com.squareup.moshi.JsonReader; -import com.squareup.moshi.JsonWriter; import com.squareup.moshi.Moshi; +import com.squareup.moshi.Types; import datadog.remoteconfig.ConfigurationEndListener; import datadog.remoteconfig.ConfigurationPoller; import datadog.remoteconfig.PollingRateHinter; @@ -52,7 +51,6 @@ import datadog.trace.api.ConfigCollector; import datadog.trace.api.ProductActivation; import datadog.trace.api.UserIdCollectionMode; -import datadog.trace.api.telemetry.LogCollector; import datadog.trace.api.telemetry.WafMetricCollector; import java.io.ByteArrayInputStream; import java.io.FileInputStream; @@ -67,7 +65,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import javax.annotation.Nullable; import okio.Okio; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,25 +92,10 @@ public class AppSecConfigServiceImpl implements AppSecConfigService { new WAFInitializationResultReporter(); private final WAFStatsReporter statsReporter = new WAFStatsReporter(); - private static final JsonAdapter ADAPTER = + private static final JsonAdapter> ADAPTER = new Moshi.Builder() - .add( - Double.class, - new JsonAdapter() { - @Override - public Number fromJson(JsonReader reader) throws IOException { - double value = reader.nextDouble(); - long longValue = (long) value; - return value % 1 == 0 ? longValue : value; - } - - @Override - public void toJson(JsonWriter writer, @Nullable Number value) throws IOException { - throw new UnsupportedOperationException(); - } - }) .build() - .adapter(Object.class); + .adapter(Types.newParameterizedType(Map.class, String.class, Object.class)); private boolean hasUserWafConfig; private boolean defaultConfigActivated; @@ -308,7 +290,6 @@ private void handleWafUpdateResultReport(String configKey, Map r } // TODO: Send diagnostics via telemetry - final LogCollector telemetryLogger = LogCollector.get(); initReporter.setReportForPublication(wafDiagnostics); if (wafDiagnostics.rulesetVersion != null @@ -487,8 +468,7 @@ private static Map loadDefaultWafConfig() throws IOException { throw new IOException("Resource " + DEFAULT_CONFIG_LOCATION + " not found"); } - Map ret = - (Map) ADAPTER.fromJson(Okio.buffer(Okio.source(is))); + Map ret = ADAPTER.fromJson(Okio.buffer(Okio.source(is))); StandardizedLogging._initialConfigSourceAndLibddwafVersion(log, ""); if (log.isInfoEnabled()) { @@ -505,8 +485,7 @@ private static Map loadUserWafConfig(Config tracerConfig) throws return null; } try (InputStream is = new FileInputStream(filename)) { - Map ret = - (Map) ADAPTER.fromJson(Okio.buffer(Okio.source(is))); + Map ret = ADAPTER.fromJson(Okio.buffer(Okio.source(is))); StandardizedLogging._initialConfigSourceAndLibddwafVersion(log, filename); if (log.isInfoEnabled()) { diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index e1301248e67..2750cf32c73 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -34,7 +34,6 @@ import datadog.trace.api.ProductActivation; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Flow; -import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.telemetry.LogCollector; import datadog.trace.api.telemetry.WafMetricCollector; import datadog.trace.api.time.SystemTimeSource; @@ -53,7 +52,6 @@ import java.lang.reflect.UndeclaredThrowableException; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -81,8 +79,6 @@ public class WAFModule implements AppSecModule { private static final JsonAdapter> RES_JSON_ADAPTER; - private static final Map DEFAULT_ACTIONS; - private static final String EXPLOIT_DETECTED_MSG = "Exploit detected"; private boolean init = true; private String rulesetVersion; @@ -118,12 +114,6 @@ private CtxAndAddresses(Collection> addressesOfInterest, WafHandle ct Moshi moshi = new Moshi.Builder().build(); RES_JSON_ADAPTER = moshi.adapter(Types.newParameterizedType(List.class, WAFResultData.class)); - Map actionParams = new HashMap<>(); - actionParams.put("status_code", 403); - actionParams.put("type", "auto"); - actionParams.put("grpc_status_code", 10); - DEFAULT_ACTIONS = - Collections.singletonMap("block", new ActionInfo("block_request", actionParams)); createLimitsObject(); } @@ -406,6 +396,7 @@ public void onDataAvailable( boolean isThrottled = reqCtx.isThrottled(rateLimiter); if (resultWithData.keep) { + reqCtx.setManuallyKept(true); if (!isThrottled) { AgentSpan activeSpan = AgentTracer.get().activeSpan(); if (activeSpan != null) { @@ -430,20 +421,18 @@ public void onDataAvailable( } } } - if (resultWithData.events && !events.isEmpty() && !isThrottled) { - reqCtx.reportEvents(events); - } if (flow.isBlocking()) { if (!gwCtx.isRasp) { reqCtx.setWafBlocked(); } } + // report is still done even without keep, in case sampler_keep is desired + if (resultWithData.events) { + reqCtx.reportEvents(events); + } } - reqCtx.setKeepType( - resultWithData.keep ? PrioritySampling.USER_KEEP : PrioritySampling.USER_DROP); - if (resultWithData.attributes != null && !resultWithData.attributes.isEmpty()) { reqCtx.reportDerivatives(resultWithData.attributes); } diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java index 904d60318ff..da73ace3188 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java @@ -13,7 +13,6 @@ import datadog.trace.api.Config; import datadog.trace.api.http.StoredBodySupplier; import datadog.trace.api.internal.TraceSegment; -import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.util.stacktrace.StackTraceEvent; import java.io.Closeable; import java.util.*; @@ -147,12 +146,12 @@ public class AppSecRequestContext implements DataBundle, Closeable { private volatile boolean keepOpenForApiSecurityPostProcessing; private volatile Long apiSecurityEndpointHash; - private volatile byte keepType = PrioritySampling.SAMPLER_KEEP; private static final AtomicIntegerFieldUpdater WAF_TIMEOUTS_UPDATER = AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "wafTimeouts"); private static final AtomicIntegerFieldUpdater RASP_TIMEOUTS_UPDATER = AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "raspTimeouts"); + private boolean manuallyKept = false; // to be called by the Event Dispatcher public void addAll(DataBundle newData) { @@ -363,14 +362,6 @@ public Long getApiSecurityEndpointHash() { return this.apiSecurityEndpointHash; } - public void setKeepType(byte keepType) { - this.keepType = keepType; - } - - public byte getKeepType() { - return this.keepType; - } - void addRequestHeader(String name, String value) { if (finishedRequestHeaders) { throw new IllegalStateException("Request headers were said to be finished before"); @@ -948,4 +939,12 @@ public boolean isRaspMatched() { public void setRaspMatched(boolean raspMatched) { this.raspMatched = raspMatched; } + + public boolean isManuallyKept() { + return manuallyKept; + } + + public void setManuallyKept(boolean manuallyKept) { + this.manuallyKept = manuallyKept; + } } diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 76565c0e4cb..99e0270d842 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -5,7 +5,6 @@ import static com.datadog.appsec.gateway.AppSecRequestContext.DEFAULT_REQUEST_HEADERS_ALLOW_LIST; import static com.datadog.appsec.gateway.AppSecRequestContext.REQUEST_HEADERS_ALLOW_LIST; import static com.datadog.appsec.gateway.AppSecRequestContext.RESPONSE_HEADERS_ALLOW_LIST; -import static datadog.trace.bootstrap.instrumentation.api.Tags.SAMPLING_PRIORITY; import com.datadog.appsec.AppSecSystem; import com.datadog.appsec.api.security.ApiSecuritySampler; @@ -22,6 +21,7 @@ import com.datadog.appsec.report.AppSecEvent; import com.datadog.appsec.report.AppSecEventWrapper; import datadog.trace.api.Config; +import datadog.trace.api.DDTags; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Events; import datadog.trace.api.gateway.Flow; @@ -750,9 +750,12 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { // If detected any events - mark span at appsec.event if (!collectedEvents.isEmpty()) { - // Set asm keep in case that root span was not available when events are detected - traceSeg.setTagTop(Tags.ASM_KEEP, true); - traceSeg.setTagTop(SAMPLING_PRIORITY, ctx.getKeepType()); + if (ctx.isManuallyKept()) { + traceSeg.setTagTop(DDTags.MANUAL_KEEP, true); + } else { + // Set asm keep in case that root span was not available when events are detected + traceSeg.setTagTop(Tags.ASM_KEEP, true); + } traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); traceSeg.setTagTop("appsec.event", true); traceSeg.setTagTop("network.client.ip", ctx.getPeerAddress()); diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplJsonAdapterTest.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplJsonAdapterTest.groovy deleted file mode 100644 index 8d4556378a8..00000000000 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplJsonAdapterTest.groovy +++ /dev/null @@ -1,86 +0,0 @@ -package com.datadog.appsec.config - -import datadog.trace.test.util.DDSpecification -import okio.Buffer - -class AppSecConfigServiceImplJsonAdapterTest extends DDSpecification { - - void 'test JSON number conversion - whole numbers'() { - given: - def json = '42.0' - def buffer = new Buffer().writeUtf8(json) - - when: - def result = AppSecConfigServiceImpl.ADAPTER.fromJson(buffer) - - then: - result != null - // This should trigger the true branch: value % 1 == 0 ? longValue : value - } - - void 'test JSON number conversion - fractional numbers'() { - given: - def json = '42.5' - def buffer = new Buffer().writeUtf8(json) - - when: - def result = AppSecConfigServiceImpl.ADAPTER.fromJson(buffer) - - then: - result != null - // This should trigger the false branch: value % 1 == 0 ? longValue : value - } - - void 'test JSON number conversion - mixed object'() { - given: - def json = '{"whole": 100.0, "fractional": 3.14}' - def buffer = new Buffer().writeUtf8(json) - - when: - def result = AppSecConfigServiceImpl.ADAPTER.fromJson(buffer) - - then: - result != null - result instanceof Map - // This exercises both branches through the nested numbers - } - - void 'test JSON number conversion - zero'() { - given: - def json = '0.0' - def buffer = new Buffer().writeUtf8(json) - - when: - def result = AppSecConfigServiceImpl.ADAPTER.fromJson(buffer) - - then: - result != null - // This should trigger the true branch: 0.0 % 1 == 0 - } - - void 'test JSON number conversion - negative whole'() { - given: - def json = '-10.0' - def buffer = new Buffer().writeUtf8(json) - - when: - def result = AppSecConfigServiceImpl.ADAPTER.fromJson(buffer) - - then: - result != null - // This should trigger the true branch: -10.0 % 1 == 0 - } - - void 'test JSON number conversion - negative fractional'() { - given: - def json = '-3.5' - def buffer = new Buffer().writeUtf8(json) - - when: - def result = AppSecConfigServiceImpl.ADAPTER.fromJson(buffer) - - then: - result != null - // This should trigger the false branch: -3.5 % 1 != 0 - } -} diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy index 47cb2f89f8b..7589dd06a91 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy @@ -1,5 +1,6 @@ package com.datadog.appsec.ddwaf +import com.datadog.appsec.AppSecModule.AppSecModuleActivationException import com.datadog.appsec.AppSecSystem import com.datadog.appsec.config.AppSecConfigService import com.datadog.appsec.config.AppSecConfigServiceImpl @@ -150,6 +151,7 @@ class WAFModuleSpecification extends DDSpecification { listener.accept(config, json.getBytes(), null) } + void 'override on_match through reconfiguration'() { ChangeableFlow flow = Mock() @@ -206,7 +208,6 @@ class WAFModuleSpecification extends DDSpecification { rba.statusCode == 501 && rba.blockingContentType == BlockingContentType.JSON }) - 1 * ctx.setKeepType(_) 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * tracer.activeSpan() @@ -216,6 +217,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -240,7 +242,6 @@ class WAFModuleSpecification extends DDSpecification { rba.statusCode == 403 && rba.blockingContentType == BlockingContentType.AUTO }) - 1 * ctx.setKeepType(_) 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) >> { wafContext = new WafContext(it[0]) } @@ -251,6 +252,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: 'merges new waf data with the one in the rules config' @@ -285,8 +287,8 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * flow.isBlocking() - 1 * ctx.setKeepType(_) 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -310,7 +312,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * _ when: 'changes the rules config' @@ -362,7 +364,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -378,7 +380,6 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() - 1 * ctx.setKeepType(_) 0 * _ } @@ -435,7 +436,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -453,7 +454,6 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() - 1 * ctx.setKeepType(_) 0 * _ } @@ -512,8 +512,8 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * ctx.setWafBlocked() - 1 * ctx.setKeepType(_) 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -578,9 +578,9 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() - 1 * ctx.setKeepType(_) 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -602,7 +602,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) flow.blocking flow.action instanceof Flow.Action.RequestBlockingAction @@ -666,7 +666,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) flow.blocking flow.action.statusCode == 418 @@ -694,7 +694,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) metrics == null } @@ -745,8 +745,8 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(*_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.isWafContextClosed() >> false - 1 * ctx.setKeepType(_) 0 * ctx._(*_) flow.blocking } @@ -1005,10 +1005,10 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.closeWafContext() 2 * tracer.activeSpan() 1 * wafMetricCollector.wafInit(Waf.LIB_VERSION, _, true) - 1 * ctx.setKeepType(_) 0 * _ } @@ -1046,8 +1046,8 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * flow.isBlocking() - 1 * ctx.setKeepType(_) 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -1113,7 +1113,6 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1132,7 +1131,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * reconf.reloadSubscriptions() 1 * ctx.closeWafContext() 2 * ctx.getWafMetrics() - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1154,8 +1152,8 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * flow.isBlocking() - 1 * ctx.setKeepType(_) 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1173,7 +1171,6 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1202,7 +1199,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() >> { wafContext.close() } - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1225,7 +1221,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() >> { wafContext.close() } - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1253,10 +1248,10 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() >> { wafContext.close() } - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: 'removing c and a removes c and a, allows earlier toggle to take effect' @@ -1279,7 +1274,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() >> { wafContext.close() } - 1 * ctx.setKeepType(_) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1332,8 +1326,9 @@ class WAFModuleSpecification extends DDSpecification { initialRuleAddWithMap(waf) then: - thrown RuntimeException + thrown AppSecModuleActivationException wafModule.dataSubscriptions.empty + 1 * wafMetricCollector.wafInit(Waf.LIB_VERSION, _, false) 0 * _ } @@ -1344,8 +1339,10 @@ class WAFModuleSpecification extends DDSpecification { initialRuleAddWithMap(waf) then: - thrown RuntimeException + thrown AppSecModuleActivationException wafModule.ctxAndAddresses.get() == null + // WAF initialization is attempted but fails, so wafInit is called with success=false + 1 * wafMetricCollector.wafInit(Waf.LIB_VERSION, _, false) 0 * _ } @@ -1394,8 +1391,8 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.isWafContextClosed() >> false - 1 * ctx.setKeepType(_) 0 * _ when: @@ -1409,11 +1406,11 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_ as Collection) >> { it[0].iterator().next().ruleMatches[0].parameters[0].value == 'user-to-block-1' } - 1 * ctx.setKeepType(_) 2 * ctx.getWafMetrics() 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * flow.isBlocking() 0 * _ } @@ -1486,9 +1483,9 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.closeWafContext() - 1 * ctx.setKeepType(_) 1 * ctx.isWafContextClosed() 2 * tracer.activeSpan() 1 * flow.isBlocking() @@ -1519,10 +1516,10 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.closeWafContext() 2 * tracer.activeSpan() - 1 * ctx.setKeepType(_) 0 * _ } @@ -1904,7 +1901,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v1', '_dd.appsec.trace.integer': 123456789]) 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.reportEvents([]) 0 * ctx._(*_) !flow1.blocking @@ -1922,7 +1919,8 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v2', '_dd.appsec.trace.integer': 987654321]) 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) + 1 * ctx.reportEvents([]) 0 * ctx._(*_) !flow2.blocking @@ -1941,11 +1939,114 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v3', '_dd.appsec.trace.integer': 555666777]) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.isThrottled(null) - 1 * ctx.setKeepType(_) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) !flow3.blocking } + void 'test trace tagging rule with attributes, no keep and event (dynamic value extraction)'() { + setup: + def rulesConfig = [ + version: '2.1', + metadata: [ + rules_version: '1.2.7' + ], + rules: [ + [ + id: 'arachni_rule', + name: 'Arachni', + tags: [ + type: 'security_scanner', + category: 'attack_attempt' + ], + conditions: [ + [ + parameters: [ + inputs: [ + [ + address: 'server.request.headers.no_cookies', + key_path: ['user-agent'] + ] + ], + regex: '^Arachni\\/v' + ], + operator: 'match_regex' + ] + ], + transformers: [], + on_match: ['block'] + ] + ], + rules_compat: [ + [ + id: 'ttr-000-004', + name: 'Trace Tagging Rule: Attributes, No Keep, Event', + tags: [ + type: 'security_scanner', + category: 'attack_attempt' + ], + conditions: [ + [ + parameters: [ + inputs: [ + [ + address: 'server.request.headers.no_cookies', + key_path: ['user-agent'] + ] + ], + regex: '^TraceTagging\\/v4' + ], + operator: 'match_regex' + ] + ], + output: [ + event: true, + keep: false, + attributes: [ + '_dd.appsec.trace.integer': [ + value: 1729 + ], + '_dd.appsec.trace.agent': [ + address: 'server.request.headers.no_cookies', + key_path: ['user-agent'] + ] + ] + ], + on_match: [] + ] + ] + ] + + when: + initialRuleAddWithMap(rulesConfig) + wafModule.applyConfig(reconf) + + then: + 1 * wafMetricCollector.wafInit(Waf.LIB_VERSION, _, true) + 1 * wafMetricCollector.wafUpdates(_, true) + 1 * reconf.reloadSubscriptions() + 0 * _ + + when: 'test trace tagging rule with attributes, no keep and event (dynamic value extraction)' + def bundle = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES, + new CaseInsensitiveMap>(['user-agent': 'TraceTagging/v4'])) + def flow = new ChangeableFlow() + dataListener.onDataAvailable(flow, ctx, bundle, gwCtx) + ctx.closeWafContext() + + then: + 1 * ctx.getOrCreateWafContext(_, true, false) + 2 * ctx.getWafMetrics() >> metrics + 1 * ctx.isWafContextClosed() >> false + 1 * ctx.closeWafContext() + // Should report derivatives with dynamic value extraction - the user-agent value should be extracted + 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'TraceTagging/v4', '_dd.appsec.trace.integer': 1729]) + 1 * ctx.reportEvents(_ as Collection) + 1 * ctx.isThrottled(null) + 0 * ctx._(*_) + !flow.blocking // Should not block since keep: false + } + private static class BadConfig implements Map { @Delegate private Map delegate diff --git a/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy b/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy index 5a10eb7a197..17764f4f220 100644 --- a/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy +++ b/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy @@ -154,6 +154,42 @@ class TraceTaggingSmokeTest extends AbstractAppSecServerSmokeTest { ] ], on_match: [] + ], + [ + id: 'ttr-000-004', + name: 'Trace Tagging Rule: Attributes, No Keep, Event', + tags: [ + type: 'security_scanner', + category: 'attack_attempt' + ], + conditions: [ + [ + parameters: [ + inputs: [ + [ + address: 'server.request.headers.no_cookies', + key_path: ['user-agent'] + ] + ], + regex: '^TraceTagging\\/v4' + ], + operator: 'match_regex' + ] + ], + output: [ + event: true, + keep: false, + attributes: [ + '_dd.appsec.trace.integer': [ + value: 1729 + ], + '_dd.appsec.trace.agent': [ + address: 'server.request.headers.no_cookies', + key_path: ['user-agent'] + ] + ] + ], + on_match: [] ] ] ] @@ -265,4 +301,37 @@ class TraceTaggingSmokeTest extends AbstractAppSecServerSmokeTest { assert appsecJson.triggers != null, "Missing triggers in WAF attack event" } + def "test trace tagging rule with attributes, no keep and event"() { + when: + String url = "http://localhost:${httpPort}/greeting" + def request = new Request.Builder() + .url(url) + .addHeader("User-Agent", "TraceTagging/v4") + .build() + def response = client.newCall(request).execute() + def responseBodyStr = response.body().string() + waitForTraceCount(1) + + then: + responseBodyStr == "Sup AppSec Dawg" + response.code() == 200 + rootSpans.size() == 1 + + def rootSpan = rootSpans[0] + assert rootSpan.meta['_dd.appsec.trace.agent'] != null, "Missing _dd.appsec.trace.agent from span's meta" + assert rootSpan.metrics['_dd.appsec.trace.integer'] != null, "Missing _dd.appsec.trace.integer from span's metrics" + + assert rootSpan.meta['_dd.appsec.trace.agent'].startsWith("TraceTagging/v4") + assert rootSpan.metrics['_dd.appsec.trace.integer'] == 1729 + + // Check for WAF attack event (should exist since event: true) + assert rootSpan.meta['_dd.appsec.json'] != null, "Missing WAF attack event" + def appsecJson = new JsonSlurper().parseText(rootSpan.meta['_dd.appsec.json']) + assert appsecJson.triggers != null, "Missing triggers in WAF attack event" + + // Should NOT have USER_KEEP sampling priority since keep: false + assert rootSpan.metrics.get('_sampling_priority_v1') < 2, "Should not have USER_KEEP sampling priority when keep: false" + + } + } diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java b/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java index 9e98eb89e02..162c19e8cd4 100644 --- a/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java +++ b/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java @@ -28,7 +28,7 @@ public boolean isBlocking() { } class RequestBlockingAction implements Action { - private final int statusCode; + private final long statusCode; private final BlockingContentType blockingContentType; private final Map extraHeaders; @@ -56,7 +56,7 @@ public boolean isBlocking() { } public int getStatusCode() { - return statusCode; + return Math.toIntExact(statusCode); } public BlockingContentType getBlockingContentType() { From 726049243edcddcca4d889f6a1a128839fc02700 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 26 Sep 2025 14:50:53 +0200 Subject: [PATCH 02/13] Controversial commit that works for trace tag Signed-off-by: sezen.leblay --- .../com/datadog/appsec/ddwaf/WAFModule.java | 14 ++++++++++- .../datadog/appsec/gateway/GatewayBridge.java | 6 ++++- ...ApmTracingDisabledSamplingSmokeTest.groovy | 2 +- .../trace/api/sampling/PrioritySampling.java | 1 + .../common/sampling/AsmStandaloneSampler.java | 23 ++++++++++++++++++ .../datadog/trace/core/DDSpanContext.java | 11 ++++++--- .../sampling/AsmStandaloneSamplerTest.groovy | 24 +++++++++++++++++++ 7 files changed, 75 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index 2750cf32c73..fee0bfbc521 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -31,6 +31,7 @@ import datadog.communication.monitor.Counter; import datadog.communication.monitor.Monitoring; import datadog.trace.api.Config; +import datadog.trace.api.DDTags; import datadog.trace.api.ProductActivation; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Flow; @@ -403,7 +404,7 @@ public void onDataAvailable( log.debug("Setting force-keep tag and manual keep tag on the current span"); // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. - activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); + activeSpan.getLocalRootSpan().setTag(DDTags.MANUAL_KEEP, true); // If APM is disabled, inform downstream services that the current // distributed trace contains at least one ASM event and must inherit // the given force-keep priority @@ -430,6 +431,17 @@ public void onDataAvailable( // report is still done even without keep, in case sampler_keep is desired if (resultWithData.events) { reqCtx.reportEvents(events); + if (!reqCtx.isManuallyKept()) { // Then keep the sample keep behavior + if (!isThrottled) { + AgentSpan activeSpan = AgentTracer.get().activeSpan(); + if (activeSpan != null) { + activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); + activeSpan + .getLocalRootSpan() + .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); + } + } + } } } diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 99e0270d842..0e63b8f8c08 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -730,7 +730,11 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { if (maybeSampleForApiSecurity(ctx, spanInfo, tags)) { if (!Config.get().isApmTracingEnabled()) { - traceSeg.setTagTop(Tags.ASM_KEEP, true); + if (ctx.isManuallyKept()) { + traceSeg.setTagTop(DDTags.MANUAL_KEEP, true); + } else { + traceSeg.setTagTop(Tags.ASM_KEEP, true); + } traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } } else { diff --git a/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy index 126e918344c..cdfd70808e5 100644 --- a/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy +++ b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy @@ -47,7 +47,7 @@ class ApmTracingDisabledSamplingSmokeTest extends AbstractApmTracingDisabledSmok noForceKeepResponse.successful waitForTraceCount(2) assert traces.size() == 2 - checkRootSpanPrioritySampling(traces[1], PrioritySampling.SAMPLER_KEEP) + checkRootSpanPrioritySampling(traces[1], PrioritySampling.USER_KEEP) !hasAppsecPropagationTag(traces[1]) when: "Request without ASM events and force kept span" diff --git a/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java b/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java index 4aeda333623..8ca07851ddc 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java @@ -5,6 +5,7 @@ public class PrioritySampling { * Implementation detail of the client. will not be sent to the agent or propagated. * *

Internal value used when the priority sampling flag has not been set on the span context. + * For more information, see the documentation on trace ingestion mechanisms */ public static final byte UNSET = (byte) 0x80; /** The sampler has decided to drop the trace. */ diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java index 54a2d750700..3722801cb0c 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java @@ -3,8 +3,11 @@ import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP; import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP; +import datadog.trace.api.ProductTraceSource; +import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.sampling.SamplingMechanism; import datadog.trace.core.CoreSpan; +import datadog.trace.core.DDSpan; import java.time.Clock; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; @@ -39,7 +42,13 @@ public > boolean sample(final T span) { @Override public > void setSamplingPriority(final T span) { + if (span.samplingPriority() == PrioritySampling.USER_KEEP && hasAsmTraceSource(span)) { + log.debug( + "Preserving USER_KEEP priority for span {} with ASM trace source", span.getSpanId()); + return; // Keep existing USER_KEEP priority + } + // Apply normal sampling logic (either for non-USER_KEEP spans or downgraded USER_KEEP spans) if (shouldSample()) { log.debug("Set SAMPLER_KEEP for span {}", span.getSpanId()); span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); @@ -49,6 +58,20 @@ public > void setSamplingPriority(final T span) { } } + /** + * Check if the trace has ASM source marking. Only USER_KEEP from ASM traces should be preserved + * in ASM standalone mode. + */ + private > boolean hasAsmTraceSource(final T span) { + // Check if the trace source is marked as ASM + if (span instanceof DDSpan) { + DDSpan ddSpan = (DDSpan) span; + int traceSource = ddSpan.context().getPropagationTags().getTraceSource(); + return ProductTraceSource.isProductMarked(traceSource, ProductTraceSource.ASM); + } + return false; + } + private boolean shouldSample() { long now = clock.millis(); return lastSampleTime.updateAndGet( diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index 4c404ae0a38..d24c4107d10 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -522,11 +522,16 @@ public void forceKeep(byte samplingMechanism) { } private void forceKeepThisSpan(byte samplingMechanism) { + // two ways to force keep, sample or manual + int priority = PrioritySampling.SAMPLER_KEEP; + if (samplingMechanism == SamplingMechanism.MANUAL + || samplingMechanism == SamplingMechanism.APPSEC) { + priority = PrioritySampling.USER_KEEP; + } // if the user really wants to keep this trace chunk, we will let them, // even if the old sampling priority and mechanism have already propagated - if (SAMPLING_PRIORITY_UPDATER.getAndSet(this, PrioritySampling.USER_KEEP) - == PrioritySampling.UNSET) { - propagationTags.updateTraceSamplingPriority(PrioritySampling.USER_KEEP, samplingMechanism); + if (SAMPLING_PRIORITY_UPDATER.getAndSet(this, priority) == PrioritySampling.UNSET) { + propagationTags.updateTraceSamplingPriority(priority, samplingMechanism); } } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy index 1d83510ec52..c6ba7d30fd6 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy @@ -3,6 +3,7 @@ package datadog.trace.common.sampling import datadog.trace.common.writer.ListWriter import datadog.trace.core.test.DDCoreSpecification import datadog.trace.api.sampling.PrioritySampling +import datadog.trace.api.ProductTraceSource import java.time.Clock import java.util.concurrent.atomic.AtomicLong @@ -52,4 +53,27 @@ class AsmStandaloneSamplerTest extends DDCoreSpecification{ tracer.close() } + void "test AppSec spans preserve USER_KEEP priority"() { + setup: + def current = new AtomicLong(System.currentTimeMillis()) + final Clock clock = Mock(Clock) { + millis() >> { current.get() } + } + def sampler = new AsmStandaloneSampler(clock) + def tracer = tracerBuilder().writer(writer).sampler(sampler).build() + + when: "AppSec span with ASM trace source and USER_KEEP priority" + def asmSpan = tracer.buildSpan("web.request").start() + asmSpan.setSamplingPriority(PrioritySampling.USER_KEEP) + asmSpan.context().getPropagationTags().addTraceSource(ProductTraceSource.ASM) + sampler.setSamplingPriority(asmSpan) + + then: "USER_KEEP priority is preserved for ASM spans" + asmSpan.getSamplingPriority() == PrioritySampling.USER_KEEP + + cleanup: + tracer.close() + } + + } From 2914c00302abb0e972201c27fba0dba4a0e26903 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 30 Sep 2025 16:55:21 +0200 Subject: [PATCH 03/13] Revert "Controversial commit that works for trace tag" This reverts commit d9990058072ccd754630590c4308cbbeed2af406. --- .../com/datadog/appsec/ddwaf/WAFModule.java | 14 +---------- .../datadog/appsec/gateway/GatewayBridge.java | 6 +---- ...ApmTracingDisabledSamplingSmokeTest.groovy | 2 +- .../trace/api/sampling/PrioritySampling.java | 1 - .../common/sampling/AsmStandaloneSampler.java | 23 ------------------ .../datadog/trace/core/DDSpanContext.java | 11 +++------ .../sampling/AsmStandaloneSamplerTest.groovy | 24 ------------------- 7 files changed, 6 insertions(+), 75 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index fee0bfbc521..2750cf32c73 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -31,7 +31,6 @@ import datadog.communication.monitor.Counter; import datadog.communication.monitor.Monitoring; import datadog.trace.api.Config; -import datadog.trace.api.DDTags; import datadog.trace.api.ProductActivation; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Flow; @@ -404,7 +403,7 @@ public void onDataAvailable( log.debug("Setting force-keep tag and manual keep tag on the current span"); // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. - activeSpan.getLocalRootSpan().setTag(DDTags.MANUAL_KEEP, true); + activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); // If APM is disabled, inform downstream services that the current // distributed trace contains at least one ASM event and must inherit // the given force-keep priority @@ -431,17 +430,6 @@ public void onDataAvailable( // report is still done even without keep, in case sampler_keep is desired if (resultWithData.events) { reqCtx.reportEvents(events); - if (!reqCtx.isManuallyKept()) { // Then keep the sample keep behavior - if (!isThrottled) { - AgentSpan activeSpan = AgentTracer.get().activeSpan(); - if (activeSpan != null) { - activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); - activeSpan - .getLocalRootSpan() - .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); - } - } - } } } diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 0e63b8f8c08..99e0270d842 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -730,11 +730,7 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { if (maybeSampleForApiSecurity(ctx, spanInfo, tags)) { if (!Config.get().isApmTracingEnabled()) { - if (ctx.isManuallyKept()) { - traceSeg.setTagTop(DDTags.MANUAL_KEEP, true); - } else { - traceSeg.setTagTop(Tags.ASM_KEEP, true); - } + traceSeg.setTagTop(Tags.ASM_KEEP, true); traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } } else { diff --git a/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy index cdfd70808e5..126e918344c 100644 --- a/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy +++ b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy @@ -47,7 +47,7 @@ class ApmTracingDisabledSamplingSmokeTest extends AbstractApmTracingDisabledSmok noForceKeepResponse.successful waitForTraceCount(2) assert traces.size() == 2 - checkRootSpanPrioritySampling(traces[1], PrioritySampling.USER_KEEP) + checkRootSpanPrioritySampling(traces[1], PrioritySampling.SAMPLER_KEEP) !hasAppsecPropagationTag(traces[1]) when: "Request without ASM events and force kept span" diff --git a/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java b/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java index 8ca07851ddc..4aeda333623 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/sampling/PrioritySampling.java @@ -5,7 +5,6 @@ public class PrioritySampling { * Implementation detail of the client. will not be sent to the agent or propagated. * *

Internal value used when the priority sampling flag has not been set on the span context. - * For more information, see the documentation on trace ingestion mechanisms */ public static final byte UNSET = (byte) 0x80; /** The sampler has decided to drop the trace. */ diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java index 3722801cb0c..54a2d750700 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java @@ -3,11 +3,8 @@ import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP; import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP; -import datadog.trace.api.ProductTraceSource; -import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.sampling.SamplingMechanism; import datadog.trace.core.CoreSpan; -import datadog.trace.core.DDSpan; import java.time.Clock; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; @@ -42,13 +39,7 @@ public > boolean sample(final T span) { @Override public > void setSamplingPriority(final T span) { - if (span.samplingPriority() == PrioritySampling.USER_KEEP && hasAsmTraceSource(span)) { - log.debug( - "Preserving USER_KEEP priority for span {} with ASM trace source", span.getSpanId()); - return; // Keep existing USER_KEEP priority - } - // Apply normal sampling logic (either for non-USER_KEEP spans or downgraded USER_KEEP spans) if (shouldSample()) { log.debug("Set SAMPLER_KEEP for span {}", span.getSpanId()); span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); @@ -58,20 +49,6 @@ public > void setSamplingPriority(final T span) { } } - /** - * Check if the trace has ASM source marking. Only USER_KEEP from ASM traces should be preserved - * in ASM standalone mode. - */ - private > boolean hasAsmTraceSource(final T span) { - // Check if the trace source is marked as ASM - if (span instanceof DDSpan) { - DDSpan ddSpan = (DDSpan) span; - int traceSource = ddSpan.context().getPropagationTags().getTraceSource(); - return ProductTraceSource.isProductMarked(traceSource, ProductTraceSource.ASM); - } - return false; - } - private boolean shouldSample() { long now = clock.millis(); return lastSampleTime.updateAndGet( diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index d24c4107d10..4c404ae0a38 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -522,16 +522,11 @@ public void forceKeep(byte samplingMechanism) { } private void forceKeepThisSpan(byte samplingMechanism) { - // two ways to force keep, sample or manual - int priority = PrioritySampling.SAMPLER_KEEP; - if (samplingMechanism == SamplingMechanism.MANUAL - || samplingMechanism == SamplingMechanism.APPSEC) { - priority = PrioritySampling.USER_KEEP; - } // if the user really wants to keep this trace chunk, we will let them, // even if the old sampling priority and mechanism have already propagated - if (SAMPLING_PRIORITY_UPDATER.getAndSet(this, priority) == PrioritySampling.UNSET) { - propagationTags.updateTraceSamplingPriority(priority, samplingMechanism); + if (SAMPLING_PRIORITY_UPDATER.getAndSet(this, PrioritySampling.USER_KEEP) + == PrioritySampling.UNSET) { + propagationTags.updateTraceSamplingPriority(PrioritySampling.USER_KEEP, samplingMechanism); } } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy index c6ba7d30fd6..1d83510ec52 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/AsmStandaloneSamplerTest.groovy @@ -3,7 +3,6 @@ package datadog.trace.common.sampling import datadog.trace.common.writer.ListWriter import datadog.trace.core.test.DDCoreSpecification import datadog.trace.api.sampling.PrioritySampling -import datadog.trace.api.ProductTraceSource import java.time.Clock import java.util.concurrent.atomic.AtomicLong @@ -53,27 +52,4 @@ class AsmStandaloneSamplerTest extends DDCoreSpecification{ tracer.close() } - void "test AppSec spans preserve USER_KEEP priority"() { - setup: - def current = new AtomicLong(System.currentTimeMillis()) - final Clock clock = Mock(Clock) { - millis() >> { current.get() } - } - def sampler = new AsmStandaloneSampler(clock) - def tracer = tracerBuilder().writer(writer).sampler(sampler).build() - - when: "AppSec span with ASM trace source and USER_KEEP priority" - def asmSpan = tracer.buildSpan("web.request").start() - asmSpan.setSamplingPriority(PrioritySampling.USER_KEEP) - asmSpan.context().getPropagationTags().addTraceSource(ProductTraceSource.ASM) - sampler.setSamplingPriority(asmSpan) - - then: "USER_KEEP priority is preserved for ASM spans" - asmSpan.getSamplingPriority() == PrioritySampling.USER_KEEP - - cleanup: - tracer.close() - } - - } From c513eb68cdf10da906c480e06998cf32988221e4 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 30 Sep 2025 17:13:08 +0200 Subject: [PATCH 04/13] trial Signed-off-by: sezen.leblay --- .../com/datadog/appsec/ddwaf/WAFModule.java | 35 +++++++++---------- .../ddwaf/WAFModuleSpecification.groovy | 22 ------------ 2 files changed, 17 insertions(+), 40 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index 2750cf32c73..ff9954214e8 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -31,6 +31,7 @@ import datadog.communication.monitor.Counter; import datadog.communication.monitor.Monitoring; import datadog.trace.api.Config; +import datadog.trace.api.DDTags; import datadog.trace.api.ProductActivation; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Flow; @@ -395,30 +396,28 @@ public void onDataAvailable( Collection events = buildEvents(resultWithData); boolean isThrottled = reqCtx.isThrottled(rateLimiter); - if (resultWithData.keep) { - reqCtx.setManuallyKept(true); - if (!isThrottled) { - AgentSpan activeSpan = AgentTracer.get().activeSpan(); - if (activeSpan != null) { + if (!isThrottled) { + AgentSpan activeSpan = AgentTracer.get().activeSpan(); + if (activeSpan != null) { + if (resultWithData.keep) { log.debug("Setting force-keep tag and manual keep tag on the current span"); // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. + activeSpan.getLocalRootSpan().setTag(DDTags.MANUAL_KEEP, true); + } else if (resultWithData.events) { activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); - // If APM is disabled, inform downstream services that the current - // distributed trace contains at least one ASM event and must inherit - // the given force-keep priority - activeSpan - .getLocalRootSpan() - .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); - } else { - // If active span is not available then we need to set manual keep in GatewayBridge - log.debug("There is no active span available"); } + activeSpan + .getLocalRootSpan() + .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } else { - log.debug("Rate limited WAF events"); - if (!gwCtx.isRasp) { - reqCtx.setWafRateLimited(); - } + // If active span is not available then we need to set manual keep in GatewayBridge + log.debug("There is no active span available"); + } + } else { + log.debug("Rate limited WAF events"); + if (!gwCtx.isRasp) { + reqCtx.setWafRateLimited(); } } diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy index 7589dd06a91..b17d8e67345 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy @@ -217,7 +217,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ } @@ -252,7 +251,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ when: 'merges new waf data with the one in the rules config' @@ -288,7 +286,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -312,7 +309,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ when: 'changes the rules config' @@ -364,7 +360,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -436,7 +431,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -513,7 +507,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ } @@ -580,7 +573,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ } @@ -602,7 +594,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) flow.blocking flow.action instanceof Flow.Action.RequestBlockingAction @@ -666,7 +657,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) flow.blocking flow.action.statusCode == 418 @@ -694,7 +684,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) metrics == null } @@ -745,7 +734,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(*_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * ctx.isWafContextClosed() >> false 0 * ctx._(*_) flow.blocking @@ -1005,7 +993,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * ctx.closeWafContext() 2 * tracer.activeSpan() 1 * wafMetricCollector.wafInit(Waf.LIB_VERSION, _, true) @@ -1047,7 +1034,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ } @@ -1153,7 +1139,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1251,7 +1236,6 @@ class WAFModuleSpecification extends DDSpecification { _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * _ when: 'removing c and a removes c and a, allows earlier toggle to take effect' @@ -1391,7 +1375,6 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * ctx.isWafContextClosed() >> false 0 * _ @@ -1410,7 +1393,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * flow.isBlocking() 0 * _ } @@ -1483,7 +1465,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.closeWafContext() 1 * ctx.isWafContextClosed() @@ -1516,7 +1497,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.closeWafContext() 2 * tracer.activeSpan() @@ -1919,7 +1899,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v2', '_dd.appsec.trace.integer': 987654321]) 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents([]) 0 * ctx._(*_) !flow2.blocking @@ -1939,7 +1918,6 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v3', '_dd.appsec.trace.integer': 555666777]) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.isThrottled(null) - 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) !flow3.blocking } From 00fa9fd3fc2b4c14cce5c60c3628d5db4af43a97 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Wed, 1 Oct 2025 11:56:21 +0200 Subject: [PATCH 05/13] oh! Signed-off-by: sezen.leblay --- .../src/main/java/com/datadog/appsec/ddwaf/WAFModule.java | 4 ++-- .../java/com/datadog/appsec/gateway/GatewayBridge.java | 2 +- .../datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy | 3 ++- dd-trace-api/src/main/java/datadog/trace/api/DDTags.java | 3 +++ .../trace/common/sampling/AsmStandaloneSampler.java | 2 +- .../datadog/trace/core/taginterceptor/TagInterceptor.java | 8 ++++++++ 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index ff9954214e8..f8c20789a66 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -404,8 +404,8 @@ public void onDataAvailable( // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. activeSpan.getLocalRootSpan().setTag(DDTags.MANUAL_KEEP, true); - } else if (resultWithData.events) { - activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); + } else if (resultWithData.events) { // sampler still might keep + activeSpan.getLocalRootSpan().setTag(DDTags.ASM_SAMPLER_KEEP, true); } activeSpan .getLocalRootSpan() diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 99e0270d842..66e4b5dc3bc 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -754,7 +754,7 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { traceSeg.setTagTop(DDTags.MANUAL_KEEP, true); } else { // Set asm keep in case that root span was not available when events are detected - traceSeg.setTagTop(Tags.ASM_KEEP, true); + traceSeg.setTagTop(DDTags.ASM_SAMPLER_KEEP, true); } traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); traceSeg.setTagTop("appsec.event", true); diff --git a/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy b/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy index 17764f4f220..cebd1fb6028 100644 --- a/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy +++ b/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/TraceTaggingSmokeTest.groovy @@ -330,7 +330,8 @@ class TraceTaggingSmokeTest extends AbstractAppSecServerSmokeTest { assert appsecJson.triggers != null, "Missing triggers in WAF attack event" // Should NOT have USER_KEEP sampling priority since keep: false - assert rootSpan.metrics.get('_sampling_priority_v1') < 2, "Should not have USER_KEEP sampling priority when keep: false" + assert rootSpan.metrics.get('_sampling_priority_v1') < 2, + "Should not have USER_KEEP sampling priority when keep: false" } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java index 33ee2edfb2b..15ac2aa8c15 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java @@ -59,6 +59,9 @@ public class DDTags { /** Manually force tracer to drop the trace */ public static final String MANUAL_DROP = "manual.drop"; + /** ASM force tracer to keep the trace with sampler priority (SAMPLER_KEEP) */ + public static final String ASM_SAMPLER_KEEP = "asm.sampler.keep"; + public static final String TRACE_START_TIME = "t0"; /* Tags below are for internal use only. */ diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java index 54a2d750700..7cdb73b0d25 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java @@ -41,7 +41,7 @@ public > boolean sample(final T span) { public > void setSamplingPriority(final T span) { if (shouldSample()) { - log.debug("Set SAMPLER_KEEP for span {}", span.getSpanId()); + log.debug("Set USER_KEEP for span {}", span.getSpanId()); span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); } else { log.debug("Set SAMPLER_DROP for span {}", span.getSpanId()); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java b/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java index 3da653c5398..31c778d2ec1 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java @@ -4,6 +4,7 @@ import static datadog.trace.api.DDTags.MEASURED; import static datadog.trace.api.DDTags.ORIGIN_KEY; import static datadog.trace.api.DDTags.SPAN_TYPE; +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP; import static datadog.trace.api.sampling.PrioritySampling.USER_DROP; import static datadog.trace.api.sampling.PrioritySampling.USER_KEEP; import static datadog.trace.bootstrap.instrumentation.api.Tags.HTTP_METHOD; @@ -108,6 +109,7 @@ public boolean needsIntercept(String tag) { case DDTags.MANUAL_KEEP: case DDTags.MANUAL_DROP: case Tags.ASM_KEEP: + case DDTags.ASM_SAMPLER_KEEP: case Tags.SAMPLING_PRIORITY: case Tags.PROPAGATED_TRACE_SOURCE: case Tags.PROPAGATED_DEBUG: @@ -155,6 +157,12 @@ public boolean interceptTag(DDSpanContext span, String tag, Object value) { return true; } return false; + case DDTags.ASM_SAMPLER_KEEP: + if (asBoolean(value)) { + span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); + return true; + } + return false; case Tags.SAMPLING_PRIORITY: return interceptSamplingPriority(span, value); case Tags.PROPAGATED_TRACE_SOURCE: From 05fab9c04cc7bfde02de0d2b529b7cb5a8cefe80 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Wed, 1 Oct 2025 16:24:41 +0200 Subject: [PATCH 06/13] alejandro part 1 Signed-off-by: sezen.leblay --- .../java/com/datadog/appsec/ddwaf/WAFModule.java | 13 ++++++------- .../com/datadog/appsec/gateway/GatewayBridge.java | 8 ++------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index f8c20789a66..0c2b2225619 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -31,7 +31,6 @@ import datadog.communication.monitor.Counter; import datadog.communication.monitor.Monitoring; import datadog.trace.api.Config; -import datadog.trace.api.DDTags; import datadog.trace.api.ProductActivation; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Flow; @@ -400,16 +399,16 @@ public void onDataAvailable( AgentSpan activeSpan = AgentTracer.get().activeSpan(); if (activeSpan != null) { if (resultWithData.keep) { + reqCtx.setManuallyKept(true); log.debug("Setting force-keep tag and manual keep tag on the current span"); // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. - activeSpan.getLocalRootSpan().setTag(DDTags.MANUAL_KEEP, true); - } else if (resultWithData.events) { // sampler still might keep - activeSpan.getLocalRootSpan().setTag(DDTags.ASM_SAMPLER_KEEP, true); + activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); + + activeSpan + .getLocalRootSpan() + .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } - activeSpan - .getLocalRootSpan() - .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } else { // If active span is not available then we need to set manual keep in GatewayBridge log.debug("There is no active span available"); diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 66e4b5dc3bc..3322d78461c 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -21,7 +21,6 @@ import com.datadog.appsec.report.AppSecEvent; import com.datadog.appsec.report.AppSecEventWrapper; import datadog.trace.api.Config; -import datadog.trace.api.DDTags; import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Events; import datadog.trace.api.gateway.Flow; @@ -751,12 +750,9 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { // If detected any events - mark span at appsec.event if (!collectedEvents.isEmpty()) { if (ctx.isManuallyKept()) { - traceSeg.setTagTop(DDTags.MANUAL_KEEP, true); - } else { - // Set asm keep in case that root span was not available when events are detected - traceSeg.setTagTop(DDTags.ASM_SAMPLER_KEEP, true); + traceSeg.setTagTop(Tags.ASM_KEEP, true); + traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } - traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); traceSeg.setTagTop("appsec.event", true); traceSeg.setTagTop("network.client.ip", ctx.getPeerAddress()); From 8fe160a5cd1a6a841cf52d6ce0b32f9bf3a76e2a Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Wed, 1 Oct 2025 16:31:08 +0200 Subject: [PATCH 07/13] mistake Signed-off-by: sezen.leblay --- .../datadog/trace/common/sampling/AsmStandaloneSampler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java index 7cdb73b0d25..54a2d750700 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java @@ -41,7 +41,7 @@ public > boolean sample(final T span) { public > void setSamplingPriority(final T span) { if (shouldSample()) { - log.debug("Set USER_KEEP for span {}", span.getSpanId()); + log.debug("Set SAMPLER_KEEP for span {}", span.getSpanId()); span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); } else { log.debug("Set SAMPLER_DROP for span {}", span.getSpanId()); From f2f9558ee8f7f85abf0bc6acffe72092007e42a7 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Thu, 2 Oct 2025 14:28:24 +0200 Subject: [PATCH 08/13] cleanup of unit tests Signed-off-by: sezen.leblay --- .../com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy index b17d8e67345..f16281055aa 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy @@ -594,6 +594,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) flow.blocking flow.action instanceof Flow.Action.RequestBlockingAction @@ -657,6 +658,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) flow.blocking flow.action.statusCode == 418 @@ -684,6 +686,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) metrics == null } @@ -734,6 +737,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportEvents(*_) 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.isWafContextClosed() >> false 0 * ctx._(*_) flow.blocking @@ -1899,6 +1903,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v2', '_dd.appsec.trace.integer': 987654321]) 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents([]) 0 * ctx._(*_) !flow2.blocking @@ -1918,6 +1923,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.reportDerivatives(['_dd.appsec.trace.agent':'RulesCompat/v3', '_dd.appsec.trace.integer': 555666777]) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * ctx._(*_) !flow3.blocking } From 357968b04cf2f6a65bad97a7c9a47aee226ce2c1 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Thu, 2 Oct 2025 16:15:51 +0200 Subject: [PATCH 09/13] cleanup Signed-off-by: sezen.leblay --- .../src/main/java/com/datadog/appsec/ddwaf/WAFModule.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index 0c2b2225619..877c1b1452c 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -396,10 +396,10 @@ public void onDataAvailable( boolean isThrottled = reqCtx.isThrottled(rateLimiter); if (!isThrottled) { - AgentSpan activeSpan = AgentTracer.get().activeSpan(); - if (activeSpan != null) { - if (resultWithData.keep) { - reqCtx.setManuallyKept(true); + if (resultWithData.keep) { + reqCtx.setManuallyKept(true); + AgentSpan activeSpan = AgentTracer.get().activeSpan(); + if (activeSpan != null) { log.debug("Setting force-keep tag and manual keep tag on the current span"); // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. From 9fc0b3a49b6a6b2344eeb56ef5828809b862a23d Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Thu, 2 Oct 2025 16:33:47 +0200 Subject: [PATCH 10/13] cleanup Signed-off-by: sezen.leblay --- .../appsec/ddwaf/WAFModuleSpecification.groovy | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy index f16281055aa..7589dd06a91 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy @@ -217,6 +217,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -251,6 +252,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: 'merges new waf data with the one in the rules config' @@ -286,6 +288,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -309,6 +312,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: 'changes the rules config' @@ -360,6 +364,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -431,6 +436,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: @@ -507,6 +513,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * ctx.setWafBlocked() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -573,6 +580,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -997,6 +1005,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.closeWafContext() 2 * tracer.activeSpan() 1 * wafMetricCollector.wafInit(Waf.LIB_VERSION, _, true) @@ -1038,6 +1047,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ } @@ -1143,6 +1153,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.closeWafContext() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 0 * _ @@ -1240,6 +1251,7 @@ class WAFModuleSpecification extends DDSpecification { _ * ctx.increaseWafTimeouts() _ * ctx.increaseRaspTimeouts() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 0 * _ when: 'removing c and a removes c and a, allows earlier toggle to take effect' @@ -1379,6 +1391,7 @@ class WAFModuleSpecification extends DDSpecification { 2 * ctx.getWafMetrics() 1 * flow.isBlocking() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.isWafContextClosed() >> false 0 * _ @@ -1397,6 +1410,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.isWafContextClosed() >> false 1 * ctx.closeWafContext() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * flow.isBlocking() 0 * _ } @@ -1469,6 +1483,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.closeWafContext() 1 * ctx.isWafContextClosed() @@ -1501,6 +1516,7 @@ class WAFModuleSpecification extends DDSpecification { 1 * ctx.getOrCreateWafContext(_ as WafHandle, true, false) 2 * ctx.getWafMetrics() 1 * ctx.isThrottled(null) + 1 * ctx.setManuallyKept(true) 1 * ctx.reportEvents(_ as Collection) 1 * ctx.closeWafContext() 2 * tracer.activeSpan() From 0bec75cb01c0031132080558a5ebac6910552e2c Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Thu, 2 Oct 2025 16:54:41 +0200 Subject: [PATCH 11/13] cleanup Signed-off-by: sezen.leblay --- .../src/main/java/com/datadog/appsec/gateway/GatewayBridge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index a33b5ef2372..f0f18abe5f2 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -8,7 +8,7 @@ import static com.datadog.appsec.gateway.AppSecRequestContext.REQUEST_HEADERS_ALLOW_LIST; import static com.datadog.appsec.gateway.AppSecRequestContext.RESPONSE_HEADERS_ALLOW_LIST; import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY; -import static datadog.trace.bootstrap.instrumentation.api.Tags.SAMPLING_PRIORITY; + import com.datadog.appsec.AppSecSystem; import com.datadog.appsec.api.security.ApiSecurityDownstreamSampler; import com.datadog.appsec.api.security.ApiSecurityDownstreamSamplerImpl; From 5f82fb01523b245f42734517967159c16aabc7b0 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 3 Oct 2025 16:33:51 +0200 Subject: [PATCH 12/13] cleanup Signed-off-by: sezen.leblay --- .../java/com/datadog/appsec/gateway/GatewayBridge.java | 1 + dd-trace-api/src/main/java/datadog/trace/api/DDTags.java | 3 --- .../datadog/trace/core/taginterceptor/TagInterceptor.java | 8 -------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index f0f18abe5f2..fff447f6937 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -863,6 +863,7 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { // If detected any events - mark span at appsec.event if (!collectedEvents.isEmpty()) { if (ctx.isManuallyKept()) { + // Set asm keep in case that root span was not available when events are detected traceSeg.setTagTop(Tags.ASM_KEEP, true); traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java index 15ac2aa8c15..33ee2edfb2b 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java @@ -59,9 +59,6 @@ public class DDTags { /** Manually force tracer to drop the trace */ public static final String MANUAL_DROP = "manual.drop"; - /** ASM force tracer to keep the trace with sampler priority (SAMPLER_KEEP) */ - public static final String ASM_SAMPLER_KEEP = "asm.sampler.keep"; - public static final String TRACE_START_TIME = "t0"; /* Tags below are for internal use only. */ diff --git a/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java b/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java index 31c778d2ec1..3da653c5398 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java @@ -4,7 +4,6 @@ import static datadog.trace.api.DDTags.MEASURED; import static datadog.trace.api.DDTags.ORIGIN_KEY; import static datadog.trace.api.DDTags.SPAN_TYPE; -import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP; import static datadog.trace.api.sampling.PrioritySampling.USER_DROP; import static datadog.trace.api.sampling.PrioritySampling.USER_KEEP; import static datadog.trace.bootstrap.instrumentation.api.Tags.HTTP_METHOD; @@ -109,7 +108,6 @@ public boolean needsIntercept(String tag) { case DDTags.MANUAL_KEEP: case DDTags.MANUAL_DROP: case Tags.ASM_KEEP: - case DDTags.ASM_SAMPLER_KEEP: case Tags.SAMPLING_PRIORITY: case Tags.PROPAGATED_TRACE_SOURCE: case Tags.PROPAGATED_DEBUG: @@ -157,12 +155,6 @@ public boolean interceptTag(DDSpanContext span, String tag, Object value) { return true; } return false; - case DDTags.ASM_SAMPLER_KEEP: - if (asBoolean(value)) { - span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); - return true; - } - return false; case Tags.SAMPLING_PRIORITY: return interceptSamplingPriority(span, value); case Tags.PROPAGATED_TRACE_SOURCE: From b8d31589e9a1041c6234a58f51d9e9c4f1152e65 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 6 Oct 2025 11:55:51 +0200 Subject: [PATCH 13/13] comments Signed-off-by: sezen.leblay --- .../src/main/java/com/datadog/appsec/ddwaf/WAFModule.java | 4 +++- .../src/main/java/datadog/trace/api/gateway/Flow.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java index f4fe8fbbaf7..e00ddecc9a3 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java @@ -424,7 +424,9 @@ public void onDataAvailable( // Keep event related span, because it could be ignored in case of // reduced datadog sampling rate. activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true); - + // If APM is disabled, inform downstream services that the current + // distributed trace contains at least one ASM event and must inherit + // the given force-keep priority activeSpan .getLocalRootSpan() .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java b/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java index 162c19e8cd4..9e98eb89e02 100644 --- a/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java +++ b/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java @@ -28,7 +28,7 @@ public boolean isBlocking() { } class RequestBlockingAction implements Action { - private final long statusCode; + private final int statusCode; private final BlockingContentType blockingContentType; private final Map extraHeaders; @@ -56,7 +56,7 @@ public boolean isBlocking() { } public int getStatusCode() { - return Math.toIntExact(statusCode); + return statusCode; } public BlockingContentType getBlockingContentType() {