From fdda8e172b31f20a056979ac2f3cfc3f23489e04 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 10 Jan 2025 11:40:19 +0100 Subject: [PATCH 01/24] APPSEC-55380 String taint tracking: translateEscapes --- .../iast/propagation/StringModuleImpl.java | 29 ++++ .../java-lang/java-lang-15/build.gradle | 43 +++++ .../java-lang/java-lang-15/gradle.lockfile | 153 ++++++++++++++++++ .../java/lang/jdk15/StringCallSite.java | 28 ++++ .../java/lang/jdk15/StringCallSiteTest.groovy | 35 ++++ .../java/foo/bar/TestStringJDK15Suite.java | 18 +++ .../api/iast/propagation/StringModule.java | 2 + 7 files changed, 308 insertions(+) create mode 100644 dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle create mode 100644 dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile create mode 100644 dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java create mode 100644 dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy create mode 100644 dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/java/foo/bar/TestStringJDK15Suite.java diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java index 52a9c19f055..25d6dfc1474 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java @@ -33,6 +33,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.jetbrains.annotations.NotNull; public class StringModuleImpl implements StringModule { @@ -293,6 +294,34 @@ public void onStringJoin( } } + @Override + public void onStringTranslateEscapes( + @NotNull String self, @org.jetbrains.annotations.Nullable String result) { + if (!canBeTainted(result)) { + return; + } + if (self == result) { // same ref, no change in taint status + return; + } + final IastContext ctx = IastContext.Provider.get(); + if (ctx == null) { + return; + } + final TaintedObjects taintedObjects = ctx.getTaintedObjects(); + final TaintedObject taintedSelf = taintedObjects.get(self); + if (taintedSelf == null) { + return; // original string is not tainted + } + final Range[] rangesSelf = taintedSelf.getRanges(); + if (rangesSelf.length == 0) { + return; // original string is not tainted + } + final Range[] newRanges = Ranges.forSubstring(0, result.length(), rangesSelf); + if (newRanges != null) { + taintedObjects.taint(result, newRanges); // only possibility left + } + } + @Override @SuppressFBWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ") public void onStringRepeat(@Nonnull String self, int count, @Nonnull String result) { diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle b/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle new file mode 100644 index 00000000000..6da7c8a88d6 --- /dev/null +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'idea' +} + +ext { + minJavaVersionForTests = JavaVersion.VERSION_15 +} + +apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'call-site-instrumentation' + +muzzle { + pass { + coreJdk() + } +} + +idea { + module { + jdkName = '17' + } +} + +csi { + javaVersion = JavaLanguageVersion.of(15) +} + +addTestSuiteForDir('latestDepTest', 'test') + +dependencies { + testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') +} + +project.tasks.withType(AbstractCompile).configureEach { + setJavaVersion(it, 17) + if (it.name != 'compileCsiJava') { + sourceCompatibility = JavaVersion.VERSION_15 + targetCompatibility = JavaVersion.VERSION_15 + if (it instanceof JavaCompile) { + it.options.release.set(15) + } + } +} diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile b/dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile new file mode 100644 index 00000000000..02b7ec7bdd1 --- /dev/null +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile @@ -0,0 +1,153 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.2.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.2.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.beust:jcommander:1.78=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.2.2=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.javaparser:javaparser-core:3.25.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,csiCompileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs +com.github.spotbugs:spotbugs:4.7.3=spotbugs +com.github.stefanbirkner:system-rules:1.19.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,csiCompileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath +com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.auto:auto-common:0.10=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,csiCompileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.google.code.gson:gson:2.9.1=spotbugs +com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:guava:20.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.guava:guava:27.0.1-jre=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.re2j:re2j:1.7=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.thoughtworks.qdox:qdox:1.12.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +commons-codec:commons-codec:1.15=spotbugs +commons-fileupload:commons-fileupload:1.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +de.thetaphi:forbiddenapis:3.1=compileClasspath,csiCompileClasspath +info.picocli:picocli:4.6.3=latestDepTestRuntimeClasspath,testRuntimeClasspath +io.sqreen:libsqreen:11.2.0=latestDepTestRuntimeClasspath,testRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +jaxen:jaxen:1.2.0=spotbugs +jline:jline:2.14.6=latestDepTestRuntimeClasspath,testRuntimeClasspath +junit:junit-dep:4.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +junit:junit:4.13.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.14.18=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.jcip:jcip-annotations:1.0=compileClasspath,csiCompileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +net.sf.saxon:Saxon-HE:11.4=spotbugs +org.apache.ant:ant-antlr:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant-antlr:1.9.15=codenarc +org.apache.ant:ant-junit:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant-junit:1.9.15=codenarc +org.apache.ant:ant-launcher:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant:1.10.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.apache.bcel:bcel:6.5.0=spotbugs +org.apache.commons:commons-lang3:3.12.0=spotbugs +org.apache.commons:commons-text:1.10.0=spotbugs +org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs +org.apache.logging.log4j:log4j-api:2.19.0=spotbugs +org.apache.logging.log4j:log4j-core:2.19.0=spotbugs +org.apiguardian:apiguardian-api:1.1.2=latestDepTestCompileClasspath,testCompileClasspath +org.checkerframework:checker-qual:2.5.2=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.codehaus.groovy:groovy-all:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-ant:2.5.14=codenarc +org.codehaus.groovy:groovy-ant:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-astbuilder:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-cli-picocli:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-console:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-datetime:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-docgenerator:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc +org.codehaus.groovy:groovy-groovydoc:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovysh:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jmx:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:2.5.14=codenarc +org.codehaus.groovy:groovy-json:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jsr223:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-macro:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-nio:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-servlet:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-sql:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-swing:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-templates:2.5.14=codenarc +org.codehaus.groovy:groovy-templates:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test-junit5:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-testng:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-xml:2.5.14=codenarc +org.codehaus.groovy:groovy-xml:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy:2.5.14=codenarc +org.codehaus.groovy:groovy:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.codenarc:CodeNarc:2.2.0=codenarc +org.dom4j:dom4j:2.1.3=spotbugs +org.eclipse.jetty:jetty-http:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-io:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-server:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-util:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.gmetrics:GMetrics:1.1=codenarc +org.hamcrest:hamcrest-core:1.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit:junit-bom:5.9.1=spotbugs +org.junit:junit-bom:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.objenesis:objenesis:3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.4=spotbugs +org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-commons:9.4=spotbugs +org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-tree:9.4=spotbugs +org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.4=spotbugs +org.ow2.asm:asm:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm:9.4=spotbugs +org.slf4j:jcl-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.30=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath +org.slf4j:slf4j-api:1.7.32=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j +org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j +org.spockframework:spock-core:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-junit4:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.testng:testng:7.5=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.webjars:jquery:3.5.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.xmlresolver:xmlresolver:4.4.3=spotbugs +xml-apis:xml-apis:1.4.01=spotbugs +empty=csiAnnotationProcessor,csiRuntimeClasspath,main_java17AnnotationProcessor,spotbugsPlugins diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java new file mode 100644 index 00000000000..dc220964eae --- /dev/null +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java @@ -0,0 +1,28 @@ +package datadog.trace.instrumentation.java.lang.jdk15; + +import datadog.trace.agent.tooling.csi.CallSite; +import datadog.trace.api.iast.IastCallSites; +import datadog.trace.api.iast.InstrumentationBridge; +import datadog.trace.api.iast.Propagation; +import datadog.trace.api.iast.propagation.StringModule; + +@Propagation +@CallSite( + spi = IastCallSites.class, + enabled = {"datadog.trace.api.iast.IastEnabledChecks", "isMajorJavaVersionAtLeast", "15"}) +public class StringCallSite { + @CallSite.After("java.lang.String java.lang.String.translateEscapes()") + public static String afterTranslateEscapes( + @CallSite.This final String self, + @CallSite.Return final String result) { + final StringModule module = InstrumentationBridge.STRING; + try { + if (module != null) { + module.onTranslateEscapes(self, result); + } + } catch (final Throwable e) { + module.onUnexpectedException("afterTranslateEscapes threw", e); + } + return result; + } +} diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy new file mode 100644 index 00000000000..331a4ad39c3 --- /dev/null +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -0,0 +1,35 @@ +package datadog.trace.instrumentation.java.lang.jdk15 + +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.iast.InstrumentationBridge +import datadog.trace.api.iast.propagation.StringModule +import foo.bar.TestStringJDK15Suite +import spock.lang.Requires + +@Requires({ + jvm.java15Compatible +}) +class StringCallSiteTest extends AgentTestRunner { + + @Override + protected void configurePreAgent() { + injectSysConfig("dd.iast.enabled", "true") + } + + def 'test string translate escapes call site'() { + setup: + final iastModule = Mock(StringModule) + InstrumentationBridge.registerIastModule(iastModule) + + when: + final result = TestStringJDK15Suite.stringTranslateEscapes(input) + + then: + result == output + 1 * iastModule.onStringTranslateEscapes(input, output) + + where: + input | output + 'Hello\tThis is a line' | 'Hello\n This is a line\n' + } +} diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/java/foo/bar/TestStringJDK15Suite.java b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/java/foo/bar/TestStringJDK15Suite.java new file mode 100644 index 00000000000..046978c773e --- /dev/null +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/java/foo/bar/TestStringJDK15Suite.java @@ -0,0 +1,18 @@ +package foo.bar; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class TestStringJDK15Suite { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestStringJDK15Suite.class); + + private TestStringJDK15Suite() {} + + public static String stringTranslateEscapes(String self) { + LOGGER.debug("Before string translate escapes {}", self); + final String result = self.translateEscapes(); + LOGGER.debug("After string translate escapes {}", result); + return result; + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/iast/propagation/StringModule.java b/internal-api/src/main/java/datadog/trace/api/iast/propagation/StringModule.java index ebdd0fd7e70..2660b0cd53b 100644 --- a/internal-api/src/main/java/datadog/trace/api/iast/propagation/StringModule.java +++ b/internal-api/src/main/java/datadog/trace/api/iast/propagation/StringModule.java @@ -35,6 +35,8 @@ void onStringJoin( void onStringToUpperCase(@Nonnull String self, @Nullable String result); + void onStringTranslateEscapes(@Nonnull String self, @Nullable String result); + void onStringToLowerCase(@Nonnull String self, @Nullable String result); void onStringTrim(@Nonnull String self, @Nullable String result); From edbd4c11de72e921652e8325a63621c93e6ec1c4 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 10 Jan 2025 11:45:21 +0100 Subject: [PATCH 02/24] TU correction --- .../instrumentation/java/lang/jdk15/StringCallSiteTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index 331a4ad39c3..66250b43f61 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -30,6 +30,6 @@ class StringCallSiteTest extends AgentTestRunner { where: input | output - 'Hello\tThis is a line' | 'Hello\n This is a line\n' + 'Hello\tThis is a line' | 'Hello This is a line' } } From 91f4b56e54dd9d8e78557e64b44a1ef99b2c07e5 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 10 Jan 2025 13:19:35 +0100 Subject: [PATCH 03/24] non null correction --- .../java/com/datadog/iast/propagation/StringModuleImpl.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java index 25d6dfc1474..2171379aa14 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java @@ -33,7 +33,6 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.jetbrains.annotations.NotNull; public class StringModuleImpl implements StringModule { @@ -295,8 +294,7 @@ public void onStringJoin( } @Override - public void onStringTranslateEscapes( - @NotNull String self, @org.jetbrains.annotations.Nullable String result) { + public void onStringTranslateEscapes(@Nonnull String self, @Nullable String result) { if (!canBeTainted(result)) { return; } From d7940200386e6a012eb8890474477edc6b12bc39 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 10 Jan 2025 14:15:11 +0100 Subject: [PATCH 04/24] builds --- .../java-lang/java-lang-15/build.gradle | 2 +- .../java-lang/java-lang-15/gradle.lockfile | 153 ------------------ .../java/lang/jdk15/StringCallSite.java | 5 +- .../java/lang/jdk15/StringCallSiteTest.groovy | 2 +- settings.gradle | 2 + 5 files changed, 6 insertions(+), 158 deletions(-) delete mode 100644 dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle b/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle index 6da7c8a88d6..0af4d7d047f 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/build.gradle @@ -22,7 +22,7 @@ idea { } csi { - javaVersion = JavaLanguageVersion.of(15) + javaVersion = JavaLanguageVersion.of(17) } addTestSuiteForDir('latestDepTest', 'test') diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile b/dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile deleted file mode 100644 index 02b7ec7bdd1..00000000000 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/gradle.lockfile +++ /dev/null @@ -1,153 +0,0 @@ -# This is a Gradle generated file for dependency locking. -# Manual edits can break the build and are not advised. -# This file is expected to be part of source control. -cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -ch.qos.logback:logback-classic:1.2.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -ch.qos.logback:logback-core:1.2.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.beust:jcommander:1.78=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okio:okio:1.17.6=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:dd-javac-plugin-client:0.2.2=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:java-dogstatsd-client:4.4.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.javaparser:javaparser-core:3.25.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,csiCompileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs -com.github.spotbugs:spotbugs:4.7.3=spotbugs -com.github.stefanbirkner:system-rules:1.19.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,csiCompileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath -com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.auto:auto-common:0.10=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,csiCompileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.code.gson:gson:2.9.1=spotbugs -com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.guava:guava:20.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.google.guava:guava:27.0.1-jre=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.re2j:re2j:1.7=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.squareup.moshi:moshi:1.11.0=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:okhttp:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okio:okio:1.17.5=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.thoughtworks.qdox:qdox:1.12.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -commons-codec:commons-codec:1.15=spotbugs -commons-fileupload:commons-fileupload:1.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -commons-io:commons-io:2.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -de.thetaphi:forbiddenapis:3.1=compileClasspath,csiCompileClasspath -info.picocli:picocli:4.6.3=latestDepTestRuntimeClasspath,testRuntimeClasspath -io.sqreen:libsqreen:11.2.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -javax.servlet:javax.servlet-api:3.1.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -jaxen:jaxen:1.2.0=spotbugs -jline:jline:2.14.6=latestDepTestRuntimeClasspath,testRuntimeClasspath -junit:junit-dep:4.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -junit:junit:4.13.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy:1.14.18=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -net.jcip:jcip-annotations:1.0=compileClasspath,csiCompileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath -net.sf.saxon:Saxon-HE:11.4=spotbugs -org.apache.ant:ant-antlr:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.apache.ant:ant-antlr:1.9.15=codenarc -org.apache.ant:ant-junit:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.apache.ant:ant-junit:1.9.15=codenarc -org.apache.ant:ant-launcher:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.apache.ant:ant:1.10.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.apache.bcel:bcel:6.5.0=spotbugs -org.apache.commons:commons-lang3:3.12.0=spotbugs -org.apache.commons:commons-text:1.10.0=spotbugs -org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs -org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs -org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs -org.apache.logging.log4j:log4j-api:2.19.0=spotbugs -org.apache.logging.log4j:log4j-core:2.19.0=spotbugs -org.apiguardian:apiguardian-api:1.1.2=latestDepTestCompileClasspath,testCompileClasspath -org.checkerframework:checker-qual:2.5.2=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -org.codehaus.groovy:groovy-all:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-ant:2.5.14=codenarc -org.codehaus.groovy:groovy-ant:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-astbuilder:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-cli-picocli:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-console:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-datetime:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-docgenerator:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc -org.codehaus.groovy:groovy-groovydoc:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-groovysh:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-jmx:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-json:2.5.14=codenarc -org.codehaus.groovy:groovy-json:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-jsr223:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-macro:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-nio:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-servlet:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-sql:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-swing:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-templates:2.5.14=codenarc -org.codehaus.groovy:groovy-templates:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-test-junit5:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-test:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-testng:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-xml:2.5.14=codenarc -org.codehaus.groovy:groovy-xml:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy:2.5.14=codenarc -org.codehaus.groovy:groovy:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -org.codenarc:CodeNarc:2.2.0=codenarc -org.dom4j:dom4j:2.1.3=spotbugs -org.eclipse.jetty:jetty-http:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-io:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-server:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-util:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.gmetrics:GMetrics:1.1=codenarc -org.hamcrest:hamcrest-core:1.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.hamcrest:hamcrest:2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-api:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-engine:5.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-commons:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-engine:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-launcher:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-runner:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-suite-api:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-suite-commons:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit:junit-bom:5.9.1=spotbugs -org.junit:junit-bom:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.objenesis:objenesis:3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.opentest4j:opentest4j:1.2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-analysis:9.4=spotbugs -org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-commons:9.4=spotbugs -org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-tree:9.4=spotbugs -org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-util:9.4=spotbugs -org.ow2.asm:asm:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.ow2.asm:asm:9.4=spotbugs -org.slf4j:jcl-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:jul-to-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:log4j-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:slf4j-api:1.7.30=compileClasspath,csiCompileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath -org.slf4j:slf4j-api:1.7.32=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j -org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j -org.spockframework:spock-core:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.spockframework:spock-junit4:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.testng:testng:7.5=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.webjars:jquery:3.5.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.xmlresolver:xmlresolver:4.4.3=spotbugs -xml-apis:xml-apis:1.4.01=spotbugs -empty=csiAnnotationProcessor,csiRuntimeClasspath,main_java17AnnotationProcessor,spotbugsPlugins diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java index dc220964eae..8706339a849 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/main/java/datadog/trace/instrumentation/java/lang/jdk15/StringCallSite.java @@ -13,12 +13,11 @@ public class StringCallSite { @CallSite.After("java.lang.String java.lang.String.translateEscapes()") public static String afterTranslateEscapes( - @CallSite.This final String self, - @CallSite.Return final String result) { + @CallSite.This final String self, @CallSite.Return final String result) { final StringModule module = InstrumentationBridge.STRING; try { if (module != null) { - module.onTranslateEscapes(self, result); + module.onStringTranslateEscapes(self, result); } } catch (final Throwable e) { module.onUnexpectedException("afterTranslateEscapes threw", e); diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index 66250b43f61..d61d3590ca7 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -22,7 +22,7 @@ class StringCallSiteTest extends AgentTestRunner { InstrumentationBridge.registerIastModule(iastModule) when: - final result = TestStringJDK15Suite.stringTranslateEscapes(input) + final result = TestStringJDK15Suite.onStringTranslateEscapes(input) then: result == output diff --git a/settings.gradle b/settings.gradle index 67178ac923b..b834a048b0d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -513,4 +513,6 @@ include ':dd-java-agent:benchmark' include ':dd-java-agent:benchmark-integration' include ':dd-java-agent:benchmark-integration:jetty-perftest' include ':dd-java-agent:benchmark-integration:play-perftest' +include 'dd-java-agent:instrumentation:java-lang:java-lang-15' +findProject(':dd-java-agent:instrumentation:java-lang:java-lang-15')?.name = 'java-lang-15' From 1d28044a4ebefa2d7740a94107f9db20c933ae2a Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 10 Jan 2025 15:39:42 +0100 Subject: [PATCH 05/24] add module to StringCallSiteTest --- .../java/lang/jdk15/StringCallSiteTest.groovy | 5 +++-- settings.gradle | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index d61d3590ca7..0ad3c9a6925 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -22,7 +22,7 @@ class StringCallSiteTest extends AgentTestRunner { InstrumentationBridge.registerIastModule(iastModule) when: - final result = TestStringJDK15Suite.onStringTranslateEscapes(input) + final result = TestStringJDK15Suite.stringTranslateEscapes(input) then: result == output @@ -30,6 +30,7 @@ class StringCallSiteTest extends AgentTestRunner { where: input | output - 'Hello\tThis is a line' | 'Hello This is a line' + 'Hello\tThis is a line' | 'Hello\tThis is a line' + 0 * _ } } diff --git a/settings.gradle b/settings.gradle index b834a048b0d..d1fc3daae4b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -291,6 +291,7 @@ include ':dd-java-agent:instrumentation:java-io' include ':dd-java-agent:instrumentation:java-lang' include ':dd-java-agent:instrumentation:java-lang:java-lang-9' include ':dd-java-agent:instrumentation:java-lang:java-lang-11' +include ':dd-java-agent:instrumentation:java-lang:java-lang-15' include ':dd-java-agent:instrumentation:java-lang:java-lang-17' include ':dd-java-agent:instrumentation:java-net' include ':dd-java-agent:instrumentation:java-security' From e16856d99fc1aaf6da2ca2a89f1bc1a16b8ea187 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Fri, 10 Jan 2025 15:44:28 +0100 Subject: [PATCH 06/24] add module to StringCallSiteTest --- .../instrumentation/java/lang/jdk15/StringCallSiteTest.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index 0ad3c9a6925..cecc56b1402 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -31,6 +31,5 @@ class StringCallSiteTest extends AgentTestRunner { where: input | output 'Hello\tThis is a line' | 'Hello\tThis is a line' - 0 * _ } } From fe5078c4b97bd7fb8c34754d7fc40fc618720093 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 13 Jan 2025 11:15:12 +0100 Subject: [PATCH 07/24] smoke test --- .../iast-util/iast-util-17/build.gradle | 35 ++++++++++++ .../controller/StringOperationController.java | 17 ++++++ .../AbstractIast17SpringBootTest.groovy | 56 +++++++++++++++++++ settings.gradle | 1 + 4 files changed, 109 insertions(+) create mode 100644 dd-smoke-tests/iast-util/iast-util-17/build.gradle create mode 100644 dd-smoke-tests/iast-util/iast-util-17/src/main/java/datadog/smoketest/springboot/controller/StringOperationController.java create mode 100644 dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy diff --git a/dd-smoke-tests/iast-util/iast-util-17/build.gradle b/dd-smoke-tests/iast-util/iast-util-17/build.gradle new file mode 100644 index 00000000000..7cf5228a533 --- /dev/null +++ b/dd-smoke-tests/iast-util/iast-util-17/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'idea' + id 'java-test-fixtures' +} + + +apply from: "$rootDir/gradle/java.gradle" + +description = 'iast-smoke-tests-utils-java-17' + +idea { + module { + jdkName = '17' + } +} + +dependencies { + api project(':dd-smoke-tests') + compileOnly group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.0.RELEASE' + + testFixturesImplementation testFixtures(project(":dd-smoke-tests:iast-util")) +} + +project.tasks.withType(AbstractCompile).configureEach { + setJavaVersion(it, 17) + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + if (it instanceof JavaCompile) { + it.options.release.set(17) + } +} + +forbiddenApisMain { + failOnMissingClasses = false +} diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/main/java/datadog/smoketest/springboot/controller/StringOperationController.java b/dd-smoke-tests/iast-util/iast-util-17/src/main/java/datadog/smoketest/springboot/controller/StringOperationController.java new file mode 100644 index 00000000000..3f819a60f20 --- /dev/null +++ b/dd-smoke-tests/iast-util/iast-util-17/src/main/java/datadog/smoketest/springboot/controller/StringOperationController.java @@ -0,0 +1,17 @@ +package datadog.smoketest.springboot.controller; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/string") +public class StringOperationController { + + @PostMapping("/translateEscapes") + public String translateEscapes(@RequestParam(value = "parameter") final String parameter) { + parameter.translateEscapes(); + return "ok"; + } +} diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy new file mode 100644 index 00000000000..b3ebf11a79c --- /dev/null +++ b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy @@ -0,0 +1,56 @@ +package datadog.smoketest + +import okhttp3.FormBody +import okhttp3.Request + +import static datadog.trace.api.config.IastConfig.IAST_DEBUG_ENABLED +import static datadog.trace.api.config.IastConfig.IAST_DETECTION_MODE +import static datadog.trace.api.config.IastConfig.IAST_ENABLED + +abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest { + + @Override + ProcessBuilder createProcessBuilder() { + String springBootShadowJar = System.getProperty('datadog.smoketest.springboot.shadowJar.path') + + List command = [] + command.add(javaPath()) + command.addAll(defaultJavaProperties) + command.addAll(iastJvmOpts()) + command.addAll((String[]) ['-jar', springBootShadowJar, "--server.port=${httpPort}"]) + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(buildDirectory)) + // Spring will print all environment variables to the log, which may pollute it and affect log assertions. + processBuilder.environment().clear() + return processBuilder + } + + protected List iastJvmOpts() { + return [ + withSystemProperty(IAST_ENABLED, true), + withSystemProperty(IAST_DETECTION_MODE, 'FULL'), + withSystemProperty(IAST_DEBUG_ENABLED, true), + ] + } + + void 'test String#translateEscapes'() { + setup: + final url = "http://localhost:${httpPort}/string/translateEscapes" + final body = new FormBody.Builder() + .add('paramater', value) + .build() + final request = new Request.Builder().url(url).post(body).build() + + when: + client.newCall(request).execute() + + then: + hasTainted { tainted -> + tainted.value == expected + } + + where: + value | expected + "withEscape/ttab" | "withEscape#0009tab" + } +} diff --git a/settings.gradle b/settings.gradle index d1fc3daae4b..4245c5da165 100644 --- a/settings.gradle +++ b/settings.gradle @@ -168,6 +168,7 @@ include ':dd-smoke-tests:datastreams:kafkaschemaregistry' include ':dd-smoke-tests:iast-propagation' include ':dd-smoke-tests:iast-util' include ':dd-smoke-tests:iast-util:iast-util-11' +include ':dd-smoke-tests:iast-util:iast-util-17' // TODO this fails too often with a jgit failure, so disable until fixed //include ':dd-smoke-tests:debugger-integration-tests:latest-jdk-app' From 33d3163f38ea1a9a065c49b60b63e4320b3c1b87 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 13 Jan 2025 11:22:34 +0100 Subject: [PATCH 08/24] settings correction --- settings.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/settings.gradle b/settings.gradle index 4245c5da165..2c086836a09 100644 --- a/settings.gradle +++ b/settings.gradle @@ -515,6 +515,4 @@ include ':dd-java-agent:benchmark' include ':dd-java-agent:benchmark-integration' include ':dd-java-agent:benchmark-integration:jetty-perftest' include ':dd-java-agent:benchmark-integration:play-perftest' -include 'dd-java-agent:instrumentation:java-lang:java-lang-15' -findProject(':dd-java-agent:instrumentation:java-lang:java-lang-15')?.name = 'java-lang-15' From 94fb22785a9a862671c9c132fb2aea38d2c4f91e Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 13 Jan 2025 12:14:32 +0100 Subject: [PATCH 09/24] test unicode added --- .../instrumentation/java/lang/jdk15/StringCallSiteTest.groovy | 2 +- .../datadog/smoketest/AbstractIast17SpringBootTest.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index cecc56b1402..16ea9d31957 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -30,6 +30,6 @@ class StringCallSiteTest extends AgentTestRunner { where: input | output - 'Hello\tThis is a line' | 'Hello\tThis is a line' + 'Hello\tThis is a line' | 'Hello'+ Character.toString((char)9) +'This is a line' } } diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy index b3ebf11a79c..a896345533d 100644 --- a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy +++ b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy @@ -51,6 +51,6 @@ abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest where: value | expected - "withEscape/ttab" | "withEscape#0009tab" + "withEscape/ttab" | "withEscape" + Character.toString((char)9) + "tab" } } From 82e253076c16162a3422ca4799b054dc36524b21 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Fri, 10 Jan 2025 15:32:35 +0100 Subject: [PATCH 10/24] Use env-entry to add tags per webapp deployment (#8138) * Use env-entry to add tags per webapp deployment * fix gradle file * Migrate to hasmethodadvice * exclude classes from coverage * codenarc * add more repos * jacoco * Update internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java Co-authored-by: Bruce Bujon * review * use our named * more coverage * Update internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java Co-authored-by: Stuart McCulloch * Update internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java Co-authored-by: Stuart McCulloch * review * add jmh * optimize * widen muzzle excludes * exclude lazy from branch coverage * clean * Do not set contextual service name if jee-split-by-deployment is not enabled --------- Co-authored-by: Bruce Bujon Co-authored-by: Stuart McCulloch --- .../jbossmodules/ModuleInstrumentation.java | 4 +- .../LibertyServerInstrumentation.java | 4 +- ...readContextClassloaderInstrumentation.java | 4 +- .../LibertyServerInstrumentation.java | 4 +- .../servlet2/Servlet2Advice.java | 4 +- .../servlet3/Servlet3Advice.java | 4 +- .../servlet3/Servlet3Decorator.java | 4 +- .../JakartaServletInstrumentation.java | 4 +- .../latestDepTest/groovy/TomcatServer.groovy | 1 - .../groovy/TomcatServletTest.groovy | 29 +++ .../src/test/groovy/TomcatServletTest.groovy | 22 +- .../WebappClassLoaderInstrumentation.java | 48 ++++- .../instrumentation/wildfly-9/build.gradle | 193 ++++++++++++++++++ ...nvEntryInjectionSourceInstrumentation.java | 44 ++++ ...urceReferenceProcessorInstrumentation.java | 73 +++++++ .../src/test/groovy/EmbeddedWildfly.groovy | 57 ++++++ .../src/test/groovy/WildFlyForkedTest.groovy | 81 ++++++++ .../test/java/test/JakartaTestServlet.java | 12 ++ .../java/test/ModulePatchInstrumentation.java | 49 +++++ .../src/test/java/test/TestServlet.java | 12 ++ .../src/test/resources/WEB-INF/web.xml | 24 +++ .../CoreTracerClassloaderNamingBenchmark.java | 62 ++++++ .../java/datadog/trace/core/CoreTracer.java | 34 ++- internal-api/build.gradle | 1 + .../ClassloaderConfigurationOverrides.java | 144 +++++++++++++ .../api/naming/ClassloaderServiceNames.java | 76 ------- .../api/naming/v0/MessagingNamingV0.java | 12 +- ...assloaderConfigurationOverridesTest.groovy | 66 ++++++ settings.gradle | 1 + .../ot-is-shaded/build.gradle | 2 +- 30 files changed, 954 insertions(+), 121 deletions(-) create mode 100644 dd-java-agent/instrumentation/wildfly-9/build.gradle create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/EnvEntryInjectionSourceInstrumentation.java create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/ResourceReferenceProcessorInstrumentation.java create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/test/groovy/EmbeddedWildfly.groovy create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/test/groovy/WildFlyForkedTest.groovy create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/test/java/test/JakartaTestServlet.java create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/test/java/test/ModulePatchInstrumentation.java create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/test/java/test/TestServlet.java create mode 100644 dd-java-agent/instrumentation/wildfly-9/src/test/resources/WEB-INF/web.xml create mode 100644 dd-trace-core/src/jmh/java/datadog/trace/core/CoreTracerClassloaderNamingBenchmark.java create mode 100644 internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java delete mode 100644 internal-api/src/main/java/datadog/trace/api/naming/ClassloaderServiceNames.java create mode 100644 internal-api/src/test/groovy/datadog/trace/api/ClassloaderConfigurationOverridesTest.groovy diff --git a/dd-java-agent/instrumentation/jboss-modules/src/main/java/datadog/trace/instrumentation/jbossmodules/ModuleInstrumentation.java b/dd-java-agent/instrumentation/jboss-modules/src/main/java/datadog/trace/instrumentation/jbossmodules/ModuleInstrumentation.java index 39c07bebdb0..da0545b0fb1 100644 --- a/dd-java-agent/instrumentation/jboss-modules/src/main/java/datadog/trace/instrumentation/jbossmodules/ModuleInstrumentation.java +++ b/dd-java-agent/instrumentation/jboss-modules/src/main/java/datadog/trace/instrumentation/jbossmodules/ModuleInstrumentation.java @@ -9,7 +9,7 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; -import datadog.trace.api.naming.ClassloaderServiceNames; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.bootstrap.AgentClassLoading; import java.io.IOException; import java.io.InputStream; @@ -164,7 +164,7 @@ public static class CaptureModuleNameAdvice { public static void afterConstruct(@Advice.This final Module module) { final String name = ModuleNameHelper.extractDeploymentName(module.getClassLoader()); if (name != null && !name.isEmpty()) { - ClassloaderServiceNames.addServiceName(module.getClassLoader(), name); + ClassloaderConfigurationOverrides.withPinnedServiceName(module.getClassLoader(), name); } } } diff --git a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java index 87960ac1940..c6fdef889ab 100644 --- a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java +++ b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java @@ -16,11 +16,11 @@ import com.ibm.wsspi.webcontainer.webapp.IWebAppDispatcherContext; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; import datadog.trace.api.CorrelationIdentifier; import datadog.trace.api.GlobalTracer; import datadog.trace.api.gateway.Flow; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.bootstrap.ActiveSubsystems; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; @@ -116,7 +116,7 @@ public static class HandleRequestAdvice { if (webapp != null) { final ClassLoader cl = webapp.getClassLoader(); if (cl != null) { - ClassloaderServiceNames.maybeSetToSpan(span, cl); + ClassloaderConfigurationOverrides.maybeEnrichSpan(span, cl); } } } diff --git a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ThreadContextClassloaderInstrumentation.java b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ThreadContextClassloaderInstrumentation.java index bac66e2ef5a..9b71fda635c 100644 --- a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ThreadContextClassloaderInstrumentation.java +++ b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ThreadContextClassloaderInstrumentation.java @@ -6,7 +6,7 @@ import com.ibm.ws.classloading.internal.ThreadContextClassLoader; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; -import datadog.trace.api.naming.ClassloaderServiceNames; +import datadog.trace.api.ClassloaderConfigurationOverrides; import net.bytebuddy.asm.Advice; @AutoService(InstrumenterModule.class) @@ -40,7 +40,7 @@ public static class ThreadContextClassloaderAdvice { public static void afterConstruct(@Advice.This ThreadContextClassLoader self) { final String name = BundleNameHelper.extractDeploymentName(self); if (name != null && !name.isEmpty()) { - ClassloaderServiceNames.addServiceName(self, name); + ClassloaderConfigurationOverrides.withPinnedServiceName(self, name); } } } diff --git a/dd-java-agent/instrumentation/liberty-23/src/main/java/datadog/trace/instrumentation/liberty23/LibertyServerInstrumentation.java b/dd-java-agent/instrumentation/liberty-23/src/main/java/datadog/trace/instrumentation/liberty23/LibertyServerInstrumentation.java index 9591f2d50e1..bc101255856 100644 --- a/dd-java-agent/instrumentation/liberty-23/src/main/java/datadog/trace/instrumentation/liberty23/LibertyServerInstrumentation.java +++ b/dd-java-agent/instrumentation/liberty-23/src/main/java/datadog/trace/instrumentation/liberty23/LibertyServerInstrumentation.java @@ -16,11 +16,11 @@ import com.ibm.wsspi.webcontainer.webapp.IWebAppDispatcherContext; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; import datadog.trace.api.CorrelationIdentifier; import datadog.trace.api.GlobalTracer; import datadog.trace.api.gateway.Flow; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.bootstrap.ActiveSubsystems; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; @@ -118,7 +118,7 @@ public static class HandleRequestAdvice { if (webapp != null) { final ClassLoader cl = webapp.getClassLoader(); if (cl != null) { - ClassloaderServiceNames.maybeSetToSpan(span, cl); + ClassloaderConfigurationOverrides.maybeEnrichSpan(span, cl); } } } diff --git a/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Advice.java b/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Advice.java index 30feb834777..85570d6d7f8 100644 --- a/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Advice.java +++ b/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Advice.java @@ -4,12 +4,12 @@ import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE; import static datadog.trace.instrumentation.servlet2.Servlet2Decorator.DECORATE; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; import datadog.trace.api.CorrelationIdentifier; import datadog.trace.api.DDTags; import datadog.trace.api.GlobalTracer; import datadog.trace.api.gateway.Flow; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; @@ -42,7 +42,7 @@ public static boolean onEnter( final boolean hasServletTrace = spanAttr instanceof AgentSpan; if (hasServletTrace) { final AgentSpan span = (AgentSpan) spanAttr; - ClassloaderServiceNames.maybeSetToSpan(span); + ClassloaderConfigurationOverrides.maybeEnrichSpan(span); // Tracing might already be applied by the FilterChain or a parent request (forward/include). return false; } diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Advice.java b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Advice.java index fa6018ae060..0bf2807e9f8 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Advice.java +++ b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Advice.java @@ -7,12 +7,12 @@ import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE; import static datadog.trace.instrumentation.servlet3.Servlet3Decorator.DECORATE; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; import datadog.trace.api.CorrelationIdentifier; import datadog.trace.api.DDTags; import datadog.trace.api.GlobalTracer; import datadog.trace.api.gateway.Flow; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; @@ -63,7 +63,7 @@ public static boolean onEnter( final boolean hasServletTrace = spanAttrValue instanceof AgentSpan; if (hasServletTrace) { final AgentSpan span = (AgentSpan) spanAttrValue; - ClassloaderServiceNames.maybeSetToSpan(span); + ClassloaderConfigurationOverrides.maybeEnrichSpan(span); // Tracing might already be applied by other instrumentation, // the FilterChain or a parent request (forward/include). return false; diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java index 41964668659..f36907c76d9 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java +++ b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.servlet3; -import datadog.trace.api.naming.ClassloaderServiceNames; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; @@ -84,7 +84,7 @@ public AgentSpan onRequest( final HttpServletRequest request, AgentSpanContext.Extracted context) { assert span != null; - ClassloaderServiceNames.maybeSetToSpan(span); + ClassloaderConfigurationOverrides.maybeEnrichSpan(span); if (request != null) { String contextPath = request.getContextPath(); String servletPath = request.getServletPath(); diff --git a/dd-java-agent/instrumentation/servlet/request-5/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletInstrumentation.java b/dd-java-agent/instrumentation/servlet/request-5/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletInstrumentation.java index b038d43c78f..d60711b404c 100644 --- a/dd-java-agent/instrumentation/servlet/request-5/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletInstrumentation.java +++ b/dd-java-agent/instrumentation/servlet/request-5/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletInstrumentation.java @@ -11,9 +11,9 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; import datadog.trace.api.DDTags; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import jakarta.servlet.ServletRequest; @@ -61,7 +61,7 @@ public static AgentSpan before(@Advice.Argument(0) final ServletRequest request) if (span instanceof AgentSpan && CallDepthThreadLocalMap.incrementCallDepth(HttpServletRequest.class) == 0) { final AgentSpan agentSpan = (AgentSpan) span; - ClassloaderServiceNames.maybeSetToSpan(agentSpan); + ClassloaderConfigurationOverrides.maybeEnrichSpan(agentSpan); return agentSpan; } return null; diff --git a/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServer.groovy b/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServer.groovy index 0e419a7b3cd..0edb4a2f4a4 100644 --- a/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServer.groovy +++ b/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServer.groovy @@ -38,7 +38,6 @@ class TomcatServer implements HttpServer { return false } } - setupServlets(servletContext) (server.host as StandardHost).errorReportValveClass = TomcatServletTest.ErrorHandlerValve.name diff --git a/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServletTest.groovy b/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServletTest.groovy index 3569246fd0a..5b3f05d15db 100644 --- a/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServletTest.groovy +++ b/dd-java-agent/instrumentation/tomcat-5.5/src/latestDepTest/groovy/TomcatServletTest.groovy @@ -9,6 +9,7 @@ import org.apache.catalina.connector.Request import org.apache.catalina.connector.Response import org.apache.catalina.startup.Tomcat import org.apache.catalina.valves.ErrorReportValve +import org.apache.tomcat.util.descriptor.web.ContextEnvironment import org.apache.tomcat.util.descriptor.web.FilterDef import org.apache.tomcat.util.descriptor.web.FilterMap @@ -213,4 +214,32 @@ class TomcatServletClassloaderNamingForkedTest extends TomcatServletTest { } } +class TomcatServletEnvEntriesTagTest extends TomcatServletTest { + def addEntry (context, name, value) { + def envEntry = new ContextEnvironment() + envEntry.setName(name) + envEntry.setValue(value) + envEntry.setType("java.lang.String") + context.getNamingResources().addEnvironment(envEntry) + } + @Override + protected void setupServlets(Context context) { + super.setupServlets(context) + addEntry(context, "datadog/tags/custom-tag", "custom-value") + addEntry(context, "java:comp/env/datadog/tags/service", "custom-service") + } + + @Override + String expectedServiceName() { + "custom-service" + } + + @Override + Map expectedExtraServerTags(ServerEndpoint endpoint) { + super.expectedExtraServerTags(endpoint) + ["custom-tag": "custom-value"] as Map + } +} + + + diff --git a/dd-java-agent/instrumentation/tomcat-5.5/src/test/groovy/TomcatServletTest.groovy b/dd-java-agent/instrumentation/tomcat-5.5/src/test/groovy/TomcatServletTest.groovy index cc7f79e3309..c7f80b84a67 100644 --- a/dd-java-agent/instrumentation/tomcat-5.5/src/test/groovy/TomcatServletTest.groovy +++ b/dd-java-agent/instrumentation/tomcat-5.5/src/test/groovy/TomcatServletTest.groovy @@ -1,3 +1,11 @@ +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR +import static org.junit.Assume.assumeTrue + import com.google.common.io.Files import datadog.trace.agent.test.asserts.TraceAssert import datadog.trace.agent.test.base.HttpServer @@ -18,14 +26,6 @@ import org.apache.coyote.http11.Http11BaseProtocol import javax.servlet.Servlet import javax.servlet.ServletException -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR -import static org.junit.Assume.assumeTrue - abstract class TomcatServletTest extends AbstractServletTest { class TomcatServer implements HttpServer { @@ -187,7 +187,7 @@ abstract class TomcatServletTest extends AbstractServletTest childOfPrevious() tags { "component" "java-web-servlet-response" - if ({isDataStreamsEnabled()}) { + if ({ isDataStreamsEnabled() }) { "$DDTags.PATHWAY_HASH" { String } } defaultTags() @@ -227,8 +227,8 @@ abstract class TomcatServletTest extends AbstractServletTest if (endpoint.throwsException) { // Exception classes get wrapped in ServletException ["error.message": { endpoint == EXCEPTION ? "Servlet execution threw an exception" : it == endpoint.body }, - "error.type": { it == ServletException.name || it == InputMismatchException.name }, - "error.stack": String] + "error.type" : { it == ServletException.name || it == InputMismatchException.name }, + "error.stack" : String] } else { Collections.emptyMap() } diff --git a/dd-java-agent/instrumentation/tomcat-classloading-9/src/main/java/datadog/trace/instrumentation/tomcat9/WebappClassLoaderInstrumentation.java b/dd-java-agent/instrumentation/tomcat-classloading-9/src/main/java/datadog/trace/instrumentation/tomcat9/WebappClassLoaderInstrumentation.java index 2980565bec8..ccd92cba35c 100644 --- a/dd-java-agent/instrumentation/tomcat-classloading-9/src/main/java/datadog/trace/instrumentation/tomcat9/WebappClassLoaderInstrumentation.java +++ b/dd-java-agent/instrumentation/tomcat-classloading-9/src/main/java/datadog/trace/instrumentation/tomcat9/WebappClassLoaderInstrumentation.java @@ -1,16 +1,21 @@ package datadog.trace.instrumentation.tomcat9; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.api.ClassloaderConfigurationOverrides.DATADOG_TAGS_JNDI_PREFIX; +import static datadog.trace.api.ClassloaderConfigurationOverrides.DATADOG_TAGS_PREFIX; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; -import datadog.trace.api.naming.ClassloaderServiceNames; +import datadog.trace.api.ClassloaderConfigurationOverrides; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; import org.apache.catalina.Context; import org.apache.catalina.WebResourceRoot; import org.apache.catalina.loader.WebappClassLoaderBase; +import org.apache.tomcat.util.descriptor.web.ContextEnvironment; @AutoService(InstrumenterModule.class) public class WebappClassLoaderInstrumentation extends InstrumenterModule.Tracing @@ -37,10 +42,43 @@ public static void onContextAvailable( @Advice.Argument(0) final WebResourceRoot webResourceRoot) { // at this moment we have the context set in this classloader, hence its name final Context context = webResourceRoot.getContext(); - if (context != null) { - final String contextName = context.getBaseName(); - if (contextName != null && !contextName.isEmpty()) { - ClassloaderServiceNames.addServiceName(classLoader, contextName); + if (context == null) { + return; + } + ClassloaderConfigurationOverrides.ContextualInfo info = null; + + final String contextName = context.getBaseName(); + if (contextName != null && !contextName.isEmpty()) { + info = ClassloaderConfigurationOverrides.withPinnedServiceName(classLoader, contextName); + } + if (context.getNamingResources() != null) { + final ContextEnvironment[] envs = context.getNamingResources().findEnvironments(); + if (envs != null) { + final Map tags = new HashMap<>(); + for (final ContextEnvironment env : envs) { + // as a limitation here we simplify a lot the logic and we do not try to resolve the + // typed value but we just take the string representation. It avoids implementing the + // logic to convert to other types + // (i.e. long, double) or instrument more deeply tomcat naming + if (env.getValue() == null || env.getValue().isEmpty()) { + continue; + } + String name = null; + if (env.getName().startsWith(DATADOG_TAGS_PREFIX)) { + name = env.getName().substring(DATADOG_TAGS_PREFIX.length()); + } else if (env.getName().startsWith(DATADOG_TAGS_JNDI_PREFIX)) { + name = env.getName().substring(DATADOG_TAGS_JNDI_PREFIX.length()); + } + if (name != null && !name.isEmpty()) { + tags.put(name, env.getValue()); + } + } + if (!tags.isEmpty()) { + if (info == null) { + info = ClassloaderConfigurationOverrides.maybeCreateContextualInfo(classLoader); + } + tags.forEach(info::addTag); + } } } } diff --git a/dd-java-agent/instrumentation/wildfly-9/build.gradle b/dd-java-agent/instrumentation/wildfly-9/build.gradle new file mode 100644 index 00000000000..10d93694ef7 --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/build.gradle @@ -0,0 +1,193 @@ +ext { + minJavaVersionForTests = JavaVersion.VERSION_11 + latestDepTestMinJavaVersionForTests = JavaVersion.VERSION_17 + latestDepForkedTestMinJavaVersionForTests = JavaVersion.VERSION_17 +} + +repositories { + maven { + url 'https://maven.repository.redhat.com/ga/' + } + ivy { + url 'https://download.jboss.org/' + patternLayout { + artifact '/[organisation]/[revision]/[module]/[organisation]-[module]-[revision].[ext]' + metadataSources { + artifact() + } + } + } + ivy { + url 'https://github.com/wildfly' + patternLayout { + artifact '/[organisation]/releases/download/[revision]/[organisation]-[revision].[ext]' + metadataSources { + artifact() + } + } + } +} + +muzzle { + extraRepository('redhat-ga', 'https://maven.repository.redhat.com/ga/') + pass { + group = 'org.wildfly' + module = 'wildfly-ee' + versions = '[9.0.0.Final,)' + excludeDependency 'org.jboss.xnio:*' // not related and causes issues with missing jar in maven repo + } +} + +apply from: "$rootDir/gradle/java.gradle" + +addTestSuiteForDir("latestDepTest", "test") +addTestSuiteExtendingForDir("latestDepForkedTest", "latestDepTest", "test") + +configurations { + wildflyTest + wildflyLatestDepTest + wildflyLatestPoll { + canBeResolved = true + } +} + +dependencies { + compileOnly group: 'org.wildfly', name: 'wildfly-ee', version: '9.0.0.Final' + + testImplementation group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' + testImplementation group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0' + + testImplementation group: 'org.wildfly.core', name: 'wildfly-embedded', version: '21.1.0.Final' + testImplementation group: 'org.wildfly.core', name: 'wildfly-server', version: '21.1.0.Final' + testImplementation group: 'org.jboss.shrinkwrap', name: 'shrinkwrap-api', version: '1.2.6' + + testRuntimeOnly project(':dd-java-agent:instrumentation:servlet:request-3') + testRuntimeOnly project(':dd-java-agent:instrumentation:jboss-modules') + testRuntimeOnly project(':dd-java-agent:instrumentation:undertow:undertow-2.0') + testRuntimeOnly project(':dd-java-agent:instrumentation:undertow:undertow-2.2') + testRuntimeOnly group: 'org.jboss.shrinkwrap', name: 'shrinkwrap-spi', version: '1.2.6' + testRuntimeOnly group: 'org.jboss.shrinkwrap', name: 'shrinkwrap-impl-base', version: '1.2.6' + + wildflyTest "wildfly:servlet:21.0.0.Final@zip" + + latestDepTestImplementation group: 'org.wildfly.core', name: 'wildfly-embedded', version: '+' + latestDepTestImplementation group: 'org.wildfly.core', name: 'wildfly-server', version: '+' + wildflyLatestPoll group: 'org.wildfly', name: 'wildfly-dist', version: '+' + + configurations.wildflyLatestPoll.resolve() + def latestWildflyVersion = configurations.wildflyLatestPoll.resolvedConfiguration.getResolvedArtifacts().find { + it.name == "wildfly-dist" + }.moduleVersion.id.version + wildflyLatestDepTest "wildfly:wildfly:$latestWildflyVersion@zip" + latestDepForkedTest { + configure { + jvmArgs += ["-Dtest.jboss.home=$buildDir/wildfly-${latestWildflyVersion}"] + } + } + + latestDepTestRuntimeOnly project(':dd-java-agent:instrumentation:servlet:request-5') +} + + +def extractWildfly(config, zipFileNamePrefix, sync) { + delete(fileTree(buildDir).include("wildfly-*/standalone/deployments/**")) + + def zipPath = config.find { + it.name.startsWith(zipFileNamePrefix) + } + if (zipPath != null) { + def zipFile = file(zipPath) + def outputDir = file("${buildDir}") + + sync.from zipTree(zipFile) + sync.into outputDir + } else { + throw new GradleException("Can't find server zip file that starts with: " + zipFileNamePrefix) + } +} + + +tasks.register("extractWildfly", Copy) { + dependsOn configurations.wildflyTest + mustRunAfter tasks.compileTestGroovy + extractWildfly(configurations.wildflyTest, "servlet", it) + + // When tests are disabled this would still be run, so disable this manually + onlyIf { !project.rootProject.hasProperty("skipTests") } +} + +tasks.register("extractLatestWildfly", Copy) { + dependsOn configurations.wildflyLatestDepTest + mustRunAfter tasks.compileLatestDepTestGroovy + mustRunAfter tasks.compileLatestDepForkedTestGroovy + mustRunAfter tasks.compileLatestDepTestJava + mustRunAfter tasks.compileLatestDepForkedTestJava + mustRunAfter tasks.compileJava + extractWildfly(configurations.wildflyLatestDepTest, "wildfly", it) + + // When tests are disabled this would still be run, so disable this manually + onlyIf { !project.rootProject.hasProperty("skipTests") } +} + + +tasks.named("test").configure { + dependsOn 'extractWildfly' +} + +tasks.named("forkedTest").configure { + dependsOn 'extractWildfly' +} +tasks.named("latestDepForkedTest").configure { + dependsOn 'extractLatestWildfly' +} + +tasks.named("latestDepTest").configure { + dependsOn 'extractLatestWildfly' +} +compileTestGroovy.configure { + javaLauncher = getJavaLauncherFor(11) +} + +[compileLatestDepTestGroovy, compileLatestDepForkedTestGroovy].each { + it.configure { + javaLauncher = getJavaLauncherFor(17) + } +} +compileTestJava.configure { + it.configure { + setJavaVersion(it, 11) + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +[compileLatestDepTestJava, compileLatestDepForkedTestJava].each { + it.configure { + setJavaVersion(it, 17) + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +processTestResources { + filesMatching('**/WEB-INF/web.xml') { + expand( + 'servletClass': 'test.TestServlet', + ) + } +} +[processLatestDepTestResources, processLatestDepForkedTestResources].each { + it.filesMatching('**/WEB-INF/web.xml') { + expand( + 'servletClass': 'test.JakartaTestServlet', + ) + } +} + +forkedTest { + configure { + jvmArgs += ["-Dtest.jboss.home=$buildDir/wildfly-servlet-21.0.0.Final"] + } +} + + diff --git a/dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/EnvEntryInjectionSourceInstrumentation.java b/dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/EnvEntryInjectionSourceInstrumentation.java new file mode 100644 index 00000000000..58c6a5275ac --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/EnvEntryInjectionSourceInstrumentation.java @@ -0,0 +1,44 @@ +package datadog.trace.instrumentation.wildfly; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.bootstrap.InstrumentationContext; +import java.util.Collections; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import org.jboss.as.ee.component.EnvEntryInjectionSource; + +@AutoService(InstrumenterModule.class) +public class EnvEntryInjectionSourceInstrumentation extends InstrumenterModule.Tracing + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + public EnvEntryInjectionSourceInstrumentation() { + super("wildfly", "jee-env-entry"); + } + + @Override + public String instrumentedType() { + return "org.jboss.as.ee.component.EnvEntryInjectionSource"; + } + + @Override + public Map contextStore() { + return Collections.singletonMap( + "org.jboss.as.ee.component.EnvEntryInjectionSource", Object.class.getName()); + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice(isConstructor(), getClass().getName() + "$ConstructorAdvice"); + } + + public static class ConstructorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.This final EnvEntryInjectionSource self, @Advice.Argument(0) final Object value) { + InstrumentationContext.get(EnvEntryInjectionSource.class, Object.class).put(self, value); + } + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/ResourceReferenceProcessorInstrumentation.java b/dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/ResourceReferenceProcessorInstrumentation.java new file mode 100644 index 00000000000..f716563c242 --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/main/java/datadog/trace/instrumentation/wildfly/ResourceReferenceProcessorInstrumentation.java @@ -0,0 +1,73 @@ +package datadog.trace.instrumentation.wildfly; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.ClassloaderConfigurationOverrides; +import datadog.trace.bootstrap.ContextStore; +import datadog.trace.bootstrap.InstrumentationContext; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import org.jboss.as.ee.component.BindingConfiguration; +import org.jboss.as.ee.component.EnvEntryInjectionSource; + +@AutoService(InstrumenterModule.class) +public class ResourceReferenceProcessorInstrumentation extends InstrumenterModule.Tracing + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + public ResourceReferenceProcessorInstrumentation() { + super("wildfly", "jee-env-entry"); + } + + @Override + public String instrumentedType() { + return "org.jboss.as.ee.component.deployers.ResourceReferenceProcessor"; + } + + @Override + public Map contextStore() { + return Collections.singletonMap( + "org.jboss.as.ee.component.EnvEntryInjectionSource", Object.class.getName()); + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + isMethod().and(named("getEnvironmentEntries")), + getClass().getName() + "$GetEnvironmentEntriesAdvice"); + } + + public static class GetEnvironmentEntriesAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.Argument(value = 1) final ClassLoader classLoader, + @Advice.Return final List configurations) { + ClassloaderConfigurationOverrides.ContextualInfo info = null; + ContextStore contextStore = + InstrumentationContext.get(EnvEntryInjectionSource.class, Object.class); + for (BindingConfiguration bindingConfiguration : configurations) { + if (bindingConfiguration.getSource() instanceof EnvEntryInjectionSource) { + final Object value = + contextStore.get((EnvEntryInjectionSource) bindingConfiguration.getSource()); + if (value != null + && bindingConfiguration + .getName() + .startsWith(ClassloaderConfigurationOverrides.DATADOG_TAGS_JNDI_PREFIX)) { + if (info == null) { + info = ClassloaderConfigurationOverrides.maybeCreateContextualInfo(classLoader); + } + info.addTag( + bindingConfiguration + .getName() + .substring(ClassloaderConfigurationOverrides.DATADOG_TAGS_JNDI_PREFIX.length()), + value); + } + } + } + } + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/test/groovy/EmbeddedWildfly.groovy b/dd-java-agent/instrumentation/wildfly-9/src/test/groovy/EmbeddedWildfly.groovy new file mode 100644 index 00000000000..c4e9f78d56a --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/test/groovy/EmbeddedWildfly.groovy @@ -0,0 +1,57 @@ +import datadog.trace.agent.test.utils.OkHttpUtils +import datadog.trace.agent.test.utils.PortUtils +import okhttp3.HttpUrl +import okhttp3.Request +import org.jboss.shrinkwrap.api.exporter.ExplodedExporter +import org.jboss.shrinkwrap.api.spec.WebArchive +import org.wildfly.core.embedded.Configuration +import org.wildfly.core.embedded.EmbeddedProcessFactory +import org.wildfly.core.embedded.StandaloneServer +import spock.util.concurrent.PollingConditions + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.concurrent.TimeUnit + +class EmbeddedWildfly { + + private final StandaloneServer server + private final Path home + private final int port + + EmbeddedWildfly(String jbossHome, int httpPort) { + home = Paths.get(jbossHome) + port = httpPort + def conf = Configuration.Builder + .of(home) + .addCommandArgument("-Djboss.management.http.port=0") + .addCommandArgument("-Djboss.management.https.port=0") + .addCommandArgument("-Djboss.ajp.port=0") + .addCommandArgument("-Djboss.http.port=$httpPort") + .addCommandArgument("-Djboss.https.port=0") + .addSystemPackages("datadog", "groovy") + .build() + server = EmbeddedProcessFactory.createStandaloneServer(conf) + } + + void start() { + server.start() + PortUtils.waitForPortToOpen(port, 30, TimeUnit.SECONDS) + } + + void stop() { + server.stop() + } + + void deploy(WebArchive webArchive) { + def deploymentPath = home.resolve("standalone/deployments") + webArchive.as(ExplodedExporter).exportExploded(deploymentPath.toFile(), "test.war") + Files.createFile(deploymentPath.resolve("test.war.dodeploy")) + new PollingConditions(timeout: 30, delay: 2).eventually { + def request = new Request.Builder().url(HttpUrl.get("http://localhost:$port/test")).build() + def call = OkHttpUtils.client().newCall(request) + assert call.execute().code() == 200 + } + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/test/groovy/WildFlyForkedTest.groovy b/dd-java-agent/instrumentation/wildfly-9/src/test/groovy/WildFlyForkedTest.groovy new file mode 100644 index 00000000000..969d831b5be --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/test/groovy/WildFlyForkedTest.groovy @@ -0,0 +1,81 @@ +import datadog.trace.agent.test.base.WithHttpServer +import datadog.trace.agent.test.naming.TestingGenericHttpNamingConventions +import datadog.trace.agent.test.utils.OkHttpUtils +import datadog.trace.api.DDSpanTypes +import datadog.trace.bootstrap.instrumentation.api.InstrumentationTags +import datadog.trace.bootstrap.instrumentation.api.Tags +import okhttp3.HttpUrl +import okhttp3.Request +import org.jboss.shrinkwrap.api.ShrinkWrap +import org.jboss.shrinkwrap.api.spec.WebArchive +import test.JakartaTestServlet +import test.TestServlet + +class WildFlyForkedTest extends WithHttpServer implements TestingGenericHttpNamingConventions.ServerV0 { + @Override + EmbeddedWildfly startServer(int port) { + // create the archive + def war = ShrinkWrap.create(WebArchive) + war.setWebXML(getClass().getResource("/WEB-INF/web.xml")) + .addClass(TestServlet) // for wildfly 21 (EE 8) + .addClass(JakartaTestServlet) // for latestDep + + def server = new EmbeddedWildfly(System.getProperty("test.jboss.home"), port) + server.start() + server.deploy(war) + server + } + + @Override + void stopServer(EmbeddedWildfly embeddedWildfly) { + embeddedWildfly?.stop() + } + + @Override + protected void configurePreAgent() { + super.configurePreAgent() + // otherwise there are differences in setting the resource name across wildfly versions + injectSysConfig("undertow.legacy.tracing.enabled", "false") + } + + def "should have service name and tags set"() { + setup: + TEST_WRITER.clear() + when: + def request = new Request.Builder().url(HttpUrl.get(server.address()).resolve("/test/hello")).build() + def call = OkHttpUtils.client().newCall(request) + def response = call.execute() + then: + assert response.code() == 200 + assertTraces(1, { + trace(1) { + span { + serviceName "custom-service" + operationName "servlet.request" + resourceName "GET /test/hello" + spanType DDSpanTypes.HTTP_SERVER + errored false + parent() + + tags { + "$Tags.COMPONENT" "undertow-http-server" + "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER + "$Tags.PEER_PORT" Integer + "$Tags.PEER_HOST_IPV4" { String } + "$Tags.HTTP_CLIENT_IP" { String } + "$Tags.HTTP_HOSTNAME" address.host + "$Tags.HTTP_URL" { String } + "$Tags.HTTP_METHOD" "GET" + "$Tags.HTTP_STATUS" 200 + "$Tags.HTTP_USER_AGENT" String + "$Tags.HTTP_ROUTE" { true } + "$InstrumentationTags.SERVLET_CONTEXT" "/test" + "$InstrumentationTags.SERVLET_PATH" "/hello" + "custom-metric" 1983 + defaultTags(true) + } + } + } + }) + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/JakartaTestServlet.java b/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/JakartaTestServlet.java new file mode 100644 index 00000000000..2af90032412 --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/JakartaTestServlet.java @@ -0,0 +1,12 @@ +package test; + +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public class JakartaTestServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + resp.setStatus(HttpServletResponse.SC_OK); + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/ModulePatchInstrumentation.java b/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/ModulePatchInstrumentation.java new file mode 100644 index 00000000000..84095fa4762 --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/ModulePatchInstrumentation.java @@ -0,0 +1,49 @@ +package test; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import net.bytebuddy.asm.Advice; +import org.jboss.modules.Module; + +/** + * This instrumentation is to hack the way the jboss module classloader is loading SPI services. In + * fact, in test we have a classloader different from the one usually used when launching wildfly. + * In particular, we do not want to have SPI load services defined outside the jboss classloader + * module, otherwise this class won't be found afterwards. + */ +@AutoService(InstrumenterModule.class) +public class ModulePatchInstrumentation extends InstrumenterModule.Tracing + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + + public ModulePatchInstrumentation() { + super("jboss-module-patch"); + } + + @Override + public String instrumentedType() { + return "org.jboss.modules.Module"; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice(named("getResources"), getClass().getName() + "$SystemResourcesAdvice"); + } + + public static class SystemResourcesAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.This Module self, + @Advice.Argument(0) String name, + @Advice.Return(readOnly = false) Enumeration ret) { + if (self.getName().endsWith(".jdk")) { + ret = Collections.emptyEnumeration(); + } + } + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/TestServlet.java b/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/TestServlet.java new file mode 100644 index 00000000000..551fa4baf4b --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/test/java/test/TestServlet.java @@ -0,0 +1,12 @@ +package test; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class TestServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + resp.setStatus(HttpServletResponse.SC_OK); + } +} diff --git a/dd-java-agent/instrumentation/wildfly-9/src/test/resources/WEB-INF/web.xml b/dd-java-agent/instrumentation/wildfly-9/src/test/resources/WEB-INF/web.xml new file mode 100644 index 00000000000..bc4afc2b00a --- /dev/null +++ b/dd-java-agent/instrumentation/wildfly-9/src/test/resources/WEB-INF/web.xml @@ -0,0 +1,24 @@ + + + + + test + ${servletClass} + + + + test + /* + + + + java:comp/env/datadog/tags/service + java.lang.String + custom-service + + + java:comp/env/datadog/tags/custom-metric + java.lang.Integer + 1983 + + diff --git a/dd-trace-core/src/jmh/java/datadog/trace/core/CoreTracerClassloaderNamingBenchmark.java b/dd-trace-core/src/jmh/java/datadog/trace/core/CoreTracerClassloaderNamingBenchmark.java new file mode 100644 index 00000000000..cc68ddf847f --- /dev/null +++ b/dd-trace-core/src/jmh/java/datadog/trace/core/CoreTracerClassloaderNamingBenchmark.java @@ -0,0 +1,62 @@ +package datadog.trace.core; + +import static java.util.concurrent.TimeUnit.MICROSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.util.WeakHashMap; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@Warmup(iterations = 1, time = 15, timeUnit = SECONDS) +@Measurement(iterations = 3, time = 30, timeUnit = SECONDS) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(MICROSECONDS) +@Fork(value = 1) +/** + * Benchmark (simulateOverhead) Mode Cnt Score Error Units + * CoreTracerClassloaderNamingBenchmark.benchSpanCreation false avgt 3 0.747 ± 0.040 us/op + * CoreTracerClassloaderNamingBenchmark.benchSpanCreation true avgt 3 0.695 ± 0.106 us/op + */ +public class CoreTracerClassloaderNamingBenchmark { + CoreTracer tracer; + + WeakHashMap weakCache; + + @Param({"false", "true"}) + boolean simulateOverhead; + + @Setup(Level.Iteration) + public void init(Blackhole blackhole) { + tracer = + CoreTracer.builder() + .writer(new BlackholeWriter(blackhole, new TraceCounters(), 0)) + .strictTraceWrites(false) + .build(); + weakCache = new WeakHashMap<>(); + weakCache.put(Thread.currentThread().getContextClassLoader(), "test"); + } + + @Benchmark + public void benchSpanCreation(Blackhole blackhole) { + final AgentSpan span = tracer.startSpan("", ""); + if (simulateOverhead) { + // simulates an extra getContextClassLoader + a WeakHashMap.get + weakCache.get(Thread.currentThread().getContextClassLoader()); + } + span.finish(); + blackhole.consume(span); + } +} diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 437c397883b..29208628624 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -18,6 +18,7 @@ import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.communication.monitor.Monitoring; import datadog.communication.monitor.Recording; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; import datadog.trace.api.DDSpanId; import datadog.trace.api.DDTraceId; @@ -40,7 +41,6 @@ import datadog.trace.api.interceptor.TraceInterceptor; import datadog.trace.api.internal.TraceSegment; import datadog.trace.api.metrics.SpanMetricRegistry; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.api.naming.SpanNaming; import datadog.trace.api.remoteconfig.ServiceNameCollector; import datadog.trace.api.sampling.PrioritySampling; @@ -139,8 +139,10 @@ public static CoreTracerBuilder builder() { /** Tracer start time in nanoseconds measured up to a millisecond accuracy */ private final long startTimeNano; + /** Nanosecond ticks value at tracer start */ private final long startNanoTicks; + /** How often should traced threads check clock ticks against the wall clock */ private final long clockSyncPeriod; @@ -149,6 +151,7 @@ public static CoreTracerBuilder builder() { /** Last time (in nanosecond ticks) the clock was checked for drift */ private volatile long lastSyncTicks; + /** Nanosecond offset to counter clock drift */ private volatile long counterDrift; @@ -160,10 +163,13 @@ public static CoreTracerBuilder builder() { /** Default service name if none provided on the trace or span */ final String serviceName; + /** Writer is an charge of reporting traces and spans to the desired endpoint */ final Writer writer; + /** Sampler defines the sampling policy in order to reduce the number of traces for instance */ final Sampler initialSampler; + /** Scope manager is in charge of managing the scopes from which spans are created */ final ContinuableScopeManager scopeManager; @@ -171,10 +177,13 @@ public static CoreTracerBuilder builder() { /** Initial static configuration associated with the tracer. */ final Config initialConfig; + /** Maintains dynamic configuration associated with the tracer */ private final DynamicConfig dynamicConfig; + /** A set of tags that are added only to the application's root span */ private final Map localRootSpanTags; + /** A set of tags that are added to every span */ private final Map defaultSpanTags; @@ -1589,10 +1598,19 @@ private DDSpanContext buildSpanContext() { if (serviceName == null) { serviceName = traceConfig.getPreferredServiceName(); } - if (serviceName == null && parentServiceName == null) { - // in this case we have a local root without service name. We can try to see if we can find - // one from the thread context classloader - serviceName = ClassloaderServiceNames.maybeGetForCurrentThread(); + Map contextualTags = null; + if (parentServiceName == null) { + // only fetch this on local root spans + final ClassloaderConfigurationOverrides.ContextualInfo contextualInfo = + ClassloaderConfigurationOverrides.maybeGetContextualInfo(); + if (contextualInfo != null) { + // in this case we have a local root without service name. + // We can try to see if we can find one from the thread context classloader + if (serviceName == null) { + serviceName = contextualInfo.getServiceName(); + } + contextualTags = contextualInfo.getTags(); + } } if (serviceName == null) { // it could be on the initial snapshot but may be overridden to null and service name @@ -1609,7 +1627,8 @@ private DDSpanContext buildSpanContext() { mergedTracerTags.size() + (null == tags ? 0 : tags.size()) + (null == coreTags ? 0 : coreTags.size()) - + (null == rootSpanTags ? 0 : rootSpanTags.size()); + + (null == rootSpanTags ? 0 : rootSpanTags.size()) + + (null == contextualTags ? 0 : contextualTags.size()); if (builderRequestContextDataAppSec != null) { requestContextDataAppSec = builderRequestContextDataAppSec; @@ -1655,6 +1674,9 @@ private DDSpanContext buildSpanContext() { context.setAllTags(tags); context.setAllTags(coreTags); context.setAllTags(rootSpanTags); + if (contextualTags != null) { + context.setAllTags(contextualTags); + } return context; } } diff --git a/internal-api/build.gradle b/internal-api/build.gradle index dea10d40519..7b05c6989d7 100644 --- a/internal-api/build.gradle +++ b/internal-api/build.gradle @@ -195,6 +195,7 @@ excludedClassesCoverage += [ ] excludedClassesBranchCoverage = [ 'datadog.trace.api.ProductActivationConfig', + 'datadog.trace.api.ClassloaderConfigurationOverrides.Lazy', 'datadog.trace.api.Config', 'datadog.trace.util.stacktrace.HotSpotStackWalker', 'datadog.trace.util.stacktrace.StackWalkerFactory' diff --git a/internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java b/internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java new file mode 100644 index 00000000000..cfcff9a10b0 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/ClassloaderConfigurationOverrides.java @@ -0,0 +1,144 @@ +package datadog.trace.api; + +import datadog.trace.api.config.GeneralConfig; +import datadog.trace.api.env.CapturedEnvironment; +import datadog.trace.api.remoteconfig.ServiceNameCollector; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ClassloaderConfigurationOverrides { + public static final String DATADOG_TAGS_PREFIX = "datadog/tags/"; + public static final String DATADOG_TAGS_JNDI_PREFIX = "java:comp/env/" + DATADOG_TAGS_PREFIX; + // not final for testing purposes + static boolean CAN_SPLIT_SERVICE_NAME_BY_DEPLOYMENT = + Config.get().isJeeSplitByDeployment() && !Config.get().isServiceNameSetByUser(); + + static class Lazy { + static final ClassloaderConfigurationOverrides INSTANCE = + new ClassloaderConfigurationOverrides(); + } + + public static class ContextualInfo { + private final String serviceName; + private final Map tags = new HashMap<>(); + + public ContextualInfo(String serviceName) { + this.serviceName = serviceName; + } + + public String getServiceName() { + return serviceName; + } + + public void addTag(String name, Object value) { + tags.put(name, value); + } + + public Map getTags() { + return Collections.unmodifiableMap(tags); + } + } + + private static final Function EMPTY_CONTEXTUAL_INFO_ADDER = + ignored -> new ContextualInfo(null); + + private final WeakHashMap weakCache = new WeakHashMap<>(); + private final String inferredServiceName = + CapturedEnvironment.get().getProperties().get(GeneralConfig.SERVICE_NAME); + + private static volatile boolean atLeastOneEntry; + private static final Lock lock = new ReentrantLock(); + + private ClassloaderConfigurationOverrides() {} + + public static void addContextualInfo(ClassLoader classLoader, ContextualInfo contextualInfo) { + try { + lock.lock(); + Lazy.INSTANCE.weakCache.put(classLoader, contextualInfo); + atLeastOneEntry = true; + } finally { + lock.unlock(); + } + } + + public static ContextualInfo maybeCreateContextualInfo(ClassLoader classLoader) { + try { + lock.lock(); + final ContextualInfo ret = + Lazy.INSTANCE.weakCache.computeIfAbsent(classLoader, EMPTY_CONTEXTUAL_INFO_ADDER); + atLeastOneEntry = true; + return ret; + } finally { + lock.unlock(); + } + } + + @Nullable + public static ContextualInfo withPinnedServiceName(ClassLoader classLoader, String serviceName) { + if (!CAN_SPLIT_SERVICE_NAME_BY_DEPLOYMENT) { + return null; + } + final ContextualInfo contextualInfo = new ContextualInfo(serviceName); + addContextualInfo(classLoader, contextualInfo); + return contextualInfo; + } + + @Nullable + public static ContextualInfo maybeGetContextualInfo(ClassLoader classLoader) { + if (atLeastOneEntry) { + return Lazy.INSTANCE.weakCache.get(classLoader); + } + return null; + } + + /** + * Fetches the contextual information linked to the current thread's context classloader. + * + * @return a nullable service name. + */ + @Nullable + public static ContextualInfo maybeGetContextualInfo() { + if (atLeastOneEntry) { + return maybeGetContextualInfo(Thread.currentThread().getContextClassLoader()); + } + return null; + } + + /** + * Enriches the provided spans according to the service name and tags linked to the current + * thread's classloader contextual information. + * + * @param span a nonnull span + */ + public static void maybeEnrichSpan(@Nonnull final AgentSpan span) { + if (atLeastOneEntry) { + maybeEnrichSpan(span, Thread.currentThread().getContextClassLoader()); + } + } + + public static void maybeEnrichSpan( + @Nonnull final AgentSpan span, @Nonnull final ClassLoader classLoader) { + final ContextualInfo contextualInfo = maybeGetContextualInfo(classLoader); + if (contextualInfo == null) { + return; + } + final String serviceName = contextualInfo.getServiceName(); + if (CAN_SPLIT_SERVICE_NAME_BY_DEPLOYMENT && serviceName != null && !serviceName.isEmpty()) { + final String currentServiceName = span.getServiceName(); + if (currentServiceName == null + || currentServiceName.equals(Lazy.INSTANCE.inferredServiceName)) { + span.setServiceName(serviceName); + ServiceNameCollector.get().addService(serviceName); + } + } + contextualInfo.getTags().forEach(span::setTag); + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/naming/ClassloaderServiceNames.java b/internal-api/src/main/java/datadog/trace/api/naming/ClassloaderServiceNames.java deleted file mode 100644 index c9d73f7df1d..00000000000 --- a/internal-api/src/main/java/datadog/trace/api/naming/ClassloaderServiceNames.java +++ /dev/null @@ -1,76 +0,0 @@ -package datadog.trace.api.naming; - -import datadog.trace.api.Config; -import datadog.trace.api.config.GeneralConfig; -import datadog.trace.api.env.CapturedEnvironment; -import datadog.trace.api.remoteconfig.ServiceNameCollector; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; -import java.util.WeakHashMap; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class ClassloaderServiceNames { - private static final boolean ENABLED = - Config.get().isJeeSplitByDeployment() && !Config.get().isServiceNameSetByUser(); - - private static class Lazy { - private static final ClassloaderServiceNames INSTANCE = new ClassloaderServiceNames(); - } - - private final WeakHashMap weakCache = new WeakHashMap<>(); - private final String inferredServiceName = - CapturedEnvironment.get().getProperties().get(GeneralConfig.SERVICE_NAME); - - private ClassloaderServiceNames() {} - - public static void addServiceName(@Nonnull ClassLoader classLoader, @Nonnull String serviceName) { - if (ENABLED) { - Lazy.INSTANCE.weakCache.put(classLoader, serviceName); - } - } - - @Nullable - public static String maybeGet(@Nonnull ClassLoader classLoader) { - if (ENABLED) { - return Lazy.INSTANCE.weakCache.get(classLoader); - } - return null; - } - - /** - * Fetches the service name linked to the current thread's context classloader. - * - * @return a nullable service name. - */ - @Nullable - public static String maybeGetForCurrentThread() { - return maybeGet(Thread.currentThread().getContextClassLoader()); - } - - /** - * Sets the service name to the provided spans according to the service name linked to the current - * thread's classloader. - * - * @param span a nonnull span - */ - public static void maybeSetToSpan(@Nonnull final AgentSpan span) { - maybeSetToSpan(span, Thread.currentThread().getContextClassLoader()); - } - - public static void maybeSetToSpan( - @Nonnull final AgentSpan span, @Nonnull final ClassLoader classLoader) { - if (!ENABLED) { - return; - } - final String currentServiceName = span.getServiceName(); - if (currentServiceName != null - && !currentServiceName.equals(Lazy.INSTANCE.inferredServiceName)) { - return; - } - final String service = maybeGet(classLoader); - if (service != null) { - span.setServiceName(service); - ServiceNameCollector.get().addService(service); - } - } -} diff --git a/internal-api/src/main/java/datadog/trace/api/naming/v0/MessagingNamingV0.java b/internal-api/src/main/java/datadog/trace/api/naming/v0/MessagingNamingV0.java index e7e227fbeb0..60447310128 100644 --- a/internal-api/src/main/java/datadog/trace/api/naming/v0/MessagingNamingV0.java +++ b/internal-api/src/main/java/datadog/trace/api/naming/v0/MessagingNamingV0.java @@ -1,7 +1,7 @@ package datadog.trace.api.naming.v0; +import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; -import datadog.trace.api.naming.ClassloaderServiceNames; import datadog.trace.api.naming.NamingSchema; import datadog.trace.api.remoteconfig.ServiceNameCollector; import java.util.function.Supplier; @@ -16,10 +16,12 @@ private static class ClassloaderDependentNamingSupplier implements Supplier> spanServiceName + } + if (expected) { + 1 * span.setServiceName(contextualServiceName) + } + + where: + splitByDeploymentEnabled | contextualServiceName | spanServiceName | expected + false | null | null | false + false | "test" | null | false + false | null | "test" | false + true | null | null | false + true | "" | null | false + true | "test" | null | true + true | "" | "test" | false + true | null | "test" | false + true | "test" | "test" | false + true | "test" | ddService | true + } + + def "enrich should set tags when present"() { + def span = Mock(AgentSpan) + when: + ClassloaderConfigurationOverrides.maybeCreateContextualInfo(Thread.currentThread().getContextClassLoader()).addTag("key", "value") + ClassloaderConfigurationOverrides.maybeEnrichSpan(span) + then: + 1 * span.setTag("key", "value") + _ * span.getServiceName() + } + + def "no enrichment when contextual info is absent"() { + def span = Mock(AgentSpan) + when: + ClassloaderConfigurationOverrides.addContextualInfo(Thread.currentThread().getContextClassLoader(), null) + then: + ClassloaderConfigurationOverrides.maybeGetContextualInfo() == null + when: + ClassloaderConfigurationOverrides.maybeEnrichSpan(span) + then: + _ + } +} diff --git a/settings.gradle b/settings.gradle index 2c086836a09..9cdfaca3d11 100644 --- a/settings.gradle +++ b/settings.gradle @@ -507,6 +507,7 @@ include ':dd-java-agent:instrumentation:redisson:redisson-2.0.0' include ':dd-java-agent:instrumentation:redisson:redisson-2.3.0' include ':dd-java-agent:instrumentation:redisson:redisson-3.10.3' include ':dd-java-agent:instrumentation:websphere-jmx' +include ':dd-java-agent:instrumentation:wildfly-9' include ':dd-java-agent:instrumentation:zio' include ':dd-java-agent:instrumentation:zio:zio-2.0' diff --git a/test-published-dependencies/ot-is-shaded/build.gradle b/test-published-dependencies/ot-is-shaded/build.gradle index f46b8994634..1b5451238af 100644 --- a/test-published-dependencies/ot-is-shaded/build.gradle +++ b/test-published-dependencies/ot-is-shaded/build.gradle @@ -114,7 +114,7 @@ tasks.register('checkJarSize') { doLast { // Arbitrary limit to prevent unintentional increases to the dd-trace-ot jar size // Raise or lower as required - assert jarFile.length() <= 7 * 1024 * 1024 + assert jarFile.length() <= 8 * 1024 * 1024 } } From 00c8cd0c773f8f93d11cf2513f2f0590f913ac66 Mon Sep 17 00:00:00 2001 From: Thomas Hunter II Date: Fri, 10 Jan 2025 09:27:50 -0800 Subject: [PATCH 11/24] fix github issue creation (#8179) --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 - .github/ISSUE_TEMPLATE/feature_request.yaml | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 0919f60576b..d52534af831 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,6 +1,5 @@ name: "Bug Report (Low Priority)" description: "Create a public Bug Report. Note that these may not be addressed as it depeonds on capacity and that looking up account information will be difficult." -title: "" labels: "type: bug" body: - type: input diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 902e20d3444..84eef89d2c1 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -1,6 +1,5 @@ name: Feature Request (Low Priority) description: Create a public Feature Request. Note that these may not be addressed as it depeonds on capacity and that looking up account information will be difficult. -title: "" labels: "type: feature request" body: - type: input @@ -15,7 +14,7 @@ body: attributes: label: Library Version(s) description: "If your feature request is to add instrumentation support for a library please provide the version you use" - placeholder: 1.2 + placeholder: "1.2" validations: required: false From 542f3b878239ea12b0b0c93a44710933e1214c32 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Mon, 13 Jan 2025 10:01:20 +0100 Subject: [PATCH 12/24] Skip jacoco coverage for internal class (#8183) --- internal-api/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal-api/build.gradle b/internal-api/build.gradle index 7b05c6989d7..e0da08b57fa 100644 --- a/internal-api/build.gradle +++ b/internal-api/build.gradle @@ -36,6 +36,8 @@ excludedClassesCoverage += [ "datadog.trace.api.WithGlobalTracer.1", "datadog.trace.api.naming.**", "datadog.trace.api.gateway.RequestContext.Noop", + "datadog.trace.api.ClassloaderConfigurationOverrides", + "datadog.trace.api.ClassloaderConfigurationOverrides.Lazy", // an enum "datadog.trace.api.sampling.AdaptiveSampler", "datadog.trace.api.sampling.ConstantSampler", From 3c388a5e0d01390d9b4e40c277427547a19d3caf Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 13 Jan 2025 14:52:45 +0100 Subject: [PATCH 13/24] smoke test spring boot for jv17 --- .../springboot-java-17/build.gradle | 45 +++++ .../springboot17/SpringbootApplication.java | 14 ++ .../AppSecSpringBootSmokeTest.groovy | 182 ++++++++++++++++++ .../IastSpringBootSmokeTest.groovy | 5 + settings.gradle | 1 + 5 files changed, 247 insertions(+) create mode 100644 dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle create mode 100644 dd-smoke-tests/iast-propagation/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java create mode 100644 dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy create mode 100644 dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle b/dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle new file mode 100644 index 00000000000..0fbc47edc73 --- /dev/null +++ b/dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle @@ -0,0 +1,45 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'java-test-fixtures' +} + +ext { + minJavaVersionForTests = JavaVersion.VERSION_11 +} + +apply from: "$rootDir/gradle/java.gradle" +description = 'SpringBoot Java 17 Smoke Tests.' + +repositories { + mavenCentral() +} + +dependencies { + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.0.RELEASE' + + testImplementation project(':dd-smoke-tests') + testImplementation testFixtures(project(":dd-smoke-tests:iast-util:iast-util-17")) + testImplementation testFixtures(project(':dd-smoke-tests:iast-util')) + + implementation project(':dd-smoke-tests:iast-util:iast-util-17') +} + +project.tasks.withType(AbstractCompile).configureEach { + setJavaVersion(it, 17) + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + if (it instanceof JavaCompile) { + it.options.release.set(17) + } +} + +forbiddenApisMain { + failOnMissingClasses = false +} + +tasks.withType(Test).configureEach { + dependsOn "bootJar" + jvmArgs "-Ddatadog.smoketest.springboot.shadowJar.path=${tasks.bootJar.archiveFile.get()}" +} diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java b/dd-smoke-tests/iast-propagation/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java new file mode 100644 index 00000000000..73a13ac1099 --- /dev/null +++ b/dd-smoke-tests/iast-propagation/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java @@ -0,0 +1,14 @@ +package datadog.smoketest.springboot17; + +import java.lang.management.ManagementFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringbootApplication { + + public static void main(final String[] args) { + SpringApplication.run(SpringbootApplication.class, args); + System.out.println("Started in " + ManagementFactory.getRuntimeMXBean().getUptime() + "ms"); + } +} diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy b/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy new file mode 100644 index 00000000000..b362064b0be --- /dev/null +++ b/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy @@ -0,0 +1,182 @@ +package datadog.smoketest.springboot17; + +import datadog.smoketest.AbstractServerSmokeTest +import datadog.trace.test.agent.decoder.DecodedSpan +import datadog.trace.test.agent.decoder.DecodedTrace +import datadog.trace.test.agent.decoder.Decoder +import groovy.json.JsonGenerator +import groovy.json.JsonSlurper +import okhttp3.FormBody +import okhttp3.Request +import org.apache.commons.io.IOUtils +import spock.lang.Shared + +import java.nio.charset.StandardCharsets +import java.util.concurrent.BlockingQueue +import java.util.concurrent.LinkedBlockingQueue +import java.util.jar.JarFile + +class AppSecSpringBootSmokeTest extends AbstractServerSmokeTest { + + static class RootSpan { + DecodedSpan span + + Map getMeta() { + span.meta + } + + List> getTriggers() { + def appsecJSON = meta.get("_dd.appsec.json") + if (appsecJSON) { + JsonSlurper jsonParser = new JsonSlurper() + Map attack = jsonParser.parse(appsecJSON.toCharArray()) as Map + Map triggers = attack.get("triggers") as Map + if (triggers) { + return triggers + } + } + [] + } + } + + @Shared + protected BlockingQueue rootSpans = new LinkedBlockingQueue<>() + + @Shared + protected String[] defaultAppSecProperties = [ + "-Ddd.appsec.enabled=true", + "-Ddd.profiling.enabled=false", + "-Ddd.appsec.trace.rate.limit=-1", + '-Ddd.remote_config.enabled=false', + '-Ddd.trace.debug=true' + ] + + @Override + Closure decodedTracesCallback() { + return { List tr -> + tr.forEach { + // The appsec report json is on the root span + def root = Decoder.sortByStart(it.spans).head() + rootSpans << new RootSpan(span: root) + } + } + } + + def setup() { + rootSpans.clear() + } + + def cleanup() { + rootSpans.clear() + } + + /** + * This method fetches default ruleset included in the agent and merges the selected rules, then it points + * the {@code dd.appsec.rules} variable to the new file + */ + void mergeRules(final String path, final List> customRules) { + // Prepare a file with the new rules + final jarFile = new JarFile(shadowJarPath) + final zipEntry = jarFile.getEntry("appsec/default_config.json") + final content = IOUtils.toString(jarFile.getInputStream(zipEntry), StandardCharsets.UTF_8) + final json = new JsonSlurper().parseText(content) as Map + final rules = json.rules as List> + + // remove already existing rules for merge + List customRulesNames = customRules.collect { it.id } + rules.removeIf { it.id in customRulesNames } + + rules.addAll(customRules) + final gen = new JsonGenerator.Options().build() + IOUtils.write(gen.toJson(json), new FileOutputStream(path, false), StandardCharsets.UTF_8) + + // Add a new property pointing to the new ruleset + defaultAppSecProperties += "-Ddd.appsec.rules=${path}" as String + } + + @Shared + String buildDir = new File(System.getProperty("datadog.smoketest.builddir")).absolutePath + @Shared + String customRulesPath = "${buildDir}/appsec_custom_rules.json" + + def prepareCustomRules() { + // Prepare ruleset with additional test rules + mergeRules( + customRulesPath, + [ + [ + id : '__test_strings_block', + name : 'String operations of java 17', + enable : 'true', + tags : [ + type : 'String', + category : 'propagation', + cwe : '918', + capec : '1000/225/115/664', + confidence: '0', + module : 'rasp' + ], + conditions : [ + [ + parameters: [ + resource: [[address: 'server.io.net.url']], + params : [[address: 'server.request.body']], + ], + operator : "string_operation_detector", + ], + ], + transformers: [], + on_match : ['block'] + ] + ]) + } + + @Override + ProcessBuilder createProcessBuilder() { + // We run this here to ensure it runs before starting the process. Child setupSpec runs after parent setupSpec, + // so it is not a valid location. + + prepareCustomRules() + + String springBootShadowJar = System.getProperty('datadog.smoketest.springboot.shadowJar.path') + + List command = new ArrayList<>() + command.add(javaPath()) + command.addAll(defaultJavaProperties) + command.addAll(defaultAppSecProperties) + command.addAll((String[]) ["-jar", springBootShadowJar, "--server.port=${httpPort}"]) + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(buildDirectory)) + // Spring will print all environment variables to the log, which may pollute it and affect log assertions. + processBuilder.environment().clear() + return processBuilder + } + + + + void 'test String translateEscapes'() { + setup: + final url = "http://localhost:${httpPort}/string/translateEscapes" + final body = new FormBody.Builder() + .add('paramater', value).build() + final request = new Request.Builder().url(url).post(body).build() + + when: + client.newCall(request).execute() + + then: + hasTainted { tainted -> + tainted.value == expected + } + + where: + value | expected + "withEscape/ttab" | "withEscape" + Character.toString((char)9) + "tab" + } + + @Override + def logLevel() { + return "debug" + } + +} diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy b/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy new file mode 100644 index 00000000000..963c8ca1681 --- /dev/null +++ b/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy @@ -0,0 +1,5 @@ +package datadog.smoketest.springboot17; + + +class IastSpringBootSmokeTest extends AbstractIastServerSmokeTest { +} diff --git a/settings.gradle b/settings.gradle index 9cdfaca3d11..a6d1c0a2090 100644 --- a/settings.gradle +++ b/settings.gradle @@ -143,6 +143,7 @@ include ':dd-smoke-tests:springboot' include ':dd-smoke-tests:springboot-freemarker' include ':dd-smoke-tests:springboot-grpc' include ':dd-smoke-tests:springboot-java-11' +include ':dd-smoke-tests:springboot-java-17' include ':dd-smoke-tests:springboot-jetty-jsp' include ':dd-smoke-tests:springboot-jpa' include ':dd-smoke-tests:springboot-mongo' From 70db9f31f187b2f4f278a0d8497af9371fbd98db Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 13 Jan 2025 15:24:48 +0100 Subject: [PATCH 14/24] whoops --- .../AppSecSpringBootSmokeTest.groovy | 182 ------------------ .../IastSpringBootSmokeTest.groovy | 5 - .../springboot-java-17/build.gradle | 2 +- .../springboot17/SpringbootApplication.java | 0 .../IastSpringBootSmokeTest.groovy | 6 + 5 files changed, 7 insertions(+), 188 deletions(-) delete mode 100644 dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy delete mode 100644 dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy rename dd-smoke-tests/{iast-propagation => }/springboot-java-17/build.gradle (95%) rename dd-smoke-tests/{iast-propagation => }/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java (100%) create mode 100644 dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy b/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy deleted file mode 100644 index b362064b0be..00000000000 --- a/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/AppSecSpringBootSmokeTest.groovy +++ /dev/null @@ -1,182 +0,0 @@ -package datadog.smoketest.springboot17; - -import datadog.smoketest.AbstractServerSmokeTest -import datadog.trace.test.agent.decoder.DecodedSpan -import datadog.trace.test.agent.decoder.DecodedTrace -import datadog.trace.test.agent.decoder.Decoder -import groovy.json.JsonGenerator -import groovy.json.JsonSlurper -import okhttp3.FormBody -import okhttp3.Request -import org.apache.commons.io.IOUtils -import spock.lang.Shared - -import java.nio.charset.StandardCharsets -import java.util.concurrent.BlockingQueue -import java.util.concurrent.LinkedBlockingQueue -import java.util.jar.JarFile - -class AppSecSpringBootSmokeTest extends AbstractServerSmokeTest { - - static class RootSpan { - DecodedSpan span - - Map getMeta() { - span.meta - } - - List> getTriggers() { - def appsecJSON = meta.get("_dd.appsec.json") - if (appsecJSON) { - JsonSlurper jsonParser = new JsonSlurper() - Map attack = jsonParser.parse(appsecJSON.toCharArray()) as Map - Map triggers = attack.get("triggers") as Map - if (triggers) { - return triggers - } - } - [] - } - } - - @Shared - protected BlockingQueue rootSpans = new LinkedBlockingQueue<>() - - @Shared - protected String[] defaultAppSecProperties = [ - "-Ddd.appsec.enabled=true", - "-Ddd.profiling.enabled=false", - "-Ddd.appsec.trace.rate.limit=-1", - '-Ddd.remote_config.enabled=false', - '-Ddd.trace.debug=true' - ] - - @Override - Closure decodedTracesCallback() { - return { List tr -> - tr.forEach { - // The appsec report json is on the root span - def root = Decoder.sortByStart(it.spans).head() - rootSpans << new RootSpan(span: root) - } - } - } - - def setup() { - rootSpans.clear() - } - - def cleanup() { - rootSpans.clear() - } - - /** - * This method fetches default ruleset included in the agent and merges the selected rules, then it points - * the {@code dd.appsec.rules} variable to the new file - */ - void mergeRules(final String path, final List> customRules) { - // Prepare a file with the new rules - final jarFile = new JarFile(shadowJarPath) - final zipEntry = jarFile.getEntry("appsec/default_config.json") - final content = IOUtils.toString(jarFile.getInputStream(zipEntry), StandardCharsets.UTF_8) - final json = new JsonSlurper().parseText(content) as Map - final rules = json.rules as List> - - // remove already existing rules for merge - List customRulesNames = customRules.collect { it.id } - rules.removeIf { it.id in customRulesNames } - - rules.addAll(customRules) - final gen = new JsonGenerator.Options().build() - IOUtils.write(gen.toJson(json), new FileOutputStream(path, false), StandardCharsets.UTF_8) - - // Add a new property pointing to the new ruleset - defaultAppSecProperties += "-Ddd.appsec.rules=${path}" as String - } - - @Shared - String buildDir = new File(System.getProperty("datadog.smoketest.builddir")).absolutePath - @Shared - String customRulesPath = "${buildDir}/appsec_custom_rules.json" - - def prepareCustomRules() { - // Prepare ruleset with additional test rules - mergeRules( - customRulesPath, - [ - [ - id : '__test_strings_block', - name : 'String operations of java 17', - enable : 'true', - tags : [ - type : 'String', - category : 'propagation', - cwe : '918', - capec : '1000/225/115/664', - confidence: '0', - module : 'rasp' - ], - conditions : [ - [ - parameters: [ - resource: [[address: 'server.io.net.url']], - params : [[address: 'server.request.body']], - ], - operator : "string_operation_detector", - ], - ], - transformers: [], - on_match : ['block'] - ] - ]) - } - - @Override - ProcessBuilder createProcessBuilder() { - // We run this here to ensure it runs before starting the process. Child setupSpec runs after parent setupSpec, - // so it is not a valid location. - - prepareCustomRules() - - String springBootShadowJar = System.getProperty('datadog.smoketest.springboot.shadowJar.path') - - List command = new ArrayList<>() - command.add(javaPath()) - command.addAll(defaultJavaProperties) - command.addAll(defaultAppSecProperties) - command.addAll((String[]) ["-jar", springBootShadowJar, "--server.port=${httpPort}"]) - ProcessBuilder processBuilder = new ProcessBuilder(command) - processBuilder.directory(new File(buildDirectory)) - // Spring will print all environment variables to the log, which may pollute it and affect log assertions. - processBuilder.environment().clear() - return processBuilder - } - - - - void 'test String translateEscapes'() { - setup: - final url = "http://localhost:${httpPort}/string/translateEscapes" - final body = new FormBody.Builder() - .add('paramater', value).build() - final request = new Request.Builder().url(url).post(body).build() - - when: - client.newCall(request).execute() - - then: - hasTainted { tainted -> - tainted.value == expected - } - - where: - value | expected - "withEscape/ttab" | "withEscape" + Character.toString((char)9) + "tab" - } - - @Override - def logLevel() { - return "debug" - } - -} diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy b/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy deleted file mode 100644 index 963c8ca1681..00000000000 --- a/dd-smoke-tests/iast-propagation/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package datadog.smoketest.springboot17; - - -class IastSpringBootSmokeTest extends AbstractIastServerSmokeTest { -} diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle b/dd-smoke-tests/springboot-java-17/build.gradle similarity index 95% rename from dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle rename to dd-smoke-tests/springboot-java-17/build.gradle index 0fbc47edc73..c6d99c2de64 100644 --- a/dd-smoke-tests/iast-propagation/springboot-java-17/build.gradle +++ b/dd-smoke-tests/springboot-java-17/build.gradle @@ -6,7 +6,7 @@ plugins { } ext { - minJavaVersionForTests = JavaVersion.VERSION_11 + minJavaVersionForTests = JavaVersion.VERSION_17 } apply from: "$rootDir/gradle/java.gradle" diff --git a/dd-smoke-tests/iast-propagation/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java b/dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/iast-propagation/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java rename to dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy b/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy new file mode 100644 index 00000000000..800ff5a5b89 --- /dev/null +++ b/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy @@ -0,0 +1,6 @@ +package datadog.smoketest.springboot17 + +import datadog.smoketest.AbstractIast17SpringBootTest + +class IastSpringBootSmokeTest extends AbstractIast17SpringBootTest { +} From 103700928c07180f0660b387984068da76ac9550 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Mon, 13 Jan 2025 16:59:26 +0100 Subject: [PATCH 15/24] unit test --- .../iast/propagation/StringModuleImpl.java | 5 +---- .../iast/propagation/StringModuleTest.groovy | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java index 2171379aa14..b283a863e53 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java @@ -314,10 +314,7 @@ public void onStringTranslateEscapes(@Nonnull String self, @Nullable String resu if (rangesSelf.length == 0) { return; // original string is not tainted } - final Range[] newRanges = Ranges.forSubstring(0, result.length(), rangesSelf); - if (newRanges != null) { - taintedObjects.taint(result, newRanges); // only possibility left - } + taintedObjects.taint(result, rangesSelf); // only possibility left } @Override diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy index cb2d40c20a5..d24b492de48 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy @@ -1414,6 +1414,26 @@ class StringModuleTest extends IastModuleImplTestBase { taintFormat(result, taintedObject.getRanges()) == "==>my_input<==" } + void 'test translate escapes'() { + given: + final taintedObjects = ctx.getTaintedObjects() + def self = addFromTaintFormat(taintedObjects, testString) + def result = self + + when: + module.onStringTranslateEscapes(self, result) + def taintedObject = taintedObjects.get(result) + + then: + taintFormat(result, taintedObject.getRanges()) == expected + + where: + testString | expected + "==>hello world\t<==" | "==>hello world\t<==" + "==>hello world\n<==" | "==>hello world\n<==" + "==>hello worldn<==" | "==>hello worldn<==" + } + void 'test valueOf with special objects and make sure IastRequestContext is called'() { given: final taintedObjects = ctx.getTaintedObjects() From ca6797990c5b767b37ccf0adc031023e75d6740b Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 14 Jan 2025 10:21:50 +0100 Subject: [PATCH 16/24] unit test suppression of equal --- .../main/java/com/datadog/iast/propagation/StringModuleImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java index b283a863e53..3cc4a153809 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java @@ -294,6 +294,7 @@ public void onStringJoin( } @Override + @SuppressFBWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ") public void onStringTranslateEscapes(@Nonnull String self, @Nullable String result) { if (!canBeTainted(result)) { return; From b8c068580aec9bcaf6ae11f2a73c2a17c8af6909 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 14 Jan 2025 12:40:12 +0100 Subject: [PATCH 17/24] mario's idea for j17 tests --- .../datadog/smoketest/AbstractIast17SpringBootTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy index a896345533d..45e6925e9e5 100644 --- a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy +++ b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy @@ -33,7 +33,7 @@ abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest ] } - void 'test String#translateEscapes'() { + void 'test String translateEscapes'() { setup: final url = "http://localhost:${httpPort}/string/translateEscapes" final body = new FormBody.Builder() From 30c46d4cee00ccadc7491f3550194288381b8f87 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 14 Jan 2025 14:26:13 +0100 Subject: [PATCH 18/24] mario's idea for j17 tests --- .../datadog/smoketest/AbstractIast17SpringBootTest.groovy | 7 ++++--- .../SpringbootApplication.java | 2 +- .../IastSpringBootSmokeTest.groovy | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) rename dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/{springboot17 => springboot}/SpringbootApplication.java (91%) rename dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/{springboot17 => springboot}/IastSpringBootSmokeTest.groovy (76%) diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy index 45e6925e9e5..f5406a03fa3 100644 --- a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy +++ b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy @@ -37,10 +37,11 @@ abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest setup: final url = "http://localhost:${httpPort}/string/translateEscapes" final body = new FormBody.Builder() - .add('paramater', value) + .add('parameter', value) .build() final request = new Request.Builder().url(url).post(body).build() + when: client.newCall(request).execute() @@ -50,7 +51,7 @@ abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest } where: - value | expected - "withEscape/ttab" | "withEscape" + Character.toString((char)9) + "tab" + value | expected + "withEscape\ttab" | "withEscape" + Character.toString((char)9) + "tab" } } diff --git a/dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java b/dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 91% rename from dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java rename to dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java index 73a13ac1099..03cc9791085 100644 --- a/dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot17/SpringbootApplication.java +++ b/dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java @@ -1,4 +1,4 @@ -package datadog.smoketest.springboot17; +package datadog.smoketest.springboot; import java.lang.management.ManagementFactory; import org.springframework.boot.SpringApplication; diff --git a/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy b/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot/IastSpringBootSmokeTest.groovy similarity index 76% rename from dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy rename to dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot/IastSpringBootSmokeTest.groovy index 800ff5a5b89..6435d526654 100644 --- a/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot17/IastSpringBootSmokeTest.groovy +++ b/dd-smoke-tests/springboot-java-17/src/test/groovy/datadog/smoketest/springboot/IastSpringBootSmokeTest.groovy @@ -1,4 +1,4 @@ -package datadog.smoketest.springboot17 +package datadog.smoketest.springboot import datadog.smoketest.AbstractIast17SpringBootTest From 378bd8449abe87659b1c3563359e2dd5eebd7773 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Tue, 14 Jan 2025 15:25:55 +0100 Subject: [PATCH 19/24] a few more tests --- .../java/lang/jdk15/StringCallSiteTest.groovy | 7 ++++++- .../datadog/smoketest/AbstractIast17SpringBootTest.groovy | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index 16ea9d31957..989a58ce491 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -1,5 +1,6 @@ package datadog.trace.instrumentation.java.lang.jdk15 +import com.github.javaparser.utils.StringEscapeUtils import datadog.trace.agent.test.AgentTestRunner import datadog.trace.api.iast.InstrumentationBridge import datadog.trace.api.iast.propagation.StringModule @@ -30,6 +31,10 @@ class StringCallSiteTest extends AgentTestRunner { where: input | output - 'Hello\tThis is a line' | 'Hello'+ Character.toString((char)9) +'This is a line' + "HelloThisisaline" | "HelloThisisaline" + "Hello\tThis is a line" | "Hello"+ StringEscapeUtils.unescapeJava("\\u0009") +"This is a line" + /Hello\sThis is a line/ | "Hello"+ StringEscapeUtils.unescapeJava("\\u0020") +"This is a line" + /Hello\"This is a line/ | "Hello"+ StringEscapeUtils.unescapeJava("\\u0022") +"This is a line" + /Hello\0This is a line/ | "Hello"+ StringEscapeUtils.unescapeJava("\\u0000") +"This is a line" } } diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy index f5406a03fa3..ecec41ce035 100644 --- a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy +++ b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy @@ -1,5 +1,6 @@ package datadog.smoketest +import com.github.javaparser.utils.StringEscapeUtils import okhttp3.FormBody import okhttp3.Request @@ -53,5 +54,7 @@ abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest where: value | expected "withEscape\ttab" | "withEscape" + Character.toString((char)9) + "tab" + "withEscape\nnewline" | "withEscape" + StringEscapeUtils.unescapeJava("\\u000A")+ "newline" + "withEscape\bbackline" | "withEscape" + StringEscapeUtils.unescapeJava("\\u0008")+ "backline" } } From 13965a7f543fce61b5dd269b069dd77e7c4ce2c2 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Wed, 15 Jan 2025 14:38:29 +0100 Subject: [PATCH 20/24] fix formatting --- .../instrumentation/java/lang/jdk15/StringCallSiteTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy index 989a58ce491..bea96f705bd 100644 --- a/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy +++ b/dd-java-agent/instrumentation/java-lang/java-lang-15/src/test/groovy/datadog/trace/instrumentation/java/lang/jdk15/StringCallSiteTest.groovy @@ -31,7 +31,7 @@ class StringCallSiteTest extends AgentTestRunner { where: input | output - "HelloThisisaline" | "HelloThisisaline" + "HelloThisisaline" | "HelloThisisaline" "Hello\tThis is a line" | "Hello"+ StringEscapeUtils.unescapeJava("\\u0009") +"This is a line" /Hello\sThis is a line/ | "Hello"+ StringEscapeUtils.unescapeJava("\\u0020") +"This is a line" /Hello\"This is a line/ | "Hello"+ StringEscapeUtils.unescapeJava("\\u0022") +"This is a line" From 4956aeb02cf9a8c730476ebdbdb748f2a932fa5c Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Wed, 15 Jan 2025 14:41:10 +0100 Subject: [PATCH 21/24] fix formatting --- .../datadog/smoketest/AbstractIast17SpringBootTest.groovy | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy index ecec41ce035..4ac43ea4fc3 100644 --- a/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy +++ b/dd-smoke-tests/iast-util/iast-util-17/src/testFixtures/groovy/datadog/smoketest/AbstractIast17SpringBootTest.groovy @@ -52,9 +52,9 @@ abstract class AbstractIast17SpringBootTest extends AbstractIastServerSmokeTest } where: - value | expected - "withEscape\ttab" | "withEscape" + Character.toString((char)9) + "tab" - "withEscape\nnewline" | "withEscape" + StringEscapeUtils.unescapeJava("\\u000A")+ "newline" - "withEscape\bbackline" | "withEscape" + StringEscapeUtils.unescapeJava("\\u0008")+ "backline" + value | expected + "withEscape\ttab" | "withEscape" + Character.toString((char)9) + "tab" + "withEscape\nnewline" | "withEscape" + StringEscapeUtils.unescapeJava("\\u000A")+ "newline" + "withEscape\bbackline" | "withEscape" + StringEscapeUtils.unescapeJava("\\u0008")+ "backline" } } From 6013e2ab1df730e1de870622c0f9b06c1dd48ded Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Wed, 15 Jan 2025 15:47:54 +0100 Subject: [PATCH 22/24] pr comments --- .../java/com/datadog/iast/propagation/StringModuleImpl.java | 6 +----- .../com/datadog/iast/propagation/StringModuleTest.groovy | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java index 3cc4a153809..69252d40670 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java @@ -311,11 +311,7 @@ public void onStringTranslateEscapes(@Nonnull String self, @Nullable String resu if (taintedSelf == null) { return; // original string is not tainted } - final Range[] rangesSelf = taintedSelf.getRanges(); - if (rangesSelf.length == 0) { - return; // original string is not tainted - } - taintedObjects.taint(result, rangesSelf); // only possibility left + taintedObjects.taint(result, taintedSelf.getRanges()); // only possibility left } @Override diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy index d24b492de48..f8ca533c10a 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy @@ -1418,7 +1418,7 @@ class StringModuleTest extends IastModuleImplTestBase { given: final taintedObjects = ctx.getTaintedObjects() def self = addFromTaintFormat(taintedObjects, testString) - def result = self + def result = self.translateEscapes() when: module.onStringTranslateEscapes(self, result) From 28db26fdbd1510bda76063d2e1f25be453a433c5 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Thu, 16 Jan 2025 09:45:29 +0100 Subject: [PATCH 23/24] revert StringModuleTest.groovy --- .../groovy/com/datadog/iast/propagation/StringModuleTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy index f8ca533c10a..d24b492de48 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy @@ -1418,7 +1418,7 @@ class StringModuleTest extends IastModuleImplTestBase { given: final taintedObjects = ctx.getTaintedObjects() def self = addFromTaintFormat(taintedObjects, testString) - def result = self.translateEscapes() + def result = self when: module.onStringTranslateEscapes(self, result) From 44f3db9c3adab147881077a257b2e689fa0b5380 Mon Sep 17 00:00:00 2001 From: "sezen.leblay" Date: Thu, 16 Jan 2025 09:53:40 +0100 Subject: [PATCH 24/24] add ignore to string translate escapes test if version less than 15 --- .../com/datadog/iast/propagation/StringModuleTest.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy index d24b492de48..c307127d6db 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy @@ -12,6 +12,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan import datadog.trace.bootstrap.instrumentation.api.AgentTracer import groovy.transform.CompileDynamic import org.junit.jupiter.api.Assertions +import spock.lang.IgnoreIf import java.text.SimpleDateFormat @@ -1414,11 +1415,12 @@ class StringModuleTest extends IastModuleImplTestBase { taintFormat(result, taintedObject.getRanges()) == "==>my_input<==" } + @IgnoreIf({ System.getProperty('java.specification.version').toBigDecimal() < 15 }) void 'test translate escapes'() { given: final taintedObjects = ctx.getTaintedObjects() def self = addFromTaintFormat(taintedObjects, testString) - def result = self + def result = self.translateEscapes() when: module.onStringTranslateEscapes(self, result)