Skip to content

Commit 866dd76

Browse files
authored
Merge branch 'master' into bdu/remove-groovy-from-buildSrc
2 parents 8ebcbf9 + c8a3897 commit 866dd76

11 files changed

Lines changed: 154 additions & 15 deletions

File tree

dd-java-agent/agent-aiguard/src/main/java/com/datadog/aiguard/AIGuardInternal.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ public Evaluation evaluate(final List<Message> messages, final Options options)
273273
WafMetricCollector.get().aiGuardRequest(action, shouldBlock);
274274
if (shouldBlock) {
275275
span.setTag(BLOCKED_TAG, true);
276-
throw new AIGuardAbortError(action, reason, tags);
276+
throw new AIGuardAbortError(action, reason, tags, sdsFindings);
277277
}
278-
return new Evaluation(action, reason, tags);
278+
return new Evaluation(action, reason, tags, sdsFindings);
279279
}
280280
} catch (AIGuardAbortError e) {
281281
span.addThrowable(e);

dd-java-agent/agent-aiguard/src/test/groovy/com/datadog/aiguard/AIGuardInternalTests.groovy

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,13 @@ class AIGuardInternalTests extends DDSpecification {
210210
error.action == suite.action
211211
error.reason == suite.reason
212212
error.tags == suite.tags
213+
error.sds == []
213214
} else {
214215
error == null
215216
eval.action == suite.action
216217
eval.reason == suite.reason
217218
eval.tags == suite.tags
219+
eval.sds == []
218220
}
219221
assertTelemetry('ai_guard.requests', "action:$suite.action", "block:$throwAbortError", 'error:false')
220222

@@ -411,14 +413,15 @@ class AIGuardInternalTests extends DDSpecification {
411413
Map<String, Object> receivedMeta
412414

413415
when:
414-
aiguard.evaluate(PROMPT, AIGuard.Options.DEFAULT)
416+
final result = aiguard.evaluate(PROMPT, AIGuard.Options.DEFAULT)
415417

416418
then:
417419
1 * span.setMetaStruct(AIGuardInternal.META_STRUCT_TAG, _) >> {
418420
receivedMeta = it[1] as Map<String, Object>
419421
return span
420422
}
421423
receivedMeta.sds == sdsFindings
424+
result.sds == sdsFindings
422425
}
423426

424427
void 'test evaluate with empty sds findings'() {
@@ -427,19 +430,41 @@ class AIGuardInternalTests extends DDSpecification {
427430
Map<String, Object> receivedMeta
428431

429432
when:
430-
aiguard.evaluate(PROMPT, AIGuard.Options.DEFAULT)
433+
final result = aiguard.evaluate(PROMPT, AIGuard.Options.DEFAULT)
431434

432435
then:
433436
1 * span.setMetaStruct(AIGuardInternal.META_STRUCT_TAG, _) >> {
434437
receivedMeta = it[1] as Map<String, Object>
435438
return span
436439
}
437440
!receivedMeta.containsKey('sds')
441+
result.sds == (sdsFindings ?: [])
438442

439443
where:
440444
sdsFindings << [null, []]
441445
}
442446

447+
void 'test evaluate with sds findings in abort error'() {
448+
given:
449+
final sdsFindings = [
450+
[
451+
rule_display_name: 'Credit Card Number',
452+
rule_tag: 'credit_card',
453+
category: 'pii',
454+
matched_text: '4111111111111111',
455+
location: [start_index: 10, end_index_exclusive: 26, path: 'messages[0].content[0].text']
456+
]
457+
]
458+
final aiguard = mockClient(200, [data: [attributes: [action: 'ABORT', reason: 'PII detected', tags: ['pii'], sds_findings: sdsFindings, is_blocking_enabled: true]]])
459+
460+
when:
461+
aiguard.evaluate(PROMPT, new AIGuard.Options().block(true))
462+
463+
then:
464+
final error = thrown(AIGuard.AIGuardAbortError)
465+
error.sds == sdsFindings
466+
}
467+
443468
void 'test missing tool name'() {
444469
given:
445470
final aiguard = mockClient(200, [data: [attributes: [action: 'ALLOW', reason: 'Just do it']]])

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import datadog.trace.api.git.GitInfoProvider;
1919
import datadog.trace.bootstrap.ContextStore;
2020
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
21+
import datadog.trace.civisibility.compiler.CompilerModuleExporter;
2122
import datadog.trace.civisibility.config.ExecutionSettings;
2223
import datadog.trace.civisibility.config.JvmInfo;
2324
import datadog.trace.civisibility.coverage.file.instrumentation.CoverageClassTransformer;
@@ -75,6 +76,10 @@ public static void start(Instrumentation inst, SharedCommunicationObjects sco) {
7576

7677
sco.createRemaining(config);
7778

79+
if (config.isCiVisibilityCompilerPluginAutoConfigurationEnabled()) {
80+
inst.addTransformer(new CompilerModuleExporter(inst));
81+
}
82+
7883
CiVisibilityMetricCollector metricCollector =
7984
config.isCiVisibilityTelemetryEnabled()
8085
? new CiVisibilityMetricCollectorImpl()
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package datadog.trace.civisibility.compiler;
2+
3+
import datadog.trace.util.JDK9ModuleAccess;
4+
import java.lang.instrument.ClassFileTransformer;
5+
import java.lang.instrument.Instrumentation;
6+
import java.security.ProtectionDomain;
7+
import java.util.concurrent.ConcurrentHashMap;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
/**
12+
* Exports jdk.compiler internal packages to the classloader that loads dd-javac-plugin.
13+
*
14+
* <p>On JDK 16+ (strong encapsulation), dd-javac-plugin's CompilerModuleOpener uses burningwave to
15+
* export these packages. On JDK 26+, burningwave fails due to Unsafe restrictions (JEP 471/498).
16+
* This transformer intercepts dd-javac-plugin class loading and does the export using
17+
* Instrumentation.redefineModule() instead.
18+
*
19+
* <p>Each Maven compilation step (compile, testCompile) may use a different classloader, so we
20+
* track which classloaders have already been exported to and re-export for new ones.
21+
*/
22+
public class CompilerModuleExporter implements ClassFileTransformer {
23+
24+
private static final Logger LOGGER = LoggerFactory.getLogger(CompilerModuleExporter.class);
25+
26+
private static final String COMPILER_PLUGIN_CLASS_PREFIX = "datadog/compiler/";
27+
private static final String[] COMPILER_PACKAGES = {
28+
"com.sun.tools.javac.api",
29+
"com.sun.tools.javac.code",
30+
"com.sun.tools.javac.comp",
31+
"com.sun.tools.javac.tree",
32+
"com.sun.tools.javac.util"
33+
};
34+
35+
private final Instrumentation inst;
36+
private final ConcurrentHashMap<ClassLoader, Boolean> exportedClassLoaders =
37+
new ConcurrentHashMap<>();
38+
39+
public CompilerModuleExporter(Instrumentation inst) {
40+
this.inst = inst;
41+
}
42+
43+
@Override
44+
public byte[] transform(
45+
ClassLoader loader,
46+
String className,
47+
Class<?> classBeingRedefined,
48+
ProtectionDomain protectionDomain,
49+
byte[] classfileBuffer) {
50+
if (loader != null && className != null && className.startsWith(COMPILER_PLUGIN_CLASS_PREFIX)) {
51+
exportedClassLoaders.computeIfAbsent(loader, this::exportJdkCompilerModule);
52+
}
53+
return null; // no bytecode modification
54+
}
55+
56+
private Boolean exportJdkCompilerModule(ClassLoader loader) {
57+
try {
58+
JDK9ModuleAccess.exportModuleToUnnamedModule(inst, "jdk.compiler", COMPILER_PACKAGES, loader);
59+
LOGGER.debug("Exported jdk.compiler to classloader {}", loader);
60+
} catch (Throwable e) {
61+
LOGGER.debug("Could not export jdk.compiler packages for compiler plugin", e);
62+
}
63+
return Boolean.TRUE;
64+
}
65+
}

dd-java-agent/instrumentation/websocket/jakarta-websocket-2.0/build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ dependencies {
2222

2323
testRuntimeOnly project(":dd-java-agent:instrumentation:websocket:javax-websocket-1.0")
2424
testImplementation group: 'org.glassfish.tyrus', name: 'tyrus-container-inmemory', version: '2.0.0'
25-
latestDepTestImplementation group: 'org.glassfish.tyrus', name: 'tyrus-container-inmemory', version: '+'
25+
// `tyrus 2.3.0-M1` pulls `grizzly 5.0.0`, whose POM imports a missing `grizzly-bom 5.0.0-SNAPSHOT`.
26+
// See issue: https://github.com/eclipse-ee4j/glassfish-grizzly/issues/2278
27+
// This fix must be revisited once correct version of `grizzly-bom` will be released.
28+
latestDepTestImplementation group: 'org.glassfish.tyrus', name: 'tyrus-container-inmemory', version: '2.2.+'
2629
}
2730

2831
tasks.named('latestDepTest', Test) {

dd-smoke-tests/gradle/src/test/groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ import spock.lang.IgnoreIf
2020
import spock.lang.Shared
2121
import spock.lang.TempDir
2222

23-
@IgnoreIf(reason = "TODO: Fix for Java 26. Javac plugin fails to populate source tags correctly.", value = {
24-
JavaVirtualMachine.isJavaVersionAtLeast(26)
25-
})
2623
class GradleDaemonSmokeTest extends AbstractGradleTest {
2724

2825
private static final String TEST_SERVICE_NAME = "test-gradle-service"

dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ import java.util.concurrent.TimeoutException
2525

2626
import static org.junit.jupiter.api.Assumptions.assumeTrue
2727

28-
@IgnoreIf(reason = "TODO: Fix for Java 26. Maven compiler fails to compile the tests for Java 26-ea.", value = {
29-
JavaVirtualMachine.isJavaVersionAtLeast(26)
30-
})
3128
@IgnoreIf(reason = "IBM8 has flaky AES-GCM TLS failures when downloading Maven artifacts", value = {
3229
JavaVirtualMachine.isIbm8()
3330
})

dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit_platform_runner/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<dependency>
5858
<groupId>org.apache.groovy</groupId>
5959
<artifactId>groovy-bom</artifactId>
60-
<version>4.0.28</version>
60+
<version>4.0.30</version>
6161
<type>pom</type>
6262
<scope>import</scope>
6363
</dependency>

dd-trace-api/src/main/java/datadog/trace/api/aiguard/AIGuard.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,15 @@ public static class AIGuardAbortError extends RuntimeException {
6969
private final Action action;
7070
private final String reason;
7171
private final List<String> tags;
72+
private final List<?> sds;
7273

73-
public AIGuardAbortError(final Action action, final String reason, final List<String> tags) {
74+
public AIGuardAbortError(
75+
final Action action, final String reason, final List<String> tags, final List<?> sds) {
7476
super(reason);
7577
this.action = action;
7678
this.reason = reason;
7779
this.tags = tags;
80+
this.sds = sds != null ? sds : Collections.emptyList();
7881
}
7982

8083
public Action getAction() {
@@ -88,6 +91,10 @@ public String getReason() {
8891
public List<String> getTags() {
8992
return tags;
9093
}
94+
95+
public List<?> getSds() {
96+
return sds;
97+
}
9198
}
9299

93100
/**
@@ -149,18 +156,22 @@ public static class Evaluation {
149156
final Action action;
150157
final String reason;
151158
final List<String> tags;
159+
final List<?> sds;
152160

153161
/**
154162
* Creates a new evaluation result.
155163
*
156164
* @param action the recommended action for the evaluated content
157165
* @param reason human-readable explanation for the decision
158166
* @param tags list of tags associated with the evaluation (e.g. indirect-prompt-injection)
167+
* @param sds list of Sensitive Data Scanner findings
159168
*/
160-
public Evaluation(final Action action, final String reason, final List<String> tags) {
169+
public Evaluation(
170+
final Action action, final String reason, final List<String> tags, final List<?> sds) {
161171
this.action = action;
162172
this.reason = reason;
163173
this.tags = tags;
174+
this.sds = sds != null ? sds : Collections.emptyList();
164175
}
165176

166177
/**
@@ -189,6 +200,15 @@ public String getReason() {
189200
public List<String> getTags() {
190201
return tags;
191202
}
203+
204+
/**
205+
* Returns the list of Sensitive Data Scanner findings.
206+
*
207+
* @return list of SDS findings.
208+
*/
209+
public List<?> getSds() {
210+
return sds;
211+
}
192212
}
193213

194214
/**

dd-trace-api/src/main/java/datadog/trace/api/aiguard/noop/NoOpEvaluator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ public final class NoOpEvaluator implements Evaluator {
1313

1414
@Override
1515
public Evaluation evaluate(final List<Message> messages, final Options options) {
16-
return new Evaluation(ALLOW, "AI Guard is not enabled", emptyList());
16+
return new Evaluation(ALLOW, "AI Guard is not enabled", emptyList(), emptyList());
1717
}
1818
}

0 commit comments

Comments
 (0)