Skip to content

Commit c171a65

Browse files
committed
[appsec] Integrate SCA instrumentation with agent bootstrap and wire Instrumentation API
Completes end-to-end integration of SCA hot instrumentation by wiring the Java Instrumentation API through the agent initialization chain. The Instrumentation instance is now passed from Agent.start() → AppSecSystem.start() → AppSecConfigServiceImpl.setInstrumentation(), enabling dynamic bytecode transformation when SCA configs arrive via Remote Config.
1 parent d6fd88f commit c171a65

File tree

3 files changed

+29
-15
lines changed

3 files changed

+29
-15
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ public void execute() {
659659
resumeRemoteComponents();
660660
}
661661

662-
maybeStartAppSec(scoClass, sco);
662+
maybeStartAppSec(instrumentation, scoClass, sco);
663663
maybeStartCiVisibility(instrumentation, scoClass, sco);
664664
maybeStartLLMObs(instrumentation, scoClass, sco);
665665
// start debugger before remote config to subscribe to it before starting to poll
@@ -973,7 +973,7 @@ private static void maybeStartAiGuard() {
973973
}
974974
}
975975

976-
private static void maybeStartAppSec(Class<?> scoClass, Object o) {
976+
private static void maybeStartAppSec(Instrumentation inst, Class<?> scoClass, Object o) {
977977

978978
try {
979979
// event tracking SDK must be available for customers even if AppSec is fully disabled
@@ -990,21 +990,22 @@ private static void maybeStartAppSec(Class<?> scoClass, Object o) {
990990

991991
try {
992992
SubscriptionService ss = AgentTracer.get().getSubscriptionService(RequestContextSlot.APPSEC);
993-
startAppSec(ss, scoClass, o);
993+
startAppSec(inst, ss, scoClass, o);
994994
} catch (Exception e) {
995995
log.error("Error starting AppSec System", e);
996996
}
997997

998998
StaticEventLogger.end("AppSec");
999999
}
10001000

1001-
private static void startAppSec(SubscriptionService ss, Class<?> scoClass, Object sco) {
1001+
private static void startAppSec(
1002+
Instrumentation inst, SubscriptionService ss, Class<?> scoClass, Object sco) {
10021003
try {
10031004
final Class<?> appSecSysClass =
10041005
AGENT_CLASSLOADER.loadClass("com.datadog.appsec.AppSecSystem");
10051006
final Method appSecInstallerMethod =
1006-
appSecSysClass.getMethod("start", SubscriptionService.class, scoClass);
1007-
appSecInstallerMethod.invoke(null, ss, sco);
1007+
appSecSysClass.getMethod("start", Instrumentation.class, SubscriptionService.class, scoClass);
1008+
appSecInstallerMethod.invoke(null, inst, ss, sco);
10081009
} catch (final Throwable ex) {
10091010
log.warn("Not starting AppSec subsystem: {}", ex.getMessage());
10101011
}

dd-java-agent/appsec/src/main/java/com/datadog/appsec/AppSecSystem.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,12 @@ public class AppSecSystem {
4646
private static final AtomicBoolean API_SECURITY_INITIALIZED = new AtomicBoolean(false);
4747
private static volatile ApiSecuritySampler API_SECURITY_SAMPLER = new ApiSecuritySampler.NoOp();
4848

49-
public static void start(SubscriptionService gw, SharedCommunicationObjects sco) {
49+
public static void start(
50+
java.lang.instrument.Instrumentation inst,
51+
SubscriptionService gw,
52+
SharedCommunicationObjects sco) {
5053
try {
51-
doStart(gw, sco);
54+
doStart(inst, gw, sco);
5255
} catch (AbortStartupException ase) {
5356
throw ase;
5457
} catch (RuntimeException | Error e) {
@@ -58,7 +61,10 @@ public static void start(SubscriptionService gw, SharedCommunicationObjects sco)
5861
}
5962
}
6063

61-
private static void doStart(SubscriptionService gw, SharedCommunicationObjects sco) {
64+
private static void doStart(
65+
java.lang.instrument.Instrumentation inst,
66+
SubscriptionService gw,
67+
SharedCommunicationObjects sco) {
6268
final Config config = Config.get();
6369
ProductActivation appSecEnabledConfig = config.getAppSecActivation();
6470
if (appSecEnabledConfig == ProductActivation.FULLY_DISABLED) {
@@ -97,6 +103,9 @@ private static void doStart(SubscriptionService gw, SharedCommunicationObjects s
97103

98104
setActive(appSecEnabledConfig == ProductActivation.FULLY_ENABLED);
99105

106+
// Initialize SCA instrumentation before subscribing to Remote Config
107+
APP_SEC_CONFIG_SERVICE.setInstrumentation(inst);
108+
100109
APP_SEC_CONFIG_SERVICE.maybeSubscribeConfigPolling();
101110

102111
Blocking.setBlockingService(new BlockingServiceImpl(REPLACEABLE_EVENT_PRODUCER));

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/AppSecSystemSpecification.groovy

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,18 @@ import static datadog.trace.api.gateway.Events.EVENTS
3333
class AppSecSystemSpecification extends DDSpecification {
3434
SubscriptionService subService = Mock()
3535
ConfigurationPoller poller = Mock()
36+
java.lang.instrument.Instrumentation inst = Mock() {
37+
isRetransformClassesSupported() >> true
38+
getAllLoadedClasses() >> ([] as Class[])
39+
}
3640

3741
def cleanup() {
3842
AppSecSystem.stop()
3943
}
4044

4145
void 'registers powerwaf module'() {
4246
when:
43-
AppSecSystem.start(subService, sharedCommunicationObjects())
47+
AppSecSystem.start(inst, subService, sharedCommunicationObjects())
4448

4549
then:
4650
'ddwaf' in AppSecSystem.startedModulesInfo
@@ -51,7 +55,7 @@ class AppSecSystemSpecification extends DDSpecification {
5155
injectSysConfig('dd.appsec.rules', '/file/that/does/not/exist')
5256

5357
when:
54-
AppSecSystem.start(subService, sharedCommunicationObjects())
58+
AppSecSystem.start(inst, subService, sharedCommunicationObjects())
5559

5660
then:
5761
def exception = thrown(AbortStartupException)
@@ -66,7 +70,7 @@ class AppSecSystemSpecification extends DDSpecification {
6670
rebuildConfig()
6771

6872
when: 'starting the AppSec system'
69-
AppSecSystem.start(subService, sharedCommunicationObjects())
73+
AppSecSystem.start(inst, subService, sharedCommunicationObjects())
7074

7175
then: 'an AbortStartupException should be thrown'
7276
def exception = thrown(AbortStartupException)
@@ -88,7 +92,7 @@ class AppSecSystemSpecification extends DDSpecification {
8892
injectSysConfig('dd.appsec.ipheader', 'foo-bar')
8993

9094
when:
91-
AppSecSystem.start(subService, sharedCommunicationObjects())
95+
AppSecSystem.start(inst, subService, sharedCommunicationObjects())
9296
requestEndedCB.apply(requestContext, span)
9397

9498
then:
@@ -110,7 +114,7 @@ class AppSecSystemSpecification extends DDSpecification {
110114
rebuildConfig()
111115

112116
when:
113-
AppSecSystem.start(subService, sharedCommunicationObjects())
117+
AppSecSystem.start(inst, subService, sharedCommunicationObjects())
114118

115119
then:
116120
thrown AbortStartupException
@@ -126,7 +130,7 @@ class AppSecSystemSpecification extends DDSpecification {
126130
ConfigurationEndListener savedConfEndListener
127131

128132
when:
129-
AppSecSystem.start(subService, sharedCommunicationObjects())
133+
AppSecSystem.start(inst, subService, sharedCommunicationObjects())
130134
EventProducerService initialEPS = AppSecSystem.REPLACEABLE_EVENT_PRODUCER.cur
131135

132136
then:

0 commit comments

Comments
 (0)