Skip to content

Commit 69d7527

Browse files
committed
refactor(remote_config): move appsec-specific logic to appsec folder
Resolves TODO by decoupling the remote_config module from appsec, improving separation of concerns and module independence. Problem: The remote_config module contained appsec-specific code including WAF update capabilities, ASM_FEATURES handlers, and user tracking configuration. This created tight coupling between core remote config and appsec, making the remote_config module difficult to understand and maintain in isolation. Solution: Extract all appsec-specific remote config logic into a new appsec/remote_config.js module. The core remote_config module now focuses solely on APM tracing capabilities, while appsec manages its own remote config integration. The proxy.js orchestrator wires them together at initialization. Benefits: - Clear ownership: appsec folder contains all appsec functionality - Reduced coupling: remote_config has no knowledge of appsec - Better testability: each module tested independently - Improved maintainability: easier to understand each module's scope - Startup optimization: lazy loading preserved for serverless The appsec module now stores its own RC instance internally and manages its lifecycle independently, eliminating cross-module dependencies.
1 parent c18a9fe commit 69d7527

File tree

7 files changed

+596
-454
lines changed

7 files changed

+596
-454
lines changed

packages/dd-trace/src/appsec/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const log = require('../log')
44
const RuleManager = require('./rule_manager')
5-
const remoteConfig = require('../remote_config')
5+
const appsecRemoteConfig = require('./remote_config')
66
const {
77
bodyParser,
88
cookieParser,
@@ -63,7 +63,7 @@ function enable (_config) {
6363

6464
RuleManager.loadRules(_config.appsec)
6565

66-
remoteConfig.enableWafUpdate(_config.appsec)
66+
appsecRemoteConfig.enableWafUpdate(_config.appsec)
6767

6868
Reporter.init(_config.appsec)
6969

@@ -373,7 +373,7 @@ function disable () {
373373
graphql.disable()
374374
rasp.disable()
375375

376-
remoteConfig.disableWafUpdate()
376+
appsecRemoteConfig.disableWafUpdate()
377377

378378
apiSecuritySampler.disable()
379379

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
'use strict'
2+
3+
const Activation = require('./activation')
4+
const { setCollectionMode } = require('./user_tracking')
5+
const log = require('../log')
6+
const { updateConfig } = require('../telemetry')
7+
const RemoteConfigCapabilities = require('../remote_config/capabilities')
8+
9+
let autoUserInstrumModeId
10+
let rc
11+
12+
/**
13+
* Configures remote config handlers for appsec features
14+
* @param {Object} rcInstance - RemoteConfigManager instance
15+
*
16+
* @param {Object} config - Tracer config
17+
* @param {Object} appsec - Appsec module
18+
*/
19+
function enable (rcInstance, config, appsec) {
20+
rc = rcInstance
21+
const activation = Activation.fromConfig(config)
22+
23+
if (activation !== Activation.DISABLED) {
24+
if (activation === Activation.ONECLICK) {
25+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
26+
}
27+
28+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_AUTO_USER_INSTRUM_MODE, true)
29+
30+
rc.setProductHandler('ASM_FEATURES', (action, rcConfig, configId) => {
31+
if (!rcConfig) return
32+
33+
// this is put before other handlers because it can reject the config
34+
if (typeof rcConfig.auto_user_instrum?.mode === 'string') {
35+
if (action === 'apply' || action === 'modify') {
36+
// check if there is already a config applied with this field
37+
if (autoUserInstrumModeId && configId !== autoUserInstrumModeId) {
38+
log.error('[RC] Multiple auto_user_instrum received in ASM_FEATURES. Discarding config')
39+
// eslint-disable-next-line no-throw-literal
40+
throw 'Multiple auto_user_instrum.mode received in ASM_FEATURES'
41+
}
42+
43+
setCollectionMode(rcConfig.auto_user_instrum.mode)
44+
autoUserInstrumModeId = configId
45+
} else if (configId === autoUserInstrumModeId) {
46+
setCollectionMode(config.appsec.eventTracking.mode)
47+
autoUserInstrumModeId = null
48+
}
49+
}
50+
51+
if (activation === Activation.ONECLICK) {
52+
enableOrDisableAppsec(action, rcConfig, config, appsec)
53+
}
54+
})
55+
}
56+
}
57+
58+
/**
59+
* Enables or disables appsec based on remote config
60+
*
61+
* @param {string} action - 'apply', 'modify', or 'unapply'
62+
* @param {Object} rcConfig - Remote config
63+
* @param {Object} config - Tracer config
64+
* @param {Object} appsec - Appsec module
65+
*/
66+
function enableOrDisableAppsec (action, rcConfig, config, appsec) {
67+
if (typeof rcConfig.asm?.enabled === 'boolean') {
68+
const isRemoteConfigControlling = action === 'apply' || action === 'modify'
69+
const shouldEnable = isRemoteConfigControlling
70+
? rcConfig.asm.enabled // take control
71+
: config.appsec.enabled // give back control to local config
72+
73+
if (shouldEnable) {
74+
appsec.enable(config)
75+
} else {
76+
appsec.disable()
77+
}
78+
79+
updateConfig([
80+
{
81+
name: 'appsec.enabled',
82+
origin: isRemoteConfigControlling ? 'remote_config' : config.getOrigin('appsec.enabled'),
83+
value: shouldEnable
84+
}
85+
], config)
86+
}
87+
}
88+
89+
/**
90+
* Enables WAF update capabilities for remote config
91+
*
92+
* @param {Object} appsecConfig - Appsec config
93+
*/
94+
function enableWafUpdate (appsecConfig) {
95+
if (rc && appsecConfig && !appsecConfig.rules) {
96+
// dirty require to make startup faster for serverless
97+
const { ASM_WAF_PRODUCTS } = require('./rc-products')
98+
const RuleManager = require('./rule_manager')
99+
100+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, true)
101+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, true)
102+
// TODO: we should have a different capability for rule override
103+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_DD_RULES, true)
104+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXCLUSIONS, true)
105+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_REQUEST_BLOCKING, true)
106+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RESPONSE_BLOCKING, true)
107+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_RULES, true)
108+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, true)
109+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, true)
110+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_PROCESSOR_OVERRIDES, true)
111+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_DATA_SCANNERS, true)
112+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXCLUSION_DATA, true)
113+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_ENDPOINT_FINGERPRINT, true)
114+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_SESSION_FINGERPRINT, true)
115+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, true)
116+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, true)
117+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, true)
118+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true)
119+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXTENDED_DATA_COLLECTION, true)
120+
121+
if (appsecConfig.rasp?.enabled) {
122+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, true)
123+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SSRF, true)
124+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_LFI, true)
125+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SHI, true)
126+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_CMDI, true)
127+
}
128+
129+
rc.subscribeProducts(...ASM_WAF_PRODUCTS)
130+
rc.setBatchHandler(ASM_WAF_PRODUCTS, RuleManager.updateWafFromRC)
131+
}
132+
}
133+
134+
/**
135+
* Disables WAF update capabilities for remote config
136+
*/
137+
function disableWafUpdate () {
138+
if (rc) {
139+
const { ASM_WAF_PRODUCTS } = require('./rc-products')
140+
const RuleManager = require('./rule_manager')
141+
142+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, false)
143+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, false)
144+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_DD_RULES, false)
145+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXCLUSIONS, false)
146+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_REQUEST_BLOCKING, false)
147+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RESPONSE_BLOCKING, false)
148+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_RULES, false)
149+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, false)
150+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, false)
151+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_PROCESSOR_OVERRIDES, false)
152+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_DATA_SCANNERS, false)
153+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXCLUSION_DATA, false)
154+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_ENDPOINT_FINGERPRINT, false)
155+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_SESSION_FINGERPRINT, false)
156+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, false)
157+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, false)
158+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, false)
159+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, false)
160+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_EXTENDED_DATA_COLLECTION, false)
161+
162+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, false)
163+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SSRF, false)
164+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_LFI, false)
165+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SHI, false)
166+
rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_CMDI, false)
167+
168+
rc.unsubscribeProducts(...ASM_WAF_PRODUCTS)
169+
rc.removeBatchHandler(RuleManager.updateWafFromRC)
170+
}
171+
}
172+
173+
module.exports = {
174+
enable,
175+
enableWafUpdate,
176+
disableWafUpdate
177+
}

packages/dd-trace/src/proxy.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class Tracer extends NoopProxy {
126126
}
127127

128128
if (config.remoteConfig.enabled && !config.isCiVisibility) {
129-
const rc = require('./remote_config').enable(config, this._modules.appsec)
129+
const rc = require('./remote_config').enable(config)
130130

131131
rc.setProductHandler('APM_TRACING', (action, conf) => {
132132
if (action === 'unapply') {
@@ -156,6 +156,11 @@ class Tracer extends NoopProxy {
156156
this._flare.module.send(conf.args)
157157
})
158158

159+
if (this._modules.appsec) {
160+
const appsecRemoteConfig = require('./appsec/remote_config')
161+
appsecRemoteConfig.enable(rc, config, this._modules.appsec)
162+
}
163+
159164
if (config.dynamicInstrumentation.enabled) {
160165
DynamicInstrumentation.start(config, rc)
161166
}

0 commit comments

Comments
 (0)