From 8680447294663f7036885c3cbef92f75b1230305 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 13 Nov 2025 12:08:32 +0100 Subject: [PATCH 1/9] fix: Workaround for :dd-java-agent:testing coming with a more recent version of jetty --- .../instrumentation/dropwizard/build.gradle | 21 ++++++++++++++----- .../jetty-client-9.1/build.gradle | 19 +++++++++++++---- .../jetty-server-9.0.4/build.gradle | 20 ++++++++++++++---- .../jetty-server-9.0/build.gradle | 20 ++++++++++++++---- .../javax-servlet-3.0/build.gradle | 19 +++++++++++++---- .../javax-servlet-common/build.gradle | 12 ++++++----- .../tomcat/tomcat-5.5/build.gradle | 10 +++++---- 7 files changed, 91 insertions(+), 30 deletions(-) diff --git a/dd-java-agent/instrumentation/dropwizard/build.gradle b/dd-java-agent/instrumentation/dropwizard/build.gradle index 869109f09a7..023a9da368a 100644 --- a/dd-java-agent/instrumentation/dropwizard/build.gradle +++ b/dd-java-agent/instrumentation/dropwizard/build.gradle @@ -6,16 +6,27 @@ dependencies { testImplementation project(':dd-java-agent:instrumentation:rs:jax-rs:jax-rs-annotations:jax-rs-annotations-2') testImplementation project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0') - // Don't want to conflict with jetty from the test server. - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } - // First version with DropwizardTestSupport: testImplementation group: 'io.dropwizard', name: 'dropwizard-testing', version: '0.8.0' testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3' testImplementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner', version: '2.9.10' + constraints { + // Don't want to conflict with jetty from the test server. + testImplementation('org.eclipse.jetty:jetty-server') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '9.2.9.v20150224' + } + } + testImplementation('org.eclipse.jetty:jetty-servlet') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '9.2.9.v20150224' + } + } + } + // Anything 1.0+ fails with a java.lang.NoClassDefFoundError: org/eclipse/jetty/server/RequestLog // latestDepTestImplementation group: 'io.dropwizard', name: 'dropwizard-testing', version: '1.+' } diff --git a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle index 18d30823263..2d64149ab85 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle @@ -51,13 +51,24 @@ dependencies { implementation(project(':dd-java-agent:instrumentation:jetty:jetty-client:jetty-client-common')) { transitive = false } - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - // explicitly declared below. - exclude group: 'org.eclipse.jetty' - } testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31') testImplementation group: 'org.eclipse.jetty', name: 'jetty-client', version: '9.1.0.v20131115' testImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.1.0.v20131115' + constraints { + testImplementation('org.eclipse.jetty:jetty-server') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '9.1.0.v20131115' + } + } + testImplementation('org.eclipse.jetty:jetty-servlet') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '9.1.0.v20131115' + } + } + } + latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-client', version: '9.+' latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+' } diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle index 9d174eb9b5b..23ee96eadf8 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle @@ -17,10 +17,6 @@ dependencies { implementation project(":dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0") compileOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.0.4.v20130625' - // Don't want to conflict with jetty from the test server. - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31') testImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.0.4.v20130625' @@ -30,6 +26,22 @@ dependencies { testImplementation testFixtures(project(":dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0")) testImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')) + constraints { + // Don't want to conflict with jetty from the test server. + testImplementation('org.eclipse.jetty:jetty-server') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '9.0.4.v20130625' + } + } + testImplementation('org.eclipse.jetty:jetty-servlet') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '9.0.4.v20130625' + } + } + } + // Include all jetty-server instrumentation modules for testing. Only the version-compatible module will apply at runtime. testRuntimeOnly project(":dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0") testRuntimeOnly project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-2.2') diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle index d9039758f93..21f98665f96 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle @@ -26,10 +26,7 @@ dependencies { testFixturesImplementation(project(':dd-java-agent:instrumentation-testing')) { exclude group: 'org.eclipse.jetty', module: 'jetty-server' } - // Don't want to conflict with jetty from the test server. - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } + testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31') String jetty9Version = '9.0.0.v20130308' @@ -46,6 +43,21 @@ dependencies { testImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')) testFixturesImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')) testImplementation project(':dd-java-agent:appsec:appsec-test-fixtures') + constraints { + // Don't want to conflict with jetty from the test server. + testImplementation('org.eclipse.jetty:jetty-server') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly jetty9Version + } + } + testImplementation('org.eclipse.jetty:jetty-servlet') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly jetty9Version + } + } + } testFixturesCompileOnly(libs.bundles.groovy) } diff --git a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle index 0ef49c0e83f..9eb188597d1 100644 --- a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle +++ b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle @@ -42,13 +42,9 @@ dependencies { exclude group: 'org.eclipse.jetty', module: 'jetty-server' } testFixturesCompileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' - testFixturesCompileOnly(libs.bundles.groovy) testFixturesCompileOnly(libs.bundles.spock) - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-7.0') // See if there's any conflicts. testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-7.6') // See if there's any conflicts. testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0') // See if there's any conflicts. @@ -66,6 +62,21 @@ dependencies { testImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.0.41' testImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '8.0.41' + constraints { + testImplementation('org.eclipse.jetty:jetty-server') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '8.2.0.v20160908' + } + } + testImplementation('org.eclipse.jetty:jetty-servlet') { + because(":dd-java-agent:testing comes with a newer version that may cause conflicts") + version { + strictly '8.2.0.v20160908' + } + } + } + // Jetty 10 seems to refuse to run on java8. // TODO: we need to setup separate test for Jetty 10 when that is released. latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+' diff --git a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle index 1aff7376d0d..735eb5e76b5 100644 --- a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle +++ b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle @@ -24,10 +24,12 @@ dependencies { // servlet request instrumentation required for linking request to response. testImplementation project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-2.2') - // Don't want to conflict with jetty from the test server. - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } - testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31') } + +configurations.named('testImplementation') { + // Don't want to conflict with jetty from the test server. + // because :dd-java-agent:testing brings its own version of jetty-server + exclude(group: 'org.eclipse.jetty') +} + diff --git a/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle b/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle index 4263aff25f6..f15fe66b27d 100644 --- a/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle +++ b/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle @@ -90,10 +90,6 @@ dependencies { implementation project(':dd-java-agent:instrumentation:tomcat:tomcat-common') - testImplementation(project(':dd-java-agent:instrumentation-testing')) { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } - // Required jars for embedded tomcat: testImplementation group: 'tomcat', name: 'catalina', version: tomcatVersion testImplementation group: 'tomcat', name: 'tomcat-coyote', version: tomcatVersion @@ -147,6 +143,12 @@ tasks.withType(Test).configureEach { ) } +configurations.named('testImplementation') { + // Don't want to conflict with jetty from the test server. + // because :dd-java-agent:testing brings its own version of jetty-server + exclude(group: 'org.eclipse.jetty') +} + // Exclude all the dependencies from test for latestDepTest since the names are completely different. ["latestDepTestImplementation", "tomcat9TestImplementation", "latest10TestImplementation"].each { configurations.named(it) { From be2689987438afe5e92d5e0e79bf2dd6e31b5260 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 15 Dec 2025 18:52:37 +0100 Subject: [PATCH 2/9] fix: Proper shadowing of jetty in agent-testing --- .../instrumentation/dropwizard/build.gradle | 16 ----------- .../jetty-client-9.1/build.gradle | 14 ---------- .../jetty-server-9.0.4/build.gradle | 16 ----------- .../jetty-server-9.0/build.gradle | 15 ----------- .../javax-servlet-3.0/build.gradle | 15 ----------- .../javax-servlet-common/build.gradle | 6 ----- .../tomcat/tomcat-5.5/build.gradle | 6 ----- dd-java-agent/testing/build.gradle | 27 ++++++++++++++++++- 8 files changed, 26 insertions(+), 89 deletions(-) diff --git a/dd-java-agent/instrumentation/dropwizard/build.gradle b/dd-java-agent/instrumentation/dropwizard/build.gradle index 023a9da368a..8198a0abdcb 100644 --- a/dd-java-agent/instrumentation/dropwizard/build.gradle +++ b/dd-java-agent/instrumentation/dropwizard/build.gradle @@ -11,22 +11,6 @@ dependencies { testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3' testImplementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner', version: '2.9.10' - constraints { - // Don't want to conflict with jetty from the test server. - testImplementation('org.eclipse.jetty:jetty-server') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '9.2.9.v20150224' - } - } - testImplementation('org.eclipse.jetty:jetty-servlet') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '9.2.9.v20150224' - } - } - } - // Anything 1.0+ fails with a java.lang.NoClassDefFoundError: org/eclipse/jetty/server/RequestLog // latestDepTestImplementation group: 'io.dropwizard', name: 'dropwizard-testing', version: '1.+' } diff --git a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle index 2d64149ab85..df91fc1874a 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/build.gradle @@ -54,20 +54,6 @@ dependencies { testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31') testImplementation group: 'org.eclipse.jetty', name: 'jetty-client', version: '9.1.0.v20131115' testImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.1.0.v20131115' - constraints { - testImplementation('org.eclipse.jetty:jetty-server') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '9.1.0.v20131115' - } - } - testImplementation('org.eclipse.jetty:jetty-servlet') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '9.1.0.v20131115' - } - } - } latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-client', version: '9.+' latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+' diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle index 23ee96eadf8..e11828e5d8c 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/build.gradle @@ -26,22 +26,6 @@ dependencies { testImplementation testFixtures(project(":dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0")) testImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')) - constraints { - // Don't want to conflict with jetty from the test server. - testImplementation('org.eclipse.jetty:jetty-server') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '9.0.4.v20130625' - } - } - testImplementation('org.eclipse.jetty:jetty-servlet') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '9.0.4.v20130625' - } - } - } - // Include all jetty-server instrumentation modules for testing. Only the version-compatible module will apply at runtime. testRuntimeOnly project(":dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0") testRuntimeOnly project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-2.2') diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle index 21f98665f96..d4ca968c395 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0/build.gradle @@ -43,21 +43,6 @@ dependencies { testImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')) testFixturesImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')) testImplementation project(':dd-java-agent:appsec:appsec-test-fixtures') - constraints { - // Don't want to conflict with jetty from the test server. - testImplementation('org.eclipse.jetty:jetty-server') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly jetty9Version - } - } - testImplementation('org.eclipse.jetty:jetty-servlet') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly jetty9Version - } - } - } testFixturesCompileOnly(libs.bundles.groovy) } diff --git a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle index 9eb188597d1..0010107eb93 100644 --- a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle +++ b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-3.0/build.gradle @@ -62,21 +62,6 @@ dependencies { testImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.0.41' testImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '8.0.41' - constraints { - testImplementation('org.eclipse.jetty:jetty-server') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '8.2.0.v20160908' - } - } - testImplementation('org.eclipse.jetty:jetty-servlet') { - because(":dd-java-agent:testing comes with a newer version that may cause conflicts") - version { - strictly '8.2.0.v20160908' - } - } - } - // Jetty 10 seems to refuse to run on java8. // TODO: we need to setup separate test for Jetty 10 when that is released. latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+' diff --git a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle index 735eb5e76b5..f4a9e1f4c5e 100644 --- a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle +++ b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-common/build.gradle @@ -27,9 +27,3 @@ dependencies { testImplementation project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31') } -configurations.named('testImplementation') { - // Don't want to conflict with jetty from the test server. - // because :dd-java-agent:testing brings its own version of jetty-server - exclude(group: 'org.eclipse.jetty') -} - diff --git a/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle b/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle index f15fe66b27d..8a3b2030cd5 100644 --- a/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle +++ b/dd-java-agent/instrumentation/tomcat/tomcat-5.5/build.gradle @@ -143,12 +143,6 @@ tasks.withType(Test).configureEach { ) } -configurations.named('testImplementation') { - // Don't want to conflict with jetty from the test server. - // because :dd-java-agent:testing brings its own version of jetty-server - exclude(group: 'org.eclipse.jetty') -} - // Exclude all the dependencies from test for latestDepTest since the names are completely different. ["latestDepTestImplementation", "tomcat9TestImplementation", "latest10TestImplementation"].each { configurations.named(it) { diff --git a/dd-java-agent/testing/build.gradle b/dd-java-agent/testing/build.gradle index b280e1b48f9..197546a5d40 100644 --- a/dd-java-agent/testing/build.gradle +++ b/dd-java-agent/testing/build.gradle @@ -38,7 +38,10 @@ dependencies { api libs.bundles.test.logging api libs.guava - api group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' + // Jetty is bundled (relocated) in the shadow jar, not exposed as transitive dependency + // This avoids version conflicts with instrumentation tests that use different jetty versions + compileOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' + runtimeOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' // ^ 9.4 last to support java 8 api group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: libs.versions.okhttp.legacy.get() @@ -55,12 +58,34 @@ dependencies { } tasks.named("shadowJar", ShadowJar) { + // Only bundle jetty dependencies into the jar (relocated) + // All other dependencies remain as transitive dependencies dependencies { include(dependency { it.moduleGroup == 'org.eclipse.jetty' }) } + + // Relocate jetty classes to avoid conflicts with instrumented versions relocate "org.eclipse.jetty", "datadog.eclipse.jetty" + + // Make shadowJar replace the main jar in api configuration + archiveClassifier = '' +} + +// Remove the regular jar from api elements and use shadow jar instead +// Also exclude jetty from being exposed as a transitive dependency (it's bundled in the shadow jar) +configurations { + apiElements { + outgoing.artifacts.clear() + outgoing.artifact(tasks.shadowJar) + exclude group: 'org.eclipse.jetty' + } + runtimeElements { + outgoing.artifacts.clear() + outgoing.artifact(tasks.shadowJar) + exclude group: 'org.eclipse.jetty' + } } tasks.withType(Test).configureEach { From 9deb71507d3cf1811d6d61bbc7ac5f1a61858d7c Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 15 Dec 2025 19:30:38 +0100 Subject: [PATCH 3/9] chore: lockfiles --- .../jetty-client/jetty-client-9.1/gradle.lockfile | 3 +-- .../instrumentation/mule-4.5/gradle.lockfile | 11 +++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/gradle.lockfile b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/gradle.lockfile index 676fb42ab1e..f24ed6368fd 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/gradle.lockfile +++ b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-9.1/gradle.lockfile @@ -82,8 +82,7 @@ org.eclipse.jetty:jetty-http:9.1.0.v20131115=compileClasspath,testCompileClasspa org.eclipse.jetty:jetty-http:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath org.eclipse.jetty:jetty-io:9.1.0.v20131115=compileClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-io:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-server:9.1.0.v20131115=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-server:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.eclipse.jetty:jetty-server:9.1.0.v20131115=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-util:9.1.0.v20131115=compileClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty:jetty-util:9.4.58.v20250814=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath org.gmetrics:GMetrics:2.1.0=codenarc diff --git a/dd-java-agent/instrumentation/mule-4.5/gradle.lockfile b/dd-java-agent/instrumentation/mule-4.5/gradle.lockfile index 8c72c118885..2b4a9565735 100644 --- a/dd-java-agent/instrumentation/mule-4.5/gradle.lockfile +++ b/dd-java-agent/instrumentation/mule-4.5/gradle.lockfile @@ -6,7 +6,7 @@ cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDep cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepForkedTestRuntimeClasspath,main_java11RuntimeClasspath,mule46ForkedTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath ch.qos.logback:logback-classic:1.2.13=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath ch.qos.logback:logback-core:1.2.13=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -ch.randelshofer:fastdoubleparser:0.8.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,mule46Services,muleServices,testCompileClasspath,testRuntimeClasspath +ch.randelshofer:fastdoubleparser:0.8.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.beust:jcommander:1.78=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.beust:jcommander:1.82=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,instrumentPluginClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,main_java11CompileClasspath,main_java11RuntimeClasspath,mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath @@ -21,7 +21,8 @@ com.datadoghq:dd-javac-plugin-client:0.2.2=compileClasspath,instrumentPluginClas com.datadoghq:java-dogstatsd-client:4.4.3=instrumentPluginClasspath,latestDepForkedTestRuntimeClasspath,main_java11RuntimeClasspath,mule46ForkedTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,latestDepForkedTestRuntimeClasspath,main_java11RuntimeClasspath,mule46ForkedTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath com.fasterxml.jackson.core:jackson-annotations:2.10.0=compileClasspath -com.fasterxml.jackson.core:jackson-annotations:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,mule46Services,muleServices,testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.12.7=mule46Services,muleServices +com.fasterxml.jackson.core:jackson-annotations:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.fasterxml.jackson.core:jackson-annotations:2.16.1=latestMuleServices com.fasterxml.jackson.core:jackson-annotations:2.19.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath com.fasterxml.jackson.core:jackson-core:2.10.0=compileClasspath @@ -29,7 +30,8 @@ com.fasterxml.jackson.core:jackson-core:2.15.0=mule46ForkedTestCompileClasspath, com.fasterxml.jackson.core:jackson-core:2.16.1=latestMuleServices com.fasterxml.jackson.core:jackson-core:2.19.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath com.fasterxml.jackson.core:jackson-databind:2.10.0=compileClasspath -com.fasterxml.jackson.core:jackson-databind:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,mule46Services,muleServices,testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.12.7=mule46Services,muleServices +com.fasterxml.jackson.core:jackson-databind:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.fasterxml.jackson.core:jackson-databind:2.16.1=latestMuleServices com.fasterxml.jackson.core:jackson-databind:2.19.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath @@ -37,7 +39,8 @@ com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.19.2=latestDepForkedT com.fasterxml.jackson.module:jackson-module-jsonSchema:2.10.0=compileClasspath com.fasterxml.jackson.module:jackson-module-jsonSchema:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.fasterxml.jackson.module:jackson-module-jsonSchema:2.19.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath -com.fasterxml.jackson:jackson-bom:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,mule46Services,muleServices,testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson:jackson-bom:2.12.7=mule46Services,muleServices +com.fasterxml.jackson:jackson-bom:2.15.0=mule46ForkedTestCompileClasspath,mule46ForkedTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.fasterxml.jackson:jackson-bom:2.16.1=latestMuleServices com.fasterxml.jackson:jackson-bom:2.19.2=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath com.fasterxml.woodstox:woodstox-core:6.4.0=mule46Services,muleServices From 73e0938ab27305d529e34f8785eed42d986d59ad Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 15 Dec 2025 21:41:18 +0100 Subject: [PATCH 4/9] fix: jsp instrumentation needlessly requiring jetty http status --- .../groovy/JSPInstrumentationBasicTests.groovy | 17 ++++++++--------- .../JSPInstrumentationForwardTests.groovy | 13 ++++++------- .../jsp-2.3/src/test/groovy/JSPTestBase.groovy | 5 +++++ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy index 884e4faef9c..425cc28b15e 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy +++ b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy @@ -6,7 +6,6 @@ import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response import org.apache.jasper.JasperException -import org.eclipse.jetty.http.HttpStatus class JSPInstrumentationBasicTests extends JSPTestBase { def "non-erroneous GET #test test"() { @@ -72,7 +71,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -149,7 +148,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -222,7 +221,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -305,7 +304,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.INTERNAL_SERVER_ERROR_500 + res.code() == HTTP_INTERNAL_ERROR cleanup: res.close() @@ -380,7 +379,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -503,7 +502,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -561,7 +560,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { } } } - res.code() == HttpStatus.INTERNAL_SERVER_ERROR_500 + res.code() == HTTP_INTERNAL_ERROR cleanup: res.close() @@ -581,7 +580,7 @@ class JSPInstrumentationBasicTests extends JSPTestBase { Response res = client.newCall(req).execute() then: - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK assertTraces(1) { trace(1) { span { diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy index a236943f945..248be190967 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy +++ b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy @@ -3,7 +3,6 @@ import datadog.trace.bootstrap.instrumentation.api.Tags import okhttp3.Request import okhttp3.Response import org.apache.jasper.JasperException -import org.eclipse.jetty.http.HttpStatus class JSPInstrumentationForwardTests extends JSPTestBase { def "non-erroneous GET forward to #forwardTo"() { @@ -97,7 +96,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -171,7 +170,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -324,7 +323,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -449,7 +448,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase { } } } - res.code() == HttpStatus.OK_200 + res.code() == HTTP_OK cleanup: res.close() @@ -535,7 +534,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase { } } } - res.code() == HttpStatus.INTERNAL_SERVER_ERROR_500 + res.code() == HTTP_INTERNAL_ERROR cleanup: res.close() @@ -604,7 +603,7 @@ class JSPInstrumentationForwardTests extends JSPTestBase { } } } - res.code() == HttpStatus.NOT_FOUND_404 + res.code() == HTTP_NOT_FOUND cleanup: res.close() diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPTestBase.groovy b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPTestBase.groovy index c23ec30388d..dbf884951db 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPTestBase.groovy +++ b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPTestBase.groovy @@ -26,6 +26,11 @@ abstract class JSPTestBase extends InstrumentationSpecification { OkHttpClient client = OkHttpUtils.client() + // HTTP status code constants + static final int HTTP_OK = 200 + static final int HTTP_NOT_FOUND = 404 + static final int HTTP_INTERNAL_ERROR = 500 + @Override void configurePreAgent() { super.configurePreAgent() From 0f91d4f0559b4cf1a3c0474cf58e111d08fe602e Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 15 Dec 2025 21:41:51 +0100 Subject: [PATCH 5/9] fix: Exports servlet request api This was lost when jetty server got shadowed. --- dd-java-agent/testing/build.gradle | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dd-java-agent/testing/build.gradle b/dd-java-agent/testing/build.gradle index 197546a5d40..10b8c6e1a46 100644 --- a/dd-java-agent/testing/build.gradle +++ b/dd-java-agent/testing/build.gradle @@ -38,11 +38,14 @@ dependencies { api libs.bundles.test.logging api libs.guava - // Jetty is bundled (relocated) in the shadow jar, not exposed as transitive dependency - // This avoids version conflicts with instrumentation tests that use different jetty versions + // Do not expose jetty as a transitive dependency, as it conflicts + // with versions used to test instrumentions. + // Note: 9.4 last to support java 8 compileOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' runtimeOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' - // ^ 9.4 last to support java 8 + // Since jetty-server is shadowed, it is needed to exports the servlet api as well. + api group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' + api group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: libs.versions.okhttp.legacy.get() api project(':dd-java-agent:agent-tooling') From 2b6b84d0fae681eef0aa3eb908e5e0e3c9f57b90 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 15 Dec 2025 22:28:14 +0100 Subject: [PATCH 6/9] fix: Use config lazy API --- dd-java-agent/testing/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/testing/build.gradle b/dd-java-agent/testing/build.gradle index 10b8c6e1a46..29da06f6e0c 100644 --- a/dd-java-agent/testing/build.gradle +++ b/dd-java-agent/testing/build.gradle @@ -79,14 +79,14 @@ tasks.named("shadowJar", ShadowJar) { // Remove the regular jar from api elements and use shadow jar instead // Also exclude jetty from being exposed as a transitive dependency (it's bundled in the shadow jar) configurations { - apiElements { + named('apiElements') { outgoing.artifacts.clear() - outgoing.artifact(tasks.shadowJar) + outgoing.artifact(tasks.named('shadowJar')) exclude group: 'org.eclipse.jetty' } - runtimeElements { + named('runtimeElements') { outgoing.artifacts.clear() - outgoing.artifact(tasks.shadowJar) + outgoing.artifact(tasks.named('shadowJar')) exclude group: 'org.eclipse.jetty' } } From 612bea1952d29d1013e049b67f8d1fb3bc207d38 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Tue, 16 Dec 2025 07:52:52 +0100 Subject: [PATCH 7/9] chore: Make spotless happy --- dd-java-agent/testing/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/testing/build.gradle b/dd-java-agent/testing/build.gradle index 29da06f6e0c..ed8937cda2b 100644 --- a/dd-java-agent/testing/build.gradle +++ b/dd-java-agent/testing/build.gradle @@ -45,7 +45,7 @@ dependencies { runtimeOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' // Since jetty-server is shadowed, it is needed to exports the servlet api as well. api group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' - + api group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: libs.versions.okhttp.legacy.get() api project(':dd-java-agent:agent-tooling') From 681b9df566bf6f4568ca3db8d5c146c4951209c3 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Tue, 16 Dec 2025 18:47:59 +0100 Subject: [PATCH 8/9] fix: Replaces testing http client by raw jetty in Apache Http Client instrumentation Now that :dd-java-agent:testing shadows jetty, the jetty instrumentation was not applied. --- .../apache-httpclient-4.0/build.gradle | 5 +- .../IastHttpClientIntegrationTest.groovy | 109 ++++++++++++------ .../java/foo/bar/VulnerableUrlBuilder.java | 13 ++- 3 files changed, 85 insertions(+), 42 deletions(-) diff --git a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/build.gradle b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/build.gradle index abe5715cc11..2b83612aea0 100644 --- a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/build.gradle +++ b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/build.gradle @@ -39,9 +39,12 @@ dependencies { // to instrument the integration test iastIntegrationTestImplementation project(':dd-java-agent:agent-iast:iast-test-fixtures') iastIntegrationTestImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0' - iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0')) + // Provide real (non-shadowed) jetty for the test server bootstrap + iastIntegrationTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.56.v20240826' + iastIntegrationTestImplementation group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.4.56.v20240826' iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:apache-httpcore:apache-httpcore-4.0')) iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-common')) + iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0')) iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:java:java-lang:java-lang-1.8')) iastIntegrationTestRuntimeOnly(project(':dd-java-agent:instrumentation:java:java-net:java-net-1.8')) iastIntegrationTestRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') diff --git a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy index 75a666fac3c..32fd51a1a15 100644 --- a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy +++ b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy @@ -5,10 +5,16 @@ import datadog.trace.agent.test.base.HttpServer import foo.bar.VulnerableUrlBuilder import okhttp3.HttpUrl import okhttp3.Request +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.server.ServerConnector +import org.eclipse.jetty.servlet.ServletContextHandler +import org.eclipse.jetty.servlet.ServletHolder -import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer +import javax.servlet.http.HttpServlet +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse -class IastHttpClientIntegrationTest extends IastHttpServerTest { +class IastHttpClientIntegrationTest extends IastHttpServerTest { static final CLIENTS = [ 'org.apache.http.impl.client.AutoRetryHttpClient', @@ -20,20 +26,51 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { @Override HttpServer server() { final controller = new SsrfController() - return httpServer { - handlers { - prefix('/ssrf/execute') { - final msg = controller.apacheSsrf( - VulnerableUrlBuilder.url(request), - (String) request.getParameter('clientClassName'), - (String) request.getParameter('method'), - (String) request.getParameter('requestType'), - (String) request.getParameter('scheme') - ) - response.status(200).send(msg) - } + + // Use _raw_ jetty API, so the jetty instrumentation is applied + // (the :dd-java-agent:testing has a shadowed jetty server.) + return new HttpServer() { + Server jettyServer + int port + + @Override + void start() { + jettyServer = new Server(0) // 0 = random port + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS) + context.setContextPath('/') + jettyServer.setHandler(context) + + // Add servlet for the /ssrf/execute endpoint + context.addServlet(new ServletHolder(new HttpServlet() { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + final msg = controller.apacheSsrf( + VulnerableUrlBuilder.url(req), + req.getParameter('clientClassName'), + req.getParameter('method'), + req.getParameter('requestType'), + req.getParameter('scheme') + ) + resp.setStatus(200) + resp.writer.write(msg) + } + }), '/ssrf/execute') + + jettyServer.start() + port = ((ServerConnector) jettyServer.connectors[0]).localPort } - }.asHttpServer() + + @Override + void stop() { + jettyServer?.stop() + } + + @Override + URI address() { + return new URI("http://localhost:${port}/") + } + } } void 'ssrf is present: #suite'() { @@ -41,7 +78,6 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { final url = suite.url(address) final request = new Request.Builder().url(url).get().build() - when: def response = client.newCall(request).execute() @@ -52,6 +88,9 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { assert to != null hasVulnerability(vul -> vul.type == VulnerabilityType.SSRF && suite.evidenceMatches(vul.evidence)) + cleanup: + response?.close() + where: suite << createTestSuite() } @@ -73,12 +112,12 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { private List createTestSuite(client, method, request, scheme) { return TaintedTarget.values().collect { new TestSuite( - description: "Tainted ${it.name()} with ${client} client and ${method} method with ${request} and ${scheme} scheme", - executedMethod: method.name(), - clientImplementation: client, - requestType: request.name(), - scheme: scheme, - tainted: it + description: "Tainted ${it.name()} with ${client} client and ${method} method with ${request} and ${scheme} scheme", + executedMethod: method.name(), + clientImplementation: client, + requestType: request.name(), + scheme: scheme, + tainted: it ) } } @@ -106,14 +145,14 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { HttpUrl url(final URI address) { final builder = new HttpUrl.Builder() - .scheme(address.getScheme()) - .host(address.getHost()) - .port(address.getPort()) - .addPathSegments('ssrf/execute') - .addQueryParameter('clientClassName', clientImplementation) - .addQueryParameter('method', executedMethod) - .addQueryParameter('requestType', requestType) - .addQueryParameter('scheme', scheme) + .scheme(address.getScheme()) + .host(address.getHost()) + .port(address.getPort()) + .addPathSegments('ssrf/execute') + .addQueryParameter('clientClassName', clientImplementation) + .addQueryParameter('method', executedMethod) + .addQueryParameter('requestType', requestType) + .addQueryParameter('scheme', scheme) tainted.addTainted(builder, this) return builder.build() } @@ -129,7 +168,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { } private static enum TaintedTarget { - URL{ + URL { void addTainted(HttpUrl.Builder builder, TestSuite suite) { builder.addQueryParameter('url', suite.scheme + '://inexistent/test?1=1') } @@ -138,7 +177,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { return assertTainted(evidence, 'url', suite.scheme + '://inexistent/test?1=1') } }, - SCHEME{ + SCHEME { void addTainted(HttpUrl.Builder builder, TestSuite suite) { // already added by the test } @@ -147,7 +186,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { return assertTainted(evidence, 'scheme', suite.scheme) } }, - HOST{ + HOST { void addTainted(HttpUrl.Builder builder, TestSuite suite) { builder.addQueryParameter('host', 'inexistent') } @@ -156,7 +195,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { return assertTainted(evidence, 'host', 'inexistent') } }, - PATH{ + PATH { void addTainted(HttpUrl.Builder builder, TestSuite suite) { builder.addQueryParameter('path', '/test') } @@ -165,7 +204,7 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { return assertTainted(evidence, 'path', '/test') } }, - QUERY{ + QUERY { void addTainted(HttpUrl.Builder builder, TestSuite suite) { builder.addQueryParameter('query', '?1=1') } diff --git a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java index 9ffaa78b9bb..2ad0569a09e 100644 --- a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java +++ b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java @@ -1,28 +1,29 @@ package foo.bar; import datadog.trace.agent.test.server.http.TestHttpServer.HandlerApi.RequestApi; +import javax.servlet.http.HttpServletRequest; /** Class to be instrumented by IAST call sites containing methods to work with urls */ public abstract class VulnerableUrlBuilder { private VulnerableUrlBuilder() {} - public static String url(RequestApi request) { - final String url = (String) request.getParameter("url"); + public static String url(HttpServletRequest request) { + final String url = request.getParameter("url"); if (url != null) { return url; } - final String scheme = (String) request.getParameter("scheme"); + final String scheme = request.getParameter("scheme"); final boolean https = "https".equals(scheme); - final String host = (String) request.getParameter("host"); + final String host = request.getParameter("host"); if (host != null) { return (https ? "https://" : "http://") + host + "/test?1=1"; } - final String path = (String) request.getParameter("path"); + final String path = request.getParameter("path"); if (path != null) { return (https ? "https://inexistent/" : "http://inexistent/") + path + "?1=1"; } - final String query = (String) request.getParameter("query"); + final String query = request.getParameter("query"); if (query != null) { return (https ? "https://inexistent/test" : "http://inexistent/test") + query; } From 9f78da25d1b89e2ad84c8e0aaaa72b3cb2280cdc Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Tue, 16 Dec 2025 21:19:13 +0100 Subject: [PATCH 9/9] chore: Make spotless happy --- .../IastHttpClientIntegrationTest.groovy | 38 +++++++++---------- .../java/foo/bar/VulnerableUrlBuilder.java | 1 - 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy index 32fd51a1a15..d13904a55cb 100644 --- a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy +++ b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/groovy/IastHttpClientIntegrationTest.groovy @@ -46,11 +46,11 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) { final msg = controller.apacheSsrf( - VulnerableUrlBuilder.url(req), - req.getParameter('clientClassName'), - req.getParameter('method'), - req.getParameter('requestType'), - req.getParameter('scheme') + VulnerableUrlBuilder.url(req), + req.getParameter('clientClassName'), + req.getParameter('method'), + req.getParameter('requestType'), + req.getParameter('scheme') ) resp.setStatus(200) resp.writer.write(msg) @@ -112,12 +112,12 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { private List createTestSuite(client, method, request, scheme) { return TaintedTarget.values().collect { new TestSuite( - description: "Tainted ${it.name()} with ${client} client and ${method} method with ${request} and ${scheme} scheme", - executedMethod: method.name(), - clientImplementation: client, - requestType: request.name(), - scheme: scheme, - tainted: it + description: "Tainted ${it.name()} with ${client} client and ${method} method with ${request} and ${scheme} scheme", + executedMethod: method.name(), + clientImplementation: client, + requestType: request.name(), + scheme: scheme, + tainted: it ) } } @@ -145,14 +145,14 @@ class IastHttpClientIntegrationTest extends IastHttpServerTest { HttpUrl url(final URI address) { final builder = new HttpUrl.Builder() - .scheme(address.getScheme()) - .host(address.getHost()) - .port(address.getPort()) - .addPathSegments('ssrf/execute') - .addQueryParameter('clientClassName', clientImplementation) - .addQueryParameter('method', executedMethod) - .addQueryParameter('requestType', requestType) - .addQueryParameter('scheme', scheme) + .scheme(address.getScheme()) + .host(address.getHost()) + .port(address.getPort()) + .addPathSegments('ssrf/execute') + .addQueryParameter('clientClassName', clientImplementation) + .addQueryParameter('method', executedMethod) + .addQueryParameter('requestType', requestType) + .addQueryParameter('scheme', scheme) tainted.addTainted(builder, this) return builder.build() } diff --git a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java index 2ad0569a09e..a8b793a15b1 100644 --- a/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java +++ b/dd-java-agent/instrumentation/apache-httpclient/apache-httpclient-4.0/src/iastIntegrationTest/java/foo/bar/VulnerableUrlBuilder.java @@ -1,6 +1,5 @@ package foo.bar; -import datadog.trace.agent.test.server.http.TestHttpServer.HandlerApi.RequestApi; import javax.servlet.http.HttpServletRequest; /** Class to be instrumented by IAST call sites containing methods to work with urls */