Migrate dd-trace-core groovy files to java part 12#11662
Open
jpbempel wants to merge 212 commits into
Open
Conversation
jpbempel
force-pushed
the
jpbempel/g2j-core-pt12
branch
from
June 17, 2026 11:15
2cc67b3 to
35a718a
Compare
Contributor
|
🎯 Code Coverage (details) 🔗 Commit SHA: 4d30733 | Docs | Datadog PR Page | Give us feedback! |
Contributor
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
…he kafka-connect-0.11 muzzle range: 7.5.15, 7.6.12, 7.7.10, 7.8.9, 7.9.8 (both -ce and -ccs). Same as we did in #11377. (#11668) Skip the latest broken org.apache.kafka:connect-runtime versions in the kafka-connect-0.11 muzzle range: 7.5.15, 7.6.12, 7.7.10, 7.8.9, 7.9.8 (both -ce and -ccs). Same as we did in #11377. Co-authored-by: alexey.kuznetsov <alexey.kuznetsov@datadoghq.com>
…REPORT_TIMEOUT config keys (#11664) remove(appsec): delete dead DD_APPSEC_REPORTING_INBAND and DD_APPSEC_REPORT_TIMEOUT config keys Both config keys were introduced in 2021 (reporting inband in #1d1fc13, report timeout in #2fd53d8) but the classes that consumed them (InbandReportServiceImpl and ReportServiceImpl) were subsequently removed. The getters isAppSecReportingInband(), getAppSecReportMinTimeout() and getAppSecReportMaxTimeout() are now dead code — no caller exists in the codebase. Remove the constants, defaults, fields, assignments and getters. Refs: APPSEC-68459 remove(appsec): delete dead DD_APPSEC_REPORTING_INBAND and DD_APPSEC_REPORT_TIMEOUT from supported-configurations metadata Follow-up to the previous commit removing these keys from Config.java. The metadata/supported-configurations.json entries for DD_APPSEC_REPORTING_INBAND and DD_APPSEC_REPORT_TIMEOUT were still advertising these config keys as supported, which caused GeneratedSupportedConfigurations to include them even though Config no longer reads them. Merge branch 'master' into alejandro.gonzalez/APPSEC-68459-remove-dead-appsec-config Merge branch 'master' into alejandro.gonzalez/APPSEC-68459-remove-dead-appsec-config Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
fix muzzle guard in vertx5 to not exclude 5.1 also exclude iast forked latest tests Merge branch 'master' into vandonr/vertx51 Co-authored-by: raphael.vandon <raphael.vandon@datadoghq.com>
Improved report to be more human-readable. Co-authored-by: alexey.kuznetsov <alexey.kuznetsov@datadoghq.com>
…ps all other elements. (#11672) Fix bug where calling 'context.with((ImplicitContextKeyed) null)' drops all other elements. Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
refactor: Apply normalization on every project
perf: Insulate the BuildTimeInstrumentationPlugin from changes using a ClasspathNormalizer
BuildTimeInstrumentationPlugin install a post-processing step onto
normal compile tasks.
Flow:
1. It creates a resolvable `buildTimeInstrumentationPlugin`
configuration
2. For each main `compileJava` / `compileGroovy` / `compileScala` task,
it registers that configuration as a **compile-task input**
3. Then appends a `doLast("instrumentClasses", ...)` action to
post-process compiled classes. That action runs Byte Buddy plugins
against the compiled class output.
If any input for that task changes, the whole compile task reruns.
In particular the Byte Buddy plugins are tracked via
```kotlin
inputs.files(project.configurations.named(BUILD_TIME_INSTRUMENTATION_PLUGIN_CONFIGURATION))
```
In particular instrumentation plugins rely on instrumentation plugins
coming from `agent-tooling` project which also happens to have a version
file
```Gradle
subProj.configurations.named('buildTimeInstrumentationPlugin') {
it.dependencies.add(subProj.dependencies.project(
path: ':dd-java-agent:agent-tooling',
configuration: 'buildTimeInstrumentationToolingPlugins'
))
```
Before the normalizer, Gradle hashed the full jar contents of the
build-time instrumentation plugin classpath. And as such the jars on
that configuration changed only because their generated *.version
changed after a new Git commit. And as such invalidated the task output.
Adding the normalizer to this input only teaches Gradle to use the
normalizaton declared in the project to ignore the version file on
this input.
Important nuance: `ClasspathNormalizer` is better than
`CompileClasspathNormalizer` here. These are Byte Buddy plugins executed
at build time, so method-body/resource changes in those plugin jars
can change generated bytecode. We only want to ignore the known
volatile version resource.
---
Before this change the compile task amounted to a significant part when
only the commit version changed
```
327.901s compile*
10.486s codenarcTest
9.576s *Jar
8.217s process*Resources
2.208s expandAgentShadowJar*
2.032s generate*Index
1.241s writeVersionNumberFile
```
After this change
```
14.780s compile* # up-to-date checking, not recompilation
7.469s process*Resources
6.194s *Jar
5.056s codenarcTest
2.233s writeVersionNumberFile
1.847s generate*Index
0.899s expandAgentShadowJar*
```
Co-authored-by: brice.dutheil <brice.dutheil@datadoghq.com>
Ignore capturing connection continuation for armeria Co-authored-by: andrea.marziali <andrea.marziali@datadoghq.com>
…e PR. (#11676) Fix new instrumentation lock files leaking into core dependency-update PR. Co-authored-by: alexey.kuznetsov <alexey.kuznetsov@datadoghq.com>
chore(build): Bump Gradle to 9.6.0 fix(test): update dependencies report assertion for Gradle 9.6 project path quoting Gradle 9.6 wraps project paths in single quotes in the dependencies report output: `project ':dd-java-agent:agent-bootstrap'` instead of the previous `project :dd-java-agent:agent-bootstrap`. Drop the `project` prefix from the assertion so the check matches both formats. fix(sofarpc): force netty-all to 4.1.79 to resolve classpath conflict under Gradle 9.6 The `sofa-rpc-all:5.14.2` brings `netty-all:4.1.44.Final`, which is a fat jar, while `grpc-netty:1.53.0` brings individual `netty-*:4.1.79.Final` modules. Gradle 9.6.0 introduced a regression in the classpath ordering, as they are working on revamping the dependency traversal. The result is that the `4.1.44` fat jar classes appears earlier and its classes are loaded from it ; This produces a `NoSuchMethodError` at runtime in netty's `AbstractReferenceCountedByteBuf`. The workaround is to force `netty-all` to `4.1.79` so the fat jar and the individual modules are aligned on the same version. This should be fixed in 9.7.0 and consequently removed from the `resolutionStrategy`. See gradle/gradle#38057 refactor(build): Migrate away from property delegate (deprecated in 9.6.0) Gradle 9.6.0 deprecates a few old API, unfortunately Kotlin property delegates are part of the bag. gradle/gradle#37555 gradle/gradle#37556 https://docs.gradle.org/current/userguide/upgrading_version_9.html#kotlin_dsl_delegated_properties chore(build): Bump Gradle version in GitLab CI cache config to 9.6.0 Co-authored-by: brice.dutheil <brice.dutheil@datadoghq.com>
chore: Update Gradle dependencies Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: bruce.bujon <bruce.bujon@datadoghq.com>
feat(core): Improve http codec extractor tests Extract the ContextInterpreter tests related to AppSec to remove duplication. Handle extractor initialization in a new parent test class Deduplicate constants and values into the new parent test class Co-authored-by: bruce.bujon <bruce.bujon@datadoghq.com>
Improve crash report message when signal is absent Co-authored-by: andrea.marziali <andrea.marziali@datadoghq.com>
Remove testcontainer dependencies for buildId tests Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
chore: Update smoke test latest tool versions Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> fix: filter RC and milestone versions for maven ci: bump surefire version to 3.5.6 Co-authored-by: daniel-mohedano <daniel.mohedano@datadoghq.com>
feat(core): Improve http codec injector tests Co-authored-by: bruce.bujon <bruce.bujon@datadoghq.com>
Instrument Jetty for server.request.body.filenames Add GetFilenamesAdvice to all three Jetty AppSec modules to collect uploaded file names from multipart requests and fire the requestFilesFilenames() IG callback: - jetty-appsec-8.1.3: intercepts getParts() return value; includes Content-Disposition header fallback for Servlet 3.0 (Jetty 9.0) where getSubmittedFileName() is not available - jetty-appsec-9.2: intercepts no-arg getParts() for Servlet 3.1+ - jetty-appsec-9.3: same, applies to Jetty 9.3, 10, 11 Enable testBodyFilenames() in Jetty 9.x, 10 and 11 server tests. Fix GetFilenamesAdvice double-firing and extend coverage to getParts(MultiMap) path - jetty-appsec-9.3: add call-depth guard (Collection.class) to GetFilenamesAdvice to prevent double callback invocation when getParts() calls getParts(MultiMap) internally - jetty-appsec-9.2: extend GetFilenamesAdvice matcher to all getParts overloads (not just no-arg) to cover getParameter*()/getParameterMap() code paths, guarded with same call-depth mechanism to avoid double-firing spotless Extend testBodyFilenamesCalledOnce coverage to Jetty 9.x and 10.x - Add BODY_MULTIPART_REPEATED case to TestServlet3 (javax) so Jetty 9.x/10.x test modules can exercise the repeated getParts() scenario - Enable testBodyFilenamesCalledOnce() for Jetty 9.0, 9.0.4, 9.3, 9.4.21, and 10.0 Add BODY_MULTIPART_COMBINED test to cover GetFilenamesFromMultiPartAdvice path - New BODY_MULTIPART_COMBINED endpoint: calls getParameterMap() first (triggers GetFilenamesFromMultiPartAdvice via extractContentParameters -> getParts(MultiMap)), then getParts() explicitly (GetFilenamesAdvice must not double-fire since _contentParameters is already set) - New test 'file upload filenames called once via parameter map' verifies the callback fires exactly once across both advice paths - Enabled in Jetty 9.0, 9.0.4, 9.3, 9.4.21, 10.0 and 11.0 spotless Fix missing static imports for BODY_MULTIPART_REPEATED and BODY_MULTIPART_COMBINED Fix GetFilenamesAdvice double-fire for Jetty 9.4+ where _multiParts replaces _contentParameters as the getParts() cache In Jetty 9.3, getParts(MultiMap) sets _contentParameters, so the map==null guard prevents re-firing on repeated getParts() calls. In Jetty 9.4+, getParts() delegates to getParts(null) and caches the result in _multiParts instead, leaving _contentParameters null on every call. Add _multiParts==null as an additional guard (optional=true handles Jetty 9.3 where the field does not exist). Fix GetFilenamesAdvice double-fire in jetty-appsec-8.1.3 In Jetty 8.x/9.0, _multiPartInputStream is null only on the first getParts() call. Add OnMethodEnter guard to skip the WAF callback on subsequent calls which return the cached multipart result. Fix GetFilenamesAdvice double-fire for all Jetty 9.3–11 versions @advice.FieldValue(optional=true) is not supported in ByteBuddy 1.11.22. Replace it with @Advice.This + inline reflection to detect whether getParts() has already been called on this request: - Jetty 9.4+: checks _multiParts (set after first getParts() call) - Jetty 9.3.x: falls back to _multiPartInputStream (the cache field in 9.3.x, where _multiParts does not exist and _contentParameters is only set by the getParameterMap() → extractContentParameters() path, not by getParts()) Covers all forkedTest and latestDepForkedTest suites for Jetty 9.0–11. Simplify GetFilenamesAdvice in jetty-appsec-8.1.3: remove dead Servlet 3.1+ branch Jetty 8 implements only Servlet 3.0, so getSubmittedFileName() is never present on the Part objects. The reflection probe (try { getMethod("getSubmittedFileName") }) and the Servlet 3.1+ code path were dead code. Remove them and always parse filenames from the Content-Disposition header directly. Remove unnecessary casts in Jetty AppSec GetFilenamesAdvice Type @Advice.Return as Collection<Part> so the loop variable can be Part directly, eliminating the (Part) cast on each iteration. Extract Content-Disposition parsing to MultipartHelper + unit tests Move the filename extraction logic from GetFilenamesAdvice into a new MultipartHelper helper class so it can be unit tested in isolation. Add 12 Spock test cases covering quoted/unquoted filenames, empty values, whitespace, null input, and edge cases. Extract filename extraction to MultipartHelper in jetty-appsec-9.2 + unit tests Move the getSubmittedFileName() loop from GetFilenamesAdvice into a new MultipartHelper helper class (injected via helperClassNames) so it can be unit tested in isolation. Add 8 Spock test cases covering null/empty collections, null/empty filenames, multiple parts, and special characters. Split jetty-appsec-9.3 [9.3,12) into three clean modules: 9.3, 9.4, 11.0 Eliminates all reflection from the multipart filename instrumentation by creating version-specific modules with compile-time type safety: - jetty-appsec-9.3 [9.3,9.4): javax.servlet, uses _multiPartInputStream field - jetty-appsec-9.4 [9.4,11.0): javax.servlet, uses _multiParts field - jetty-appsec-11.0 [11.0,12.0): jakarta.servlet, uses _multiParts field Each module uses muzzle references as version discriminators instead of runtime reflection, and delegates filename extraction to a testable MultipartHelper class with 8 Spock unit tests each. Server test modules updated to reference the correct appsec module per Jetty version range. Add Jetty 8.x integration tests for multipart body and filenames - Add Jetty8LatestDepForkedTest: runs against Jetty 8.x (latestDepForkedTest task) and enables testBodyMultipart/testBodyFilenames coverage. Gated by 'test.dd.filenames' system property so it is skipped when running against Jetty 7.6. - Add testCompileOnly dep on org.eclipse.jetty.orbit:javax.servlet so MultipartConfigElement compiles without pulling in the excluded javax.servlet:javax.servlet-api artifact. - Fix ParameterCollector.put to accept (Object, Object) and cast internally: Jetty 8.x MultiMap.add uses (Object, Object) descriptor while Jetty 9.x uses (String, Object), so the ASM bytecode visitor was silently skipping all form field captures on Jetty 8. - Update GetPartsMethodVisitor to match both (String,Object) and (Object,Object) MultiMap.add descriptors and emit the INVOKEINTERFACE with (Object, Object). Fix muzzle range for jetty-appsec-9.3/9.4: split at 9.4.10 _multiPartInputStream was replaced by _multiParts in Jetty 9.4.10.v20180503. Early 9.4.x versions (9.4.0–9.4.9) still use _multiPartInputStream like 9.3.x, so extend jetty-appsec-9.3 to cover [9.3, 9.4.10) and narrow jetty-appsec-9.4 to [9.4.10, 11.0). The classLoaderMatcher in jetty-appsec-9.4 (checking for _multiParts) now correctly matches only versions >= 9.4.10. Replace MultiPartsFieldMatcher with typed module splits for Jetty 9.4–11.x The _multiParts field type changes multiple times across Jetty versions, making a single typed muzzle reference insufficient. Replace the ASM-based classLoaderMatcher with clean module splits using typed muzzle references: - jetty-appsec-9.4 [9.4.10, 10.0): _multiParts: MultiParts _queryEncoding: String (excludes 10.x) - jetty-appsec-10.0 [10.0, 10.0.10): _multiParts: MultiPartFormInputStream - jetty-appsec-10.0.10 [10.0.10, 11.0): _multiParts: MultiParts _queryEncoding: Charset (excludes 9.4.x) - jetty-appsec-11.0 [11.0, 11.0.10): _multiParts: MultiPartFormInputStream - jetty-appsec-11.0.10 [11.0.10, 12.0): _multiParts: MultiParts All six modules pass muzzle with assertInverse = true. Fix CI failures and reduce agent JAR size for Jetty filenames PR - Add jetty-appsec-9.4 and jetty-appsec-11.0 to armeria-jetty-1.24 testRuntimeOnly classpath; these are required after the muzzle split that tightened jetty-appsec-9.3 to [9.3, 9.4.10) - Merge jetty-appsec-10.0 functionality into jetty-appsec-9.4: extend the muzzle from [9.4.10, 10.0) to also cover [10.0.10, 11.0) using _multiParts:MultiParts + javax.servlet.http.Part as discriminators; delete the now-redundant jetty-appsec-10.0 module - Delete intermediate modules jetty-appsec-10.0.10 and jetty-appsec-11.0.10 that were split-by-point-release and now handled by the two modules above - Scope server.request.body.filenames to Jetty 9.3+: revert filenames additions from jetty-appsec-8.1.3 (Jetty 8, EOL 2015) and jetty-appsec-9.2 (Jetty 9.2, EOL 2019) to stay within the 32 MiB agent JAR limit; requestBodyProcessed support for those versions is unchanged Agent JAR: 33,551,402 bytes (3,030 bytes under the 32 MiB limit) Remove redundant .or(named("getParts")) from ExtractContentParametersAdvice matcher ExtractContentParametersAdvice applied to getParts() is always a no-op: it increments/decrements CallDepthThreadLocalMap but never fires since _contentParameters is always null at that point. GetFilenamesAdvice and GetFilenamesFromMultiPartAdvice handle getParts() exclusively. Disable testBodyFilenames in jetty-server-9.0 and jetty-server-9.0.4 jetty-appsec-8.1.3 (covers Jetty <9) and jetty-appsec-9.2 (covers Jetty [9.2,9.3)) were reverted to master state: they report requestBodyProcessed but not requestFilesFilenames. Jetty 9.0.x and 9.2.x therefore have no active appsec module that fires the filenames event, so testBodyFilenames() must stay false for those modules. Restore .or(named("getParts")) in ExtractContentParametersAdvice for jetty-appsec-9.3/9.4/11.0 In Armeria + Jetty 9.4.48 (and possibly other embedded/wrapped setups), getParts() is the application entry point for multipart parsing — it internally calls extractContentParameters(), which sets _contentParameters. Without the matcher on getParts(), ExtractContentParametersAdvice.after() never fires in that code path, so the requestBodyProcessed event (and request.body.converted tag) is never reported. The call-depth guard (Request.class key) already prevents double-firing when both methods are instrumented: getParts() increments depth to 1 before extractContentParameters() is entered, so the nested advice is a no-op. fix(appsec/jetty): use _dispatcherType bytecode discriminator for jetty-appsec-9.4 Replace the JAVAX_PART_REFERENCE muzzle check (class presence on classpath) with a field-level bytecode check on Request._dispatcherType descriptor: - Ljavax/servlet/DispatcherType; in Jetty 9.4/10 (javax namespace) - Ljakarta/servlet/DispatcherType; in Jetty 11+ (jakarta namespace) This reliably excludes Jetty 11+ even when both javax and jakarta servlet jars are on the test classpath simultaneously. Also remove assertInverse from 9_series muzzle block to avoid conflict with 10_series (both cover overlapping Jetty 10.0.x versions). Fixes armeria-jetty-1.24:jetty11Test ClassCastException where jetty94.MultipartHelper tried to cast jakarta.servlet.http.Part to javax.servlet.http.Part. Skip multipart test on Jetty 9.0.x where jetty-appsec-8.1.3 causes HTTP 500 jetty-appsec-8.1.3 muzzle range [8.1.3, 9.2.0.RC0) includes Jetty 9.0.x. When applied, it calls ParameterCollector.put(String, String) which does not exist in Jetty 9.0.x → HTTP 500 on multipart requests. Override multipart() with assumeTrue(false) in jetty-server-9.0 and jetty-server-9.0.4 test classes until the muzzle range is corrected. Use @ignore to skip multipart test on Jetty 9.0.x where jetty-appsec-8.1.3 causes HTTP 500 Replace assumeTrue(false) with Spock's @ignore annotation — more reliable for overriding void feature methods without Spock block labels. jetty-appsec-8.1.3 muzzle range [8.1.3, 9.2.0.RC0) includes Jetty 9.0.x. When applied, it calls ParameterCollector.put(String, String) which does not exist in Jetty 9.0.x → HTTP 500 on multipart requests. Add supportsMultipart() hook to skip multipart test on Jetty 9.0.x Spock AST-transforms feature methods, so @OverRide on a feature method override triggers a compile error. Use a boolean hook instead: - AppSecInactiveHttpServerTest.supportsMultipart() returns true by default and is guarded with assumeTrue() at the setup: block level - Jetty9InactiveAppSecTest overrides to false in both jetty-server-9.0 and jetty-server-9.0.4, where jetty-appsec-8.1.3 range [8.1.3, 9.2.0.RC0) causes ParameterCollector.put(String, String) to fail → HTTP 500. Verified locally: tests=8, skipped=3 (multipart correctly skipped), failures=0. fix(appsec/jetty): disable multipart test on Jetty 9.0.x and bump test version to 10.0.10 - jetty-server-9.0 and jetty-server-9.0.4: set testBodyMultipart() = false. jetty-appsec-8.1.3 covers [8.1.3, 9.2.0.RC0) which includes Jetty 9.0.x; its extractContentParameters() calls ParameterCollector.put(String, String) which does not exist in Jetty 9.0.x, causing HTTP 500 on multipart requests. - jetty-server-10.0: bump test dependency from 10.0.0 to 10.0.10. jetty-appsec-9.4 requires _multiParts: Lorg/eclipse/jetty/server/MultiParts; but that type was only introduced in 10.0.10 (previously MultiPartFormInputStream), so the muzzle check fails for Jetty 10.0.0-10.0.9, leaving tests uninstrumented. - Revert accidental modification of agent-jmxfetch/integrations-core submodule back to its master pointer. fix(appsec/jetty): replace bytecode injection in jetty-appsec-8.1.3 with exit-advice Replace the brittle GetPartsMethodVisitor ASM bytecode injection (intercepting MultiMap.add() calls inside getParts()) with a clean ByteBuddy exit-advice approach: - Remove ParameterCollector, GetPartsAdvice, GetPartsVisitorWrapper, RequestClassVisitor, and GetPartsMethodVisitor; drop HasTypeAdvice from the instrumentation module. - Add PartHelper with extractFormFields() (reads InputStream per part) and extractFilenames() (parses Content-Disposition manually, since Part.getSubmittedFileName() is Servlet 3.1+ and not available in Jetty 8.x). - Add GetFilenamesAdvice (@RequiresRequestContext / @ActiveRequestContext) on getParts():Collection that fires requestBodyProcessed() with form fields and requestFilesFilenames() with upload filenames. Uses CallDepthThreadLocalMap to guard against reentrant calls. - Jetty8LatestDepForkedTest: set testBodyFilenamesCalledOnce() and testBodyFilenamesCalledOnceCombined() to false because Jetty 8.x has no _multiParts / _contentParameters field guards to suppress duplicate firings. test(appsec/jetty): add unit tests for PartHelper (jetty-appsec-8.1.3) fix(appsec/jetty): cover Jetty 10.0.0-10.0.9 and close PartHelper InputStream - jetty-appsec-9.4: extend muzzle to also cover Jetty 10.0.0–10.0.9, which were previously a gap. In those versions _multiParts is typed MultiPartFormInputStream (not MultiParts); the primary Reference spec matches 9.4.10+ and 10.0.10+, and an OrReference alternative matches 10.0.0–10.0.9. The GetFilenamesAdvice already uses typing=DYNAMIC so no advice changes are needed. - jetty-appsec-8.1.3 PartHelper: wrap part.getInputStream() in try-with-resources to avoid leaking file descriptors on file-backed multipart form fields. fix(appsec/jetty): quote-aware Content-Disposition parser in PartHelper Splitting the header on ';' naively truncated filenames that contain semicolons inside a quoted value, e.g. filename="shell;evil.php" would produce "shell" instead of the full name. Replace the split() loop with a quote-aware state-machine parser that skips semicolons inside quoted strings and handles backslash-escaped characters. Add test cases for semicolons in filenames, escaped quotes, and filename appearing before other parameters. fix(appsec/jetty): use Request bytecode discriminator for jetty-appsec-11.0 Replace the JAKARTA_PART_REFERENCE classpath check with a _dispatcherType field descriptor check on Request.class bytecode, mirroring the approach already used by jetty-appsec-9.4. The classpath check passes on any Jetty 9.4/10 app that has jakarta.servlet-api as a dependency, causing double-instrumentation of extractContentParameters. The bytecode check is authoritative: in Jetty 11+ Request.class carries _dispatcherType as Ljakarta/servlet/DispatcherType;, while 9.4/10 carry the javax descriptor. feat(appsec): advise getPart(String) in Jetty 8 to catch single-part uploads In Jetty 8.x, getPart(String name) calls _multiPartInputStream.getPart(String) directly without delegating to getParts(). Applications that retrieve only one file via getPart() without ever calling getParts() would have their filename event missed. Add GetPartAdvice to cover this path. The charset fix (AI comment 2) was investigated and is not applicable: HTML5 form submissions always use UTF-8 and browsers never include charset= on individual part Content-Type headers, so the existing hardcoded UTF-8 is correct. fix(appsec): guard Jetty 8 getParts against repeated calls; disable filename tests in async suite 1. Add _multiPartInputStream == null guard to GetFilenamesAdvice.before() so that repeated getParts() calls on the same request (which Jetty caches) do not re-fire requestFilesFilenames/requestBodyProcessed WAF callbacks. The field is null before the first multipart parse and non-null on all subsequent cached calls, matching the pattern used in the 9.4/11.0 advice (_multiParts guard). 2. JettyAsyncHandlerTest already disabled testBodyFilenames() but neglected to disable testBodyFilenamesCalledOnce() and testBodyFilenamesCalledOnceCombined(), which are now enabled in the Jetty11Test parent. Override both to false in the async handler suite to prevent spurious test failures. fix(appsec): distinguish empty filename from absent filename in PartHelper filenameFromPart() was returning null for both 'no filename parameter' and 'filename=""', causing extractFormFields() to buffer the full body of file inputs submitted with no file chosen (filename=""). An empty <input type=file> is still a file part, not a form field. Return "" instead of null so that callers using != null correctly skip those parts without reading their content. Update tests to assert "" for empty-filename cases and add regression tests for extractFormFields/extractFilenames with empty-filename parts. Note: the second AI comment about getPart(String) double-firing was not implemented. The bytecode shows the internal call is to MultiPartInputStream.getParts() (not Request.getParts()), so GetFilenamesAdvice (which instruments Request.getParts()) is never triggered during a getPart() call. There is no double-firing. test(appsec): add earlyDep10ForkedTest to cover Jetty 10.0.0–10.0.9 The jetty-appsec-9.4 early_10_series muzzle pass covers [10.0.0, 10.0.10) where _multiParts is MultiPartFormInputStream (before the type changed to MultiParts in 10.0.10). The existing test suite used 10.0.10, leaving the early versions untested. Add earlyDep10ForkedTest (Jetty 10.0.9) to exercise the OR-muzzle reference and verify that multipart filename events fire correctly on the old field type. All three filename tests pass: filenames, filenames-called-once, filenames-combined. refactor(appsec/jetty): extract fire-event logic into helpers; fix ASM API constant Move duplicated IG-callback + blocking-commit blocks out of advice into helper methods (MultipartHelper.fireFilenamesEvent / PartHelper.fireBodyProcessedEvent + fireFilenamesEvent) that return BlockingException|null, exploiting @Advice.Thrown(readOnly=false) assignment behaviour. Also replace hardcoded Opcodes.ASM9 with OpenedClassReader.ASM_API in RequestGetPartsInstrumentation and fix extractFormFields to use computeIfAbsent instead of get+put. fix(appsec/jetty8): prevent double-firing filename event when getPart() delegates to getParts() In Jetty 9.0/9.1 (covered by jetty-appsec-8.1.3's [8.1.3,9.2.0.RC0) range), Request.getPart(String) delegates to getParts() internally. Without this fix, GetFilenamesAdvice fires for the full collection (via the internal getParts() call) and then GetPartAdvice fires again for the returned singleton, because the two advice classes use independent call-depth keys and cannot see each other. Fix: peek at the Part.class call depth in GetFilenamesAdvice.before(). If > 1, GetPartAdvice is active on the stack and will handle the event; skip to avoid double-firing. In Jetty 8.x (where getPart() does not delegate), the peek is always 1, so GetFilenamesAdvice continues to fire normally. fix(appsec/jetty8): correct partPeek condition — use == 0 instead of == 1 CallDepthThreadLocalMap.incrementCallDepth() uses post-increment (depth++) so it returns the depth BEFORE the increment. In the normal case (no GetPartAdvice active), Part.class depth is 0 before the peek, making partPeek == 0. The previous guard checked partPeek == 1 which is true only when GetPartAdvice IS already on the stack — exactly backwards. Result: GetFilenamesAdvice never fired for direct getParts() calls, breaking the filenames event on Jetty 8.x. Fix: use partPeek == 0 (proceed when GetPartAdvice is not active) so the condition is: - partPeek == 0: normal direct getParts() → proceed (fire filenames event) - partPeek == 1: getParts() called by getPart() in Jetty 9.0/9.1 → skip (GetPartAdvice handles it) fix(appsec/jetty8): inspect all cached parts in GetPartAdvice, not just the singleton When getPart("field") is the app's first multipart access, Jetty 8 parses the entire multipart stream and caches all parts in _multiPartInputStream, but only returns the one requested part. The previous advice forwarded just that singleton to AppSec, so any co-uploaded file parts were invisible to requestFilesFilenames — a WAF bypass if the app never called getParts() explicitly. Fix: read all cached parts via MultiPartInputStream.getParts() (reflected, cached handle) and fall back to the singleton only when reflection fails. Also remove the part==null early return: even if the requested field was not found, other file parts may have parsed. Add PartHelper.getAllParts(Object, Part) + FakeMpi unit tests. fix(appsec/jetty8): guard GetPartAdvice against repeated getPart() calls The Part.class depth check only prevents re-entry within a single getPart() invocation; after the call returns the depth is 0 again, so a second getPart("file") call on the same request would re-fire requestBodyProcessed and requestFilesFilenames with the same cached parts. Add the same _multiPartInputStream == null guard that GetFilenamesAdvice already uses: once the field is set the multipart body was parsed and events were already dispatched — skip. fix(appsec/jetty8): respect part Content-Type charset in extractFormFields Hard-coded UTF-8 in readPartContent() caused mojibake for fields with Content-Type: text/plain; charset=ISO-8859-1 (or any non-UTF-8 charset). Now parses the charset from the part's Content-Type header and falls back to UTF-8 only when absent or unrecognised. fix(appsec/jetty10): regenerate lockfile and force 10.0.9 for earlyDep10ForkedTest The lockfile was out of sync: testCompileClasspath was locked to 10.0.0 instead of 10.0.10, and earlyDep10ForkedTest configurations were missing entirely. Regenerated with --write-locks. Also added a resolutionStrategy to force Jetty 10.0.9 for earlyDep10ForkedTest: without it, Gradle picks 10.0.10 (inherited via testImplementation), defeating the purpose of the suite which exercises the MultiPartFormInputStream path present in [10.0.0, 10.0.10). fix(appsec/jetty): pendingBlock pattern, jetty9.2 filenames, tryCommit check, per-part try/catch - Fix body+filenames ordering bug in jetty8 GetFilenamesAdvice and GetPartAdvice: both callbacks now always fire even when body blocks (pendingBlock pattern, appsec-ig-events §7) - Add requestFilesFilenames support for jetty-appsec-9.2 ([9.2, 9.3)): new MultipartHelper, GetFilenamesAdvice, GetFilenamesFromMultiPartAdvice, and integration test Jetty92LatestDepForkedTest - Fix tryCommitBlockingResponse() return not checked before effectivelyBlocked() in PartHelper (jetty8) and MultipartHelper (jetty9.3, 9.4, 11.0) - Add per-part try/catch in extractFilenames() and extractFormFields() loops in PartHelper and all MultipartHelper implementations test(appsec/jetty): migrate 8 new Groovy test files to Java/JUnit 5 Satisfies the enforce-groovy-migration CI check. All 8 Groovy test files introduced in this PR are replaced by Java equivalents: - jetty-appsec-8.1.3: PartHelperTest (36 unit tests via Mockito) - jetty-appsec-9.2/9.3/9.4: MultipartHelperTest (8 unit tests each) - jetty-appsec-11.0: MultipartHelperTest using jakarta.servlet.http.Part - jetty-server-7.6: Jetty8LatestDepForkedTest (extends Jetty76Test) - jetty-server-9.0.4: Jetty92LatestDepForkedTest (extends Jetty9Test) - jetty-server-10.0: Jetty10EarlyDepForkedTest (extends Jetty10Test) Integration tests extending Groovy Spock base classes are placed in src/test/groovy/ as .java files so groovyc compiles them together with the Groovy classes they extend, avoiding the compileTestJava ordering issue. This pattern is already used elsewhere in the repo. test(appsec/jetty): delete the 8 replaced Groovy test files fix(appsec/jetty): add catch comments and remove dead call-depth decrement - Add explanatory comments to all catch(Exception ignored) blocks in PartHelper and MultipartHelper across jetty8/9.2/9.3/9.4/11.0 modules, consistent with the pattern used in Jersey and GlassFish helpers - Remove spurious CallDepthThreadLocalMap.decrementCallDepth(Request.class) from jetty92 GetPartsAdvice.after() which had no matching increment and was corrupting the thread-local counter refactor(appsec/jetty): address review comments from amarziali - ArrayList(parts.size()) in extractFilenames() across all 5 modules to pre-size the list and avoid rehashing - Callback-before-extract optimization in fireFilenamesEvent() and fireBodyProcessedEvent(): check callback != null before calling extractFilenames()/extractFormFields() so we skip Part iteration when AppSec is not listening - WithTypeStructure.structureMatcher() in jetty-appsec-11.0 to replace additionalMuzzleReferences() for javax vs jakarta DispatcherType discrimination; evaluated per-class at transformation time - Skip-increment optimization in ExtractContentParametersAdvice and GetFilenamesAdvice (jetty-appsec-11.0): return false early when guard fields are already non-null, avoiding CallDepthThreadLocalMap overhead on cached repeat calls - IODH + MethodHandle in PartHelper (jetty-appsec-8.1.3) replacing volatile Method for MultiPartInputStream.getParts() resolution; inner class MpiGetPartsHolder added to helperClassNames() fix(appsec/jetty8): duck-typed reflection fallback in getAllParts() when IODH handle is null MpiGetPartsHolder resolves MultiPartInputStream.getParts() at class-load time via Class.forName(). In test environments where jetty-server is not on the test classpath (compileOnly only), GET_PARTS is null and the MethodHandle path is unavailable. Add duck-typed reflection as fallback: when GET_PARTS is null, call getParts() via getClass().getMethod("getParts").invoke(...). In production the fast MethodHandle path always wins; the reflection fallback only activates when the class could not be resolved. This restores getAllPartsReturnsAllPartsFromMultiPartInputStream and getAllPartsPrefersFullCollectionOverSingleton unit tests that regressed after the IODH refactor. fix(appsec/jetty11): revert GetFilenamesAdvice skip-increment optimization The skip-increment optimization introduced in the amarziali review commit broke the shared Collection.class depth counter that GetFilenamesAdvice and GetFilenamesFromMultiPartAdvice rely on to coordinate. In Jetty 11.0.0, public getParts() delegates to the private getParts(MultiMap) overload. GetFilenamesAdvice increments Collection depth before the public method runs, which raises the depth so GetFilenamesFromMultiPartAdvice (also applied to the private overload) sees depth > 0 and skips firing. When the optimization skipped the increment because _multiParts != null, the private getParts(MultiMap) call found Collection depth = 0 on the second and third repeated calls and fired the requestFilesFilenames callback again, causing _dd.appsec.filenames.cb.calls = 3 (BODY_MULTIPART_REPEATED) and = 2 (BODY_MULTIPART_COMBINED) instead of the expected 1. Fix: restore the original always-increment/always-decrement pattern in GetFilenamesAdvice so the depth counter remains balanced on every code path. refactor(appsec/jetty8): remove duck-typed fallback from getAllParts, use real MultiPartInputStream in tests The reflection fallback (getClass().getMethod("getParts").invoke(...)) was only needed because MultiPartInputStream was not on the test classpath, causing the IODH MethodHandle to initialize to null. Fix the root cause instead: add testImplementation for jetty-server 8.1.3.v20120416 and replace the FakeMpi stub with mock(MultiPartInputStream.class). fix(appsec/jetty8): add log.debug to all PartHelper catch blocks - getAllParts: log.debug on MethodHandle invocation failure - extractFilenames: log.debug when skipping a malformed part - extractFormFields: log.debug when skipping a malformed part - readPartContent: log.debug on IOException before returning null IODH static block and charsetFromContentType left comment-only: static initializer context and attacker-controlled input respectively. fix(appsec/jetty8): replace increment+decrement peek with getCallDepth Use CallDepthThreadLocalMap.getCallDepth(Part.class) to read the current depth without modifying it, instead of the equivalent incrementCallDepth + decrementCallDepth pair. fix(appsec/jetty): use MultipartHelper.class as CallDepthThreadLocalMap key Replace Collection.class with MultipartHelper.class in all four jetty appsec modules (9.2, 9.3, 9.4, 11.0). Collection.class is a generic JDK class that any other instrumentation could use as a key on the same thread, silently corrupting call depth tracking. MultipartHelper.class is specific to each module and cannot collide with other instrumentations. Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3 Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
feat: Expand the jar checks to stricter agent jar validation * Maintains the size check. * Verify some required entries * Ensure there's a minimum number of classes in the whole jar * Ensure products are correctly included and have at least one class * Light size check on the indexes * Fixed list of packages that should not appear in the jar * Run checks as part of the build job, to catch issues earlier Co-authored-by: brice.dutheil <brice.dutheil@datadoghq.com>
… values (#11604) fix: waf.init and waf.updates metrics emit per-event count 1 instead of sequential counters Removes wafInitCounter and wafUpdatesCounter AtomicInteger fields from WafMetricCollector. Both wafInit() and wafUpdates() now use literal 1L, matching RFC semantics (COUNT-1-per-event). The old sequential counters (1, 2, 3, ...) caused success:N/A when the rawMetricsQueue was full and a metric was dropped — the counter advanced but the offer() silently failed, creating gaps the backend interpreted as success:N/A. Also updates currentRuleVersion from e.wafDiagnostics.rulesetVersion in the InvalidRuleSetException catch block of handleWafUpdateResultReport(), so wafUpdates() emits with the correct event_rules_version even on partial WAF config errors. Raises log level from debug to warn. fix: only update statsReporter rule version when rules were actually loaded on error On InvalidRuleSetException, always update currentRuleVersion and setRuleVersion() on modules so wafUpdates() emits with the correct event_rules_version. But only update statsReporter (trace tagging) if rules.getLoaded() is non-empty, mirroring the success path guard. This avoids tagging traces with a version whose rules failed to load. Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
… (#11694) fix: Forbid OkHostnameVerifier to prevent accidental use, CVE-2021-0341 See #11631 Co-authored-by: brice.dutheil <brice.dutheil@datadoghq.com>
…11693) Cleanup of Spotbugs annotations. Removed Spotbugs from test scope. Fixed review. Co-authored-by: alexey.kuznetsov <alexey.kuznetsov@datadoghq.com>
Add missing repositories to Update Gradle dependencies workflow Co-authored-by: sarah.chen <sarah.chen@datadoghq.com>
Add SCA benchmark gitlab config Co-authored-by: sarah.chen <sarah.chen@datadoghq.com>
Pre-construct TagMap.Entry objects in InternalTagsAdder InternalTagsAdder set base.service / version via TagMap.set(tag, value), allocating a fresh TagMap.Entry per span. Both values are fixed for the life of the tracer, and TagMap.Entry objects are safe to share across maps (the OptimizedTagMap collision design relies on it), so build the two Entry objects once in the constructor and reuse them via set(entry). A JFR profile of petclinic (2026-06-03) attributed ~52 allocation samples to InternalTagsAdder.processTags (one Entry per span); this drops them to zero. Re-applies the change from the stale PR #10965 (415 commits behind master, drifted signature) onto current master. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Fix empty-DD_SERVICE version drop; migrate test to JUnit 5 Addresses the Codex review comment on #11555: pre-building the base.service Entry must not change behavior for an explicitly-empty DD_SERVICE. Entry.create rejects empty values, so baseServiceEntry is null in that case; the processTags branch now falls back to set(BASE_SERVICE, ddService) to preserve byte-identical behavior, and the version branch is still reached when the span service also matches the empty configured service. Migrate InternalTagsAdderTest from Groovy/Spock to JUnit 5 (parameterized with @MethodSource) and add regression coverage for the empty-DD_SERVICE case (9 migrated cases + 2 new = 11). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Trim verbose generated comments in InternalTagsAdder per review feedback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Resolve merge conflict: keep @TableTest structure from master, add regression test Preserves the @TableTest versions of the two existing tests that landed on master, and adds the empty-DD_SERVICE regression test (from the PR) as a plain @test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Fix empty-ddService: exit early + drop redundant Entry.create guard - Extend the processTags null guard to also exit when ddService.length()==0, which prevents writing _dd.base_service="" via the TagMap.set path that has no empty-value guard (unlike Entry.create). Empty ddService now behaves the same as null/unset. - Remove the manual null+length>0 pre-check before TagMap.Entry.create in the constructor; Entry.create already returns null for null or empty values, so the guard was redundant. - Update the regression test to assert the new early-return behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Merge branch 'master' into dougqh/preconstruct-internal-tags Accept review feedback: @nonnull ddService, drop empty guard and regression test Config.getServiceName() always returns a non-null non-empty string (defaults to "unnamed-java-app"), so the null/@empty guard in processTags and the corresponding regression test for empty DD_SERVICE are unnecessary. Replaced @nullable with @nonnull on the constructor param to document the actual contract. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Merge branch 'master' into dougqh/preconstruct-internal-tags Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
chore: Update instrumentation Gradle dependencies Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Rolled back armeria 1.40.0 to pass the build on GitLab. Co-authored-by: AlexeyKuznetsov-DD <alexey.kuznetsov@datadoghq.com>
feat(smoke): support Maven smoke test apps The smoke-test-app plugin now has separate Gradle and Maven application entry points. OpenLiberty smoke tests can use the shared nested-build wiring instead of bespoke Exec tasks, while existing Gradle smoke-test apps keep the same task model. Maven apps still launch through the checked-in root mvnw instead of an installed mvn. Keeping mvnw preserves the Maven version pinned by .mvn/wrapper/maven-wrapper.properties and gives CI and local builds the same cross-platform launcher. CI no longer rewrites maven-wrapper.properties to use MASS. Apache Maven Wrapper documents MVNW_REPOURL as the repository-manager override, so GitLab exports it from MAVEN_REPOSITORY_PROXY and trims the trailing slash before mvnw appends the Maven distribution path: https://maven.apache.org/tools/wrapper/#Using_a_Maven_Repository_Manager The Maven path is covered by smoke-test plugin tests. ProjectBuilder verifies mavenApp task wiring, and the TestKit end-to-end test runs a fake mvnw with MAVEN_REPOSITORY_PROXY. It also asserts the nested Maven process receives MVNW_REPOURL. fix(smoke): address Maven app review feedback fix(smoke): make nested build timeouts opt-in Only wire Gradle stop and Maven build timeouts when the smoke app DSL sets them explicitly. Add Maven cache coverage that deletes the app output directory and verifies the jar is restored from the outer build cache. Mirror the output assertion for the existing Gradle cache test. Co-authored-by: brice.dutheil <brice.dutheil@datadoghq.com>
…11725) feat(appsec): add server.request.body.files_content support for Akka HTTP - Extend handleMultipartStrictFormData (strictUnmarshaller) and handleStrictFormData (formFieldMultiMap) in UnmarshallerHelpers to accumulate file content via MultipartContentDecoder and dispatch EVENTS.requestFilesContent() callback - Content dispatch is sequential after filenames (fires only if no prior block), consistent with other frameworks (Tomcat, Netty, Jersey) - Uses ByteString.take(MAX_CONTENT_BYTES).toArray() to avoid full allocation; MAX_* constants read from Config - Add testBodyFilesContent() overrides to both akka-http-10.0 and akka-http-10.6 test modules fix(appsec): skip body decoding in handleStrictFormData when body callback absent When only files_content is subscribed (not requestBodyProcessed), the previous code still called getData().decodeString() on every file body part to populate conv — decoding the full file into a String regardless of MAX_CONTENT_BYTES. Gate decodeString and handleArbitraryPostData on bodyCb != null to avoid unnecessary full-file allocation. Merge branch 'master' into filecontent-akka fix: disable testBodyFilesContent in AkkaHttp102ServerInstrumentationBindSyncTest Sync server binding does not support body processing; override returns false to match the pattern already used for testBodyMultipart, testBodyFilenames, etc. fix: disable testBodyFilesContent in AkkaHttp102ServerInstrumentationBindSyncTest (10.6) Same fix as 10.0: sync binding does not process body, override returns false to match testBodyMultipart, testBodyFilenames, etc. Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
…ental, gated) (#11658) feat(02-02): surface UFC split serialId in eval metadata + add span-enrichment gate - Add nullable Integer serialId to UFC Split model + constructor (Moshi reflectively deserializes the serialId JSON field; no custom adapter needed) - DDEvaluator surfaces __dd_split_serial_id (when present) and __dd_do_log in OpenFeature eval metadata for APM span enrichment (JAVA-01) - Add FeatureFlaggingConfig.SPAN_ENRICHMENT_ENABLED dot-form constant mapping to DD_EXPERIMENTAL_FLAGGING_PROVIDER_SPAN_ENRICHMENT_ENABLED (distinct, off by default) - Register the env var in metadata/supported-configurations.json (version A, boolean) - Update DDEvaluatorTest Split call sites for the new constructor arg feat(02-02): ULeb128 codec + accumulator + capture hook + write interceptor (gate-gated) - ULeb128Encoder: ULEB128 delta-varint + base64 codec ported verbatim from the frozen Node reference (dd-trace-js#8343); golden vector {100,108,128,130} -> ZAgUAg==, SHA-256 hex targeting-key hashing; JDK stdlib only (java.util.Base64, MessageDigest) - SpanEnrichmentAccumulator: per-trace state keyed by trace id in a shared ConcurrentHashMap; frozen limits (200/10/20/5/64), UTF-8-safe truncation, object default -> JSON (Pattern F tag shapes: ffe_flags_enc bare base64, ffe_subjects_enc / ffe_runtime_defaults JSON objects) - SpanEnrichmentHook: OpenFeature finally hook (capture) resolving the active local root via AgentTracer and applying the Node branch (serialId -> addSerialId/addSubject; missing variant -> addDefault); error-isolated - SpanEnrichmentInterceptor: TraceInterceptor (write) flushing ffe_* onto the local root onTraceComplete with unique priority 4, then clearing state; disable() for provider-close cleanup - Provider: gate-gated construction via ConfigHelper.env (DG-005 — nothing built/ registered when off), hook added to getProviderHooks, interceptor registered via GlobalTracer, shutdown() disables interceptor + drains state - feature-flagging-api: add compileOnly/testImplementation :internal-api for the tracer/interceptor types (runtime-provided by the agent) test(02-02): JUnit 5 L0 suite for span enrichment (7 required cases + golden round-trip) - Codec golden-vector round-trip {100,108,128,130} -> ZAgUAg== (encode + decode + empty + structural dedupe) - no-span, finished-root (accumulate+dedupe+flush), runtime-default missing-variant (ffe_runtime_defaults JSON object), per-subject cap (10 subj / 20 exp/subj) + doLog gating, max-200 serial ids, object-default JSON + 64-char truncation - gate-off negative control: no hook/interceptor constructed, not in getProviderHooks, no accumulator state (DG-005) - gate-on construction + provider-close cleanup (shutdown disables interceptor + drains state); error isolation; interceptor priority uniqueness - JUnit 5 only (no Groovy); injectable RootSpanResolver + Provider gate override avoid static mocking (project mockito uses the subclass mock maker) fix(02-02): correct span-enrichment lifecycle (partial-flush, leak, reconfig) Gap-closure for the three BLOCKER lifecycle defects in 02-REVIEW-java.md. The frozen contract (codec/limits/gate/tag shapes, golden vector ZAgUAg==) is unchanged — this fixes only how per-trace state is scoped, bounded, and flushed. CR-01 (partial-flush data loss + tag misattribution): CoreTracer.write -> interceptCompleteTrace runs onTraceComplete on EVERY flush, and PendingTrace.write(isPartial) excludes the still-open local root from a partial flush (getRootSpan() is null until the final write). The interceptor previously resolved the root by reference (reachable even when absent from the fragment) and unconditionally removed the accumulator on the first partial flush, dropping all pre-flush flags and tagging a not-yet-finished root. SpanEnrichmentInterceptor now flushes + removes ONLY when the local root is actually present in the flushed collection (the final write); a partial flush leaves the accumulator intact. Also adds the missing getTraceId() null guard (WR-01) and never falls back to tagging a non-root span (WR-02). CR-02 (unbounded state leak): State lived in a static ConcurrentHashMap whose only removal paths were trace-complete and shutdown, so dropped / Noop / never-finishing traces leaked forever (#4844 leak class). State now lives in a per-provider SpanEnrichmentStates store, hard-bounded at MAX_TRACES with FIFO eviction of the oldest in-flight entry, so a never-completing trace cannot grow the map unboundedly. CR-03 (reconfiguration corruption): Provider ignored addTraceInterceptor's return value, so a second gate-on provider (rejected on duplicate priority 4) still wired a hook into shared static state and its shutdown() cleared the first provider's live state. Provider now honors the registration result (wires the hook/interceptor only when registration succeeds) and each provider owns its own state store, so one provider's shutdown can never clear another's. Removes the global static map (review IN-03 root cause). Adds an injectable TraceInterceptorRegistrar test seam (mirrors the existing gate-override seam). Runtime-default rendering (String() parity) and hasData() are intentionally unchanged. L0 suite migrated to the instance-owned store; module 146 tests green. test(02-02): regression tests for span-enrichment lifecycle defects Adds SpanEnrichmentLifecycleRegressionTest exercising the real tracer lifecycle paths the original L0 suite bypassed (single root, no children, one provider). Each test FAILS against the pre-fix code and PASSES after the fix: CR-01 partialFlushExcludingRootPreservesPreFlushFlags / partialFlushNeverWrites- TagsOnAChildSpan: a partial flush carrying only child spans (root excluded, as dd-trace-core does) must not drain state or tag a child; the full pre+post-flush serial-id set {100,108,128,130} -> 'ZAgUAg==' must land on the root at final completion. Fail-before: tags written on the partial flush (NeverWantedButInvoked). CR-02 neverCompletingTracesDoNotLeakUnbounded / boundedStoreEvictsOldestFirst: 3x MAX_TRACES distinct never-flushed traces keep the store bounded; eviction is FIFO. Fail-before: store grew to 3x the cap (expected <=cap but was larger). CR-03 secondProviderRejectedRegistrationDoesNotClearFirstProviderState / eachProviderOwnsADistinctStateStore / hookAndInterceptorOfOneProviderShareThe- SameStore: a second provider whose registration is rejected wires no hook/interceptor and its shutdown does not clear the first provider's in-flight state. Fail-before: second provider kept a non-null interceptor (expected null). Fail-before verified by temporarily reintroducing each defect: 5/7 failed (the remaining 2 are structural-invariant checks that hold by construction). chore(feature-flagging): strip internal review labels from span-enrichment comments Remove leaked workflow labels (e.g. JAVA-01) from production comments so the upstream PR carries only behavioral context. fix(feature-flagging): address span-enrichment code-review findings - Reconfiguration safety: replace the per-provider trace interceptor with a single process-wide delegating interceptor (SpanEnrichmentInterceptor.INSTANCE) registered once and rebound per active provider. A closing provider unbinds only if still active, so provider close/reopen no longer permanently disables enrichment via a duplicate-priority rejection, and a displaced provider's late shutdown cannot clobber the active provider's in-flight state. - Runtime defaults: recursively unwrap OpenFeature Value (structure/list/scalar) to its native form before JSON serialization so ffe_runtime_defaults matches the frozen Node contract instead of emitting Value.toString(). - 128-bit trace ids: key per-trace state by the full trace id hex string rather than DDTraceId.toLong(), so two traces sharing low-order 64 bits no longer merge enrichment state. - Gate-off inertness: precompute the immutable provider-hook list once in the constructor so getProviderHooks() (called per evaluation) allocates nothing. - Add regression tests: reconfiguration, displaced-provider late shutdown, 128-bit low-bit collision, Value structure/list/scalar serialization, and gate-off zero-allocation. Merge master Adjustments + clean up; add FeatureFlaggingConfig.SPAN_ENRICHMENT_ENABLED; add Startup INFO log; clean tech debt Rework FFE span-enrichment state store to weak-keyed-by-span map Merge branch 'master' of github.com:DataDog/dd-trace-java into leo.romanovsky/ffe-apm-span-enrichment # Conflicts: # products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java Enhancements after techdebt skill Refactor: Move span-enrichment write tier out of the published dd-openfeature API Use JsonWriter instead of hand-written solution Fix unicode char Address review nits: gate enrichment metadata, name constants, reuse digest - Gate the __dd_split_serial_id / __dd_do_log evaluation metadata on the span-enrichment flag so an enabled provider with enrichment off attaches nothing extra per evaluation (DDEvaluator). - Extract the metadata keys to named constants (METADATA_SPLIT_SERIAL_ID / METADATA_DO_LOG) as the single source of truth; SpanEnrichmentHook references them. - Rename the config constant to EXPERIMENTAL_SPAN_ENRICHMENT_ENABLED to make its experimental status obvious at call sites. - Reuse a ThreadLocal<MessageDigest> for subject hashing instead of allocating a SHA-256 instance per capture (ULeb128Encoder). feat(ffe): Introduce config module to decouple feature flagging from tracing API (#11888) Fix 3 bugs: SpanEnrichmentWriter is now a process-wide singleton; addTraceInterceptor() false return: ensureInterceptorRegistered() now latches only on a true return; registration ordering: moved ensureInterceptorRegistered() below the root == null check Fix nits: add debug logging; fix comments Merge branch 'master' into leo.romanovsky/ffe-apm-span-enrichment Add gate on registration; adjust - add typed metadata Merge branch 'master' of github.com:DataDog/dd-trace-java into leo.romanovsky/ffe-apm-span-enrichment Merge branch 'leo.romanovsky/ffe-apm-span-enrichment' of github.com:DataDog/dd-trace-java into leo.romanovsky/ffe-apm-span-enrichment Merge branch 'master' into leo.romanovsky/ffe-apm-span-enrichment Raise feature-flagging test coverage to pass the JDK 8 jacoco gate Merge branch 'leo.romanovsky/ffe-apm-span-enrichment' of github.com:DataDog/dd-trace-java into leo.romanovsky/ffe-apm-span-enrichment Merge branch 'master' into leo.romanovsky/ffe-apm-span-enrichment Fix failing tests Merge branch 'master' of github.com:DataDog/dd-trace-java into leo.romanovsky/ffe-apm-span-enrichment Merge branch 'leo.romanovsky/ffe-apm-span-enrichment' of github.com:DataDog/dd-trace-java into leo.romanovsky/ffe-apm-span-enrichment Co-authored-by: pavlokhrebto <pavlo.khrebto@datadoghq.com> Co-authored-by: sarahchen6 <sarah.chen@datadoghq.com> Co-authored-by: PerfectSlayer <PerfectSlayer@users.noreply.github.com> Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Upgrade libddwaf-java to 17.4.0 Fixes a production SIGSEGV (APPSEC-62784) where the JIT (JDK 21.0.8+/25) could elide the ArenaLease reference in WafContext.run() before the native ddwaf_run call finished reading the backing memory (libddwaf-java#198). Merge branch 'master' into upgrtade-libddwaf Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Wire per-component cardinality limits from Config per Cardinality Limits RFC Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Raise RESOURCE cardinality limit to 1024 to avoid premature collapse Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Apply spotless formatting Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Apply spotless formatting to Config.java Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Fix supported-configurations.json: use int not integer for cardinality limits Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Align cardinality config with .NET: rename peer_tags, raise http_endpoint, add table alias - Rename DD_TRACE_STATS_PEER_TAG_CARDINALITY_LIMIT -> DD_TRACE_STATS_PEER_TAGS_CARDINALITY_LIMIT to match .NET naming (plural) - Raise DD_TRACE_STATS_HTTP_ENDPOINT_CARDINALITY_LIMIT default 64 -> 512 to match .NET - Add DD_TRACE_STATS_CARDINALITY_LIMIT as the canonical name for the aggregate table cap, aliasing the older DD_TRACE_TRACER_METRICS_MAX_AGGREGATES - Add explicit string constants for all 10 per-field cardinality limit keys in GeneralConfig so the config registry validator can find them Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Drop 7 Java-only per-field cardinality limit config keys SERVICE, OPERATION, SERVICE_SOURCE, TYPE, SPAN_KIND, HTTP_METHOD, and GRPC_STATUS_CODE have naturally low cardinality -- the aggregate table cap (DD_TRACE_STATS_CARDINALITY_LIMIT) is sufficient backstop. Aligns the public config surface with .NET (resource, http_endpoint, peer_tags, table cap). Hardcoded defaults in MetricCardinalityLimits remain; config knobs can be added later if a customer needs to tune them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Merge branch 'master' into dougqh/cardinality-limits-config Fix fixed-limit fields to bypass Config lookup, avoiding unsupported config key detection Fields with hardcoded limits (service, operation, type, span_kind, http_method, grpc_status_code, service_source) now pass their MetricCardinalityLimits constant directly to PropertyCardinalityHandler instead of going through Config.getTraceStatsCardinalityLimit. This prevents the test harness from flagging DD_TRACE_STATS_SERVICE_CARDINALITY_LIMIT etc. as unsupported config keys. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Remove aliases from DD_TRACE_STATS_CARDINALITY_LIMIT registry entry The central registry has no alias for this key; the local entry must match. The code-level alias (Config.java reads DD_TRACE_TRACER_METRICS_MAX_AGGREGATES as a fallback) is unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Bump DD_TRACE_STATS_CARDINALITY_LIMIT to version B with legacy alias Version A must match the central registry exactly (no aliases). The DD_TRACE_TRACER_METRICS_MAX_AGGREGATES alias is Java-specific, so it belongs in version B — matching the same pattern as DD_TRACE_STATS_COMPUTATION_ENABLED aliasing DD_TRACE_TRACER_METRICS_ENABLED. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Merge branch 'master' into dougqh/cardinality-limits-config Merge branch 'master' into dougqh/cardinality-limits-config Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
…oint (#11808) Tag consumer spans with the pathway hash on every data streams checkpoint The pathway.hash span tag was only set on the produce/inject path (DataStreamsPropagator.inject). Consumers that checkpoint without injecting (e.g. RabbitMQ) had no pathway.hash, unlike the JS and Python tracers which tag the span on every checkpoint. Set it centrally in DefaultDataStreamsMonitoring.setCheckpoint so all consume-side integrations get it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Remove explanatory comment on pathway hash tagging Per review on #11808; the rationale lives in the PR description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Address review on #11808 - cache pathwayContext.getHash() in a local instead of calling it twice - use a negative hash in the test so it actually exercises Long.toUnsignedString Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Expect pathway.hash on the inferred-proxy server span when DSM is enabled Now that DefaultDataStreamsMonitoring.setCheckpoint tags the span on every checkpoint, the inferred-proxy (API Gateway) HTTP server span gets a pathway.hash like any other DSM-enabled server span. The shared HttpServerTest already asserts this conditionally; SpringBootBasedTest's hand-rolled inferred-proxy assertions were missing it. Mirror the same guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Merge branch 'master' into eric.firth/dsm-consumer-pathway-hash Co-authored-by: eric.firth <eric.firth@datadoghq.com>
feat: add AGP usage visibility for Gradle projects Detect Android Gradle Plugin projects at the build-system level and surface an is_android signal independent of the test runner: - test.is_android span tag on the build-system module, rolled up to the session via the tag propagator - IsAndroid dimension on the EVENT_FINISHED telemetry metric - detection via com.android.base and com.android.kotlin.multiplatform.library (the KMP library plugin, AGP 8.8+, does not apply com.android.base) Exercised by the Robolectric Gradle smoke test through a com.android.base stand-in plugin. Co-authored-by: daniel.mohedano <daniel.mohedano@datadoghq.com>
Fix lookup-then-read race in GenerationalUtf8Cache.getUtf8 getUtf8() looks up a matching slot via lookupEntryIndex() and then reads that slot from the array in a second step. Between the two, another thread can mutate the slot: recalibrate()/eviction can null it, and promotion nulls the eden slot after promoting into tenured. The array read therefore returned either null (-> NPE on the following hit()) or, worse, a *different* value's entry whose bytes were then returned as if they were the requested value's -- silent payload corruption. This never manifests today because trace serialization runs on a single thread (TraceProcessingWorker), but the cache is built to allow concurrent access, so the race is a latent bug against that contract. CacheEntry identity is immutable (adjHash/value/valueUtf8 are final), so the fix re-validates the loaded reference against the request (entry != null && entry.matches(adjHash, value)) on both the tenured and eden read paths; a null-or-mismatched slot is treated as a miss. The residual races on hit()'s score/lastUsedMs writes are benign -- they only nudge LRU/eviction bookkeeping and never affect returned bytes. Adds a concurrent regression test that fails (NPE / wrong bytes) without the fix and passes with it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Mark Utf8 caches @threadsafe and add multi-threaded cache benchmarks Follow-on cleanup to the getUtf8 race fix: - Mark both `GenerationalUtf8Cache` and `SimpleUtf8Cache` `@ThreadSafe` (`javax.annotation.concurrent.ThreadSafe`, the annotation already used across the codebase), making the intended concurrency contract explicit. (`SimpleUtf8Cache` was already correct — its lookup returns a validated entry reference rather than re-reading the slot by index.) - Split the UTF8 cache benchmarks into a single-threaded `Utf8Benchmark` and a multi-threaded `Utf8ConcurrentBenchmark`, sharing `Utf8Workload`. The single-threaded variant reflects how the caches are driven today (serialization is single-threaded) and drives recalibrate inline; the concurrent variant uses @group to model the intended concurrent drive pattern (a dedicated recalibrate thread + worker lookup threads on the shared cache) and doubles as a concurrency guardrail. A @threads>1 benchmark like this would have hit the NPE and surfaced the race sooner. Measured cost of the matches() re-validation (single-thread, -f3, with vs without fix, `simple` as unchanged control): allocation flat (-0.03%) and throughput within run-to-run noise (changed benchmark moved less than the untouched control), i.e. no measurable cost. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Merge branch 'master' into dougqh/utf8-cache-concurrency-fix Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
…the active span (#11934) Fix a couple of IAST modules to use the IGSpanInfo in the event over the active span Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
… substring (#11737) Check the DBM comment region in place, dropping the extractCommentContent substring SQLCommenter.hasDDComment materialized sql.substring(commentStart, commentEnd) on every duplicate-comment check just to feed containsTraceComment. Add a SharedDBCommenter.containsTraceComment(sql, from, to) range overload that scans the comment body in place, and a Strings.regionContains primitive it (and the String delegate) build on -- no per-call substring. The String overload now delegates to the range form, so Mongo behavior is unchanged. regionContains is the allocation-free, copy-free primitive; the natural-reading SubSequence.contains layer can delegate to it later. Boundary semantics unit- tested on Strings.regionContains; DB needle behavior on the overloads; existing SQLCommenter/SharedDBCommenter suites unchanged and green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Read the comment-region check as a SubSequence view (the followable idiom) Add SubSequence.contains (delegating to the Strings.regionContains primitive) and rewrite containsTraceComment(sql, from, to) as SubSequence.of(sql, from, to).contains(...) -- a 1-to-1 substitution for what you'd idiomatically write on a substring, with no copy. EA elides the view in the transient consumption; even if it doesn't, the string copy is still avoided. Couples this branch to the SubSequence base (#10640); regionContains stays as the allocation-free primitive the view delegates to. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Add SQLCommenterDuplicateCommentBenchmark (substring 140 -> 0 B/op) Isolates the duplicate-comment guard (dbType=null skips the first-word scan; already-DD-commented SQL makes inject return early). The extractCommentContent substring allocated 140 B/op; the in-place range/view scan is EA-elided (~0). @threads(8), @fork(2), -prof gc; numbers in the class Javadoc. Throughput is flat-to-slightly-up but within @fork(2) noise -- this path is scan-CPU-dominated, so the win is the allocation, not throughput. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Refresh SQLCommenterDuplicateCommentBenchmark results to JDK 17 @fork(5) zulu-17 @fork(5), -prof gc: 23.5M -> 26.2M ops/s (~1.1x), 140 -> ~0 B/op. Headline win is the allocation; @fork(5) tightens the earlier bimodal spread. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Merge remote-tracking branch 'origin/master' into dougqh/dbcommenter-scan-overload # Conflicts: # internal-api/src/main/java/datadog/trace/util/SubSequence.java # internal-api/src/test/java/datadog/trace/util/SubSequenceTest.java Merge branch 'master' into dougqh/dbcommenter-scan-overload Merge branch 'master' into dougqh/dbcommenter-scan-overload Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
refactor: group karate instrumentation modules under karate/ feat: test visibility for karate v2 Merge branch 'master' into daniel.mohedano/karate-v2-instrumentation Co-authored-by: daniel.mohedano <daniel.mohedano@datadoghq.com>
Disallow AgentTracer.forceRegister(null) Callers should pass NOOP_TRACER explicitly instead of null. Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Do not run all system test VMs on MQ Co-authored-by: sarah.chen <sarah.chen@datadoghq.com>
Mark testDynamicInstrumentationEnablementWithLineProbe as Flaky Co-authored-by: sarah.chen <sarah.chen@datadoghq.com>
…1950) Move perf-review skill to .agents/skills to match repo convention Skills live canonically under .agents/skills/<name>, with a .claude/skills/<name> symlink so Claude Code still discovers them. perf-review (landed in #11912) was the outlier -- stored as real files under .claude/skills. Move it to .agents/skills/perf-review, add the compatibility symlink matching the other five skills, and point the AGENTS.md reference at the canonical path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Move akka context swap test to forked ensure actorsystem is cleaned up add latestDepForkedTests Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
feat: execution instrumentation for karate v2 chore: spotless Co-authored-by: daniel.mohedano <daniel.mohedano@datadoghq.com>
Remove unneded akka/pekko exlcusion Co-authored-by: andrea.marziali <andrea.marziali@datadoghq.com>
feat(ci): Report failed flaky tests as skip fix(ci): Fix label documentation feat(ci): Report all tests as skip instead Co-authored-by: bruce.bujon <bruce.bujon@datadoghq.com>
#11958) InternalTagAdder: defensively guard against null prebuilt tagmap entry Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Add RUM offset write regression coverage Fix RUM injection for offset writes Merge branch 'master' into codex/fix-rum-injection-offset-writes Preserve boundary-spanning RUM injection matches Refine RUM injection offset writes Consolidate Spring Boot WebMVC smoke tests Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Update configuration documentation for clarity Clarified instructions for introducing new configurations and noted auto-generated version in the Feature Parity Dashboard. Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Make the TagMap Entry pathway null-tolerant create(Object)/create(CharSequence) may return null for a null or empty value, and the Entry sinks -- getAndSet(Entry) / set(EntryReader) -- treat a null Entry as a no-op, so a null/empty value flows through the Entry pathway as "no tag" without any caller guarding. create(Object) now applies the empty-CharSequence check by runtime type, so the null/empty => absent convention holds regardless of the static type at the call site. The strict (key,value) setters keep their contract -- their values are now @nonnull -- so null tolerance is scoped to the Entry pathway. The annotations make the split self-describing. Fixes a latent NPE by construction: RemoteHostnameAdder sets create(TRACER_HOST, hostname) guarding only null, not empty, so an empty hostname previously NPE'd on set(null). Caller-side guard cleanup (incl. the redundant #11958 guard) is left to a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Mark tag keys @nonnull on the TagMap write/create surface A tag has no valid null key, so put/set/getAndSet/create now take @nonnull tag. This completes the null contract alongside the value/Entry side: keys are strict (null = a bug), values/Entries on the Entry pathway are tolerant (null = no tag). Scoped to the write/create surface; read/lookup keys (getString, remove, getXxxOrDefault) are left for a possible follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Brace single-statement null-check ifs per style convention Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
we migrate 20 tests: - TraceMapperV04PayloadTest - TraceMapperV05PayloadTest - TraceMapperV1PayloadTest - DDEvpProxyApiTest - DDIntakeApiTest - DDIntakeTraceInterceptorTest - DDIntakeTrackTypeResolverTest - DDAgentApiTest - DDAgentWriterCombinedTest - DDAgentWriterTest - DDIntakeWriterCombinedTest - DDIntakeWriterTest - MultiWriterTest - PayloadDispatcherImplTest - PrioritizationTest - SerializationTest - SpanSamplingWorkerTest - TraceMapperTest - TraceProcessingWorkerTest - WriterFactoryTest # Conflicts: # utils/junit-utils/src/main/java/datadog/trace/junit/utils/tabletest/SamplingMechanismConverter.java # Conflicts: # dd-trace-core/src/test/groovy/datadog/trace/common/writer/TraceMapperTest.groovy # dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV1PayloadTest.groovy # Conflicts: # dd-trace-core/src/test/groovy/datadog/trace/common/writer/PayloadDispatcherImplTest.groovy
spotless
jpbempel
force-pushed
the
jpbempel/g2j-core-pt12
branch
from
July 16, 2026 08:05
8796f31 to
4d30733
Compare
Contributor
|
Shall we go ahead with #11619 instead ? cc @PerfectSlayer |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
we migrate 20 tests:
TraceMapperV04PayloadTest
TraceMapperV05PayloadTest
TraceMapperV1PayloadTest
DDEvpProxyApiTest
DDIntakeApiTest
DDIntakeTraceInterceptorTest
DDIntakeTrackTypeResolverTest
DDAgentApiTest
DDAgentWriterCombinedTest
DDAgentWriterTest
DDIntakeWriterCombinedTest
DDIntakeWriterTest
MultiWriterTest
PayloadDispatcherImplTest
PrioritizationTest
SerializationTest
SpanSamplingWorkerTest
TraceMapperTest
TraceProcessingWorkerTest
WriterFactoryTest
Motivation
this is part of the effort to migrate groovy tests to Java/JUnit
part1: #11053
part2: #11062
part3: #11085
part4: #11146
part5: #11217
part6: #11362
part7: #11374
part8: #11437
part9: #11488
part10: #11543
part11: #11566 Additional Notes
Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issue/merge. You can also:/merge --commit-message "..."/merge -c/merge -f --reason "reason"; please use this judiciously, as some checks do not run at the PR-level (note: the PR still needs to be mergeable, this will only skip the pre-merge build)Jira ticket: [PROJ-IDENT]