Skip to content

chore(rcm): Remote Config refactor, publisher subscriber system #5464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 153 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
5359dfc
feat(rcm): refactor
avara1986 Mar 29, 2023
62d0854
push experiments
avara1986 Mar 31, 2023
069fd30
push experiments
avara1986 Apr 3, 2023
e00a5bc
push experiments
avara1986 Apr 3, 2023
56338e0
feat(rcm): refactor callbacks
avara1986 Apr 4, 2023
36c923c
feat(rcm): refactor callbacks
avara1986 Apr 4, 2023
101e24d
feat(rcm): refactor callbacks
avara1986 Apr 5, 2023
10eae28
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 5, 2023
5c7d5ec
fix tests
avara1986 Apr 5, 2023
ae33d55
fix tests
avara1986 Apr 5, 2023
f34000f
fix tests
avara1986 Apr 5, 2023
98200c6
fix zombie threads and processes
avara1986 Apr 5, 2023
5cfb37e
fix tests
avara1986 Apr 5, 2023
b1ef520
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 11, 2023
9898893
fix: python2 syntax error. check worker
avara1986 Apr 11, 2023
1d6aafc
fix: python2 error
avara1986 Apr 11, 2023
f990e7c
fix: profiling tests
avara1986 Apr 11, 2023
233f340
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 12, 2023
47d7103
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 13, 2023
3ebfd30
feat: migrate debugger to new RC
avara1986 Apr 13, 2023
04d4642
feat: fix attrs import
avara1986 Apr 13, 2023
f17746a
fix: codestyle
avara1986 Apr 13, 2023
61dd104
feat: migrate debugger to new RC
avara1986 Apr 13, 2023
182159b
fix debugger and profiler tests
avara1986 Apr 13, 2023
bc206ad
fix: debugger tests
avara1986 Apr 13, 2023
a679346
fix: debugger tests
avara1986 Apr 13, 2023
8238717
fix: debugger tests
avara1986 Apr 13, 2023
37b6c08
fix: debugger tests
avara1986 Apr 13, 2023
1b7650c
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 13, 2023
4b76b44
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 14, 2023
052c8fa
chore: merge RC v2 in actual RC
avara1986 Apr 14, 2023
bd54c8d
chore: add docstrings
avara1986 Apr 14, 2023
765b33e
fix: encoding error
avara1986 Apr 14, 2023
7ab7136
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 14, 2023
25c724b
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 17, 2023
6412c2a
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 17, 2023
cae6ee8
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 17, 2023
32b2951
fix: flaky test on python 3.5
avara1986 Apr 17, 2023
05fea51
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 17, 2023
a12b35f
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 18, 2023
180c7e6
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 18, 2023
218c7c8
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 18, 2023
aa07024
fix: e2e tests
avara1986 Apr 18, 2023
ef45749
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 18, 2023
33f2b42
feat(appsec): add session token to e2e tests
avara1986 Apr 19, 2023
0c65a7d
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 19, 2023
e8a192a
chore: remove prints
avara1986 Apr 19, 2023
ed7297e
fix tests
avara1986 Apr 19, 2023
44ac9b1
fix tests
avara1986 Apr 19, 2023
a8facda
fix tests
avara1986 Apr 19, 2023
5cc642d
fix tests
avara1986 Apr 19, 2023
786a707
fix tests
avara1986 Apr 19, 2023
3384314
fix tests
avara1986 Apr 19, 2023
c3696fd
fix tests
avara1986 Apr 19, 2023
f04542d
fix: python2 validations
avara1986 Apr 19, 2023
c3b8d6d
fix tests
avara1986 Apr 19, 2023
37c02ef
fix tests
avara1986 Apr 19, 2023
531ec76
fix tests
avara1986 Apr 19, 2023
c35d0e0
fix tests
avara1986 Apr 19, 2023
bf2555e
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 19, 2023
8f590df
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 20, 2023
24d5281
feat: start subscriber idempotent
avara1986 Apr 20, 2023
1720dfe
fix: disable 1click activation
avara1986 Apr 20, 2023
f662f0e
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 20, 2023
916d06c
fix tests
avara1986 Apr 20, 2023
8d0e322
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 20, 2023
e203516
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 21, 2023
b351036
feat: remove extra classes of PubSub class
avara1986 Apr 21, 2023
dd208d1
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 21, 2023
7154511
feat: update RC debugger behavior
avara1986 Apr 21, 2023
304de49
fix: codestyle
avara1986 Apr 21, 2023
7ca9309
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 21, 2023
bf005c3
fix tests
avara1986 Apr 21, 2023
d69f508
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 21, 2023
e97a33d
fix tests
avara1986 Apr 21, 2023
a23c2d1
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 21, 2023
ddc3d64
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 24, 2023
33570e2
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 24, 2023
12eb81f
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 26, 2023
e5eeee5
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Apr 27, 2023
4b67d85
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 3, 2023
00a75cc
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 5, 2023
ba3e82b
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 8, 2023
2d25c72
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 8, 2023
db1a381
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 9, 2023
af982c5
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 9, 2023
2baa5db
fix merge
avara1986 May 9, 2023
d2b3384
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 9, 2023
592bfde
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 10, 2023
33d9412
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 10, 2023
ee401e0
chore: update requirements
avara1986 May 10, 2023
17bae61
fix tests
avara1986 May 10, 2023
fc401fc
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 10, 2023
0bfa682
fix tests
avara1986 May 10, 2023
81dd96d
fix tests
avara1986 May 10, 2023
0f02659
fix tests
avara1986 May 10, 2023
7a65100
fix tests
avara1986 May 10, 2023
846b88d
fix tests
avara1986 May 10, 2023
0904157
fix tests
avara1986 May 10, 2023
92433bf
fix tests
avara1986 May 10, 2023
9ea9ebe
fix tests
avara1986 May 10, 2023
6d4d0d7
fix tests
avara1986 May 10, 2023
c8485ef
fix tests
avara1986 May 10, 2023
9e6f11d
fix tests
avara1986 May 10, 2023
7f33ec9
fix tests
avara1986 May 10, 2023
f3d2c22
fix tests
avara1986 May 10, 2023
b12d065
fix tests
avara1986 May 10, 2023
8776c5c
fix tests
avara1986 May 10, 2023
22a807f
fix tests
avara1986 May 10, 2023
dced2d5
fix tests
avara1986 May 10, 2023
f64a33e
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 10, 2023
a481348
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 11, 2023
d39b0b0
fix tests
avara1986 May 11, 2023
65c50fb
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 11, 2023
3bcc015
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 11, 2023
49da9fd
fix tests
avara1986 May 11, 2023
e35f43e
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 11, 2023
ce71a0c
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 11, 2023
b533849
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 12, 2023
b3df463
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 12, 2023
59e2fab
chore(debugger): update class and tests
avara1986 May 12, 2023
168e2ff
fix Debugger pubsub init
avara1986 May 12, 2023
f0e32be
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 16, 2023
1f28726
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 17, 2023
22108cb
chore: codestyle
avara1986 May 17, 2023
eaef50f
chore(rcm): fix debugger payloads, fix 1-click activation
avara1986 May 17, 2023
6e3df5f
chore(rcm): add debugger debug logs
avara1986 May 17, 2023
7c1e76b
chore(rcm): update tests
avara1986 May 17, 2023
8b3d7e8
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 18, 2023
79f390b
fix(rcm): update debugger callback on child process
avara1986 May 18, 2023
52b0051
chore(asm): add/update docstrings
avara1986 May 18, 2023
d0f5fc8
fix tests
avara1986 May 18, 2023
36e773f
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 18, 2023
e24aca3
fix tests
avara1986 May 18, 2023
1609e33
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 19, 2023
e6fb819
fix flaky tests
avara1986 May 19, 2023
675ebd0
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 22, 2023
d0597ab
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 22, 2023
e83986f
add TODO, explain _preprocess_results_func disabled
avara1986 May 22, 2023
dedd7c4
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 23, 2023
596ec5f
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 26, 2023
2f6dad2
fix merge
avara1986 May 26, 2023
76c651e
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 26, 2023
e2f43af
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 29, 2023
9706210
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 30, 2023
37c6c77
Update ddtrace/appsec/_remoteconfiguration.py
avara1986 May 31, 2023
c528e37
Update ddtrace/appsec/_remoteconfiguration.py
avara1986 May 31, 2023
34ae3ae
Update ddtrace/appsec/_remoteconfiguration.py
avara1986 May 31, 2023
145d8bb
Update ddtrace/appsec/_remoteconfiguration.py
avara1986 May 31, 2023
ca28260
Merge branch '1.x' into avara1986/rc_refactor
avara1986 May 31, 2023
5b70a2e
Update ddtrace/internal/remoteconfig/_pubsub.py
ZStriker19 May 31, 2023
1ffeb0b
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Jun 1, 2023
6100e98
Merge branch '1.x' into avara1986/rc_refactor
avara1986 Jun 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 134 additions & 88 deletions ddtrace/appsec/_remoteconfiguration.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import os
from typing import TYPE_CHECKING

Expand All @@ -7,8 +8,11 @@
from ddtrace.appsec.utils import _appsec_rc_file_is_not_static
from ddtrace.constants import APPSEC_ENV
from ddtrace.internal.logger import get_logger
from ddtrace.internal.remoteconfig.client import RemoteConfigCallBack
from ddtrace.internal.remoteconfig.client import RemoteConfigCallBackAfterMerge
from ddtrace.internal.remoteconfig._connectors import PublisherSubscriberConnector
from ddtrace.internal.remoteconfig._publishers import RemoteConfigPublisherMergeDicts
from ddtrace.internal.remoteconfig._pubsub import PubSub
from ddtrace.internal.remoteconfig._subscribers import RemoteConfigSubscriber
from ddtrace.internal.remoteconfig.worker import remoteconfig_poller
from ddtrace.internal.utils.formats import asbool


Expand All @@ -18,49 +22,57 @@
# handling python 2.X import error
JSONDecodeError = ValueError # type: ignore


if TYPE_CHECKING: # pragma: no cover
from typing import Any
from typing import Dict

try:
from typing import Literal
except ImportError:
# Python < 3.8. The "type ignore" is to avoid a runtime check just to silence mypy.
from typing_extensions import Literal # type: ignore
from typing import Mapping
from typing import Optional
from typing import Union

from ddtrace import Tracer

log = get_logger(__name__)


class AppSecRC(PubSub):
__subscriber_class__ = RemoteConfigSubscriber
__publisher_class__ = RemoteConfigPublisherMergeDicts
__shared_data__ = PublisherSubscriberConnector()

def __init__(self, _preprocess_results, callback):
self._publisher = self.__publisher_class__(self.__shared_data__, _preprocess_results)
self._subscriber = self.__subscriber_class__(self.__shared_data__, callback, "ASM")


def enable_appsec_rc(test_tracer=None):
# type: (Optional[Tracer]) -> None
# Tracer is a parameter for testing propose
"""Remote config will be used by ASM libraries to receive four different updates from the backend.
Each update has it’s own product:
- ASM_FEATURES product - To allow users enable or disable ASM remotely
- ASM product - To allow clients to activate or deactivate rules
- ASM_DD product - To allow the library to receive rules updates
- ASM_DATA product - To allow the library to receive list of blocked IPs and users

If environment variable `DD_APPSEC_ENABLED` is not set, registering ASM_FEATURE can enable ASM remotely. If
it's set to true, we will register the rest of the products.

Parameters `test_tracer` and `start_subscribers` are needed for testing purposes
"""
# Import tracer here to avoid a circular import
if test_tracer is None:
from ddtrace import tracer
else:
tracer = test_tracer

asm_features_callback = RCAppSecFeaturesCallBack(tracer)
asm_dd_callback = RCASMDDCallBack(tracer)
asm_callback = RCAppSecCallBack(tracer)
log.debug("[%s][P: %s] Register ASM Remote Config Callback", os.getpid(), os.getppid())
asm_callback = AppSecRC(_preprocess_results_appsec_1click_activation, _appsec_callback)

if _appsec_rc_features_is_enabled():
from ddtrace.internal.remoteconfig import RemoteConfig

RemoteConfig.register(PRODUCTS.ASM_FEATURES, asm_features_callback)
remoteconfig_poller.register(PRODUCTS.ASM_FEATURES, asm_callback)

if tracer._appsec_enabled and _appsec_rc_file_is_not_static():
from ddtrace.internal.remoteconfig import RemoteConfig

RemoteConfig.register(PRODUCTS.ASM_DATA, asm_callback) # IP Blocking
RemoteConfig.register(PRODUCTS.ASM, asm_callback) # Exclusion Filters & Custom Rules
RemoteConfig.register(PRODUCTS.ASM_DD, asm_dd_callback) # DD Rules
remoteconfig_poller.register(PRODUCTS.ASM_DATA, asm_callback) # IP Blocking
remoteconfig_poller.register(PRODUCTS.ASM, asm_callback) # Exclusion Filters & Custom Rules
remoteconfig_poller.register(PRODUCTS.ASM_DD, asm_callback) # DD Rules


def _add_rules_to_list(features, feature, message, ruleset):
Expand All @@ -71,103 +83,137 @@ def _add_rules_to_list(features, feature, message, ruleset):
if ruleset.get(feature) is None:
ruleset[feature] = []
ruleset[feature] += rules
log.debug("Reloading Appsec %s: %s", message, rules)
log.debug("Reloading Appsec %s: %s", message, str(rules)[:20])
except JSONDecodeError:
log.error("ERROR Appsec %s: invalid JSON content from remote configuration", message)


def _appsec_rules_data(tracer, features):
# type: (Tracer, Mapping[str, Any]) -> bool
def _appsec_callback(features, test_tracer=None):
# type: (Mapping[str, Any], Optional[Tracer]) -> None
config = features.get("config", {})
_appsec_1click_activation(config, test_tracer)
_appsec_rules_data(config, test_tracer)


def _appsec_rules_data(features, test_tracer):
# type: (Mapping[str, Any], Optional[Tracer]) -> bool
# Tracer is a parameter for testing propose
# Import tracer here to avoid a circular import
if test_tracer is None:
from ddtrace import tracer
else:
tracer = test_tracer

if features and tracer._appsec_processor:
ruleset = {} # type: dict[str, Optional[list[Any]]]
_add_rules_to_list(features, "rules_data", "rules data", ruleset)
_add_rules_to_list(features, "custom_rules", "custom rules", ruleset)
_add_rules_to_list(features, "rules", "Datadog rules", ruleset)
_add_rules_to_list(features, "exclusions", "exclusion filters", ruleset)
_add_rules_to_list(features, "rules_override", "rules override", ruleset)
return tracer._appsec_processor._update_rules({k: v for k, v in ruleset.items() if v is not None})
if ruleset:
return tracer._appsec_processor._update_rules({k: v for k, v in ruleset.items() if v is not None})

return False


class RCASMDDCallBack(RemoteConfigCallBack):
def __init__(self, tracer):
# type: (Tracer) -> None
self.tracer = tracer

def __call__(self, metadata, features):
if features is not None:
_appsec_rules_data(self.tracer, features)

def _preprocess_results_appsec_1click_activation(features, pubsub_instance=None):
# type: (Any, Optional[PubSub]) -> Mapping[str, Any]
"""The main process has the responsibility to enable or disable the ASM products. The child processes don't
care about that, the children only need to know about payload content.
"""
if _appsec_rc_features_is_enabled():
log.debug(
"[%s][P: %s] Receiving ASM Remote Configuration ASM_FEATURES: %s",
os.getpid(),
os.getppid(),
features.get("asm", {}),
)

class RCAppSecFeaturesCallBack(RemoteConfigCallBack):
def __init__(self, tracer):
# type: (Tracer) -> None
self.tracer = tracer
if not pubsub_instance:
pubsub_instance = AppSecRC(_preprocess_results_appsec_1click_activation, _appsec_callback)

def __call__(self, metadata, features):
rc_appsec_enabled = None
if features is not None:
self._appsec_1click_activation(features)

def _appsec_1click_activation(self, features):
# type: (Union[Literal[False], Mapping[str, Any]]) -> None
"""This callback updates appsec enabled in tracer and config instances following this logic:
```
| DD_APPSEC_ENABLED | RC Enabled | Result |
|-------------------|------------|----------|
| <not set> | <not set> | Disabled |
| <not set> | false | Disabled |
| <not set> | true | Enabled |
| false | <not set> | Disabled |
| true | <not set> | Enabled |
| false | true | Disabled |
| true | true | Enabled |
```
"""
if APPSEC_ENV in os.environ:
rc_appsec_enabled = asbool(os.environ.get(APPSEC_ENV))
elif features == {}:
rc_appsec_enabled = False
else:
asm_features = features.get("asm", {})
if asm_features is not None:
rc_appsec_enabled = asm_features.get("enabled")
log.debug(
"[%s][P: %s] ASM Remote Configuration ASM_FEATURES. Appsec enabled: %s",
os.getpid(),
os.getppid(),
rc_appsec_enabled,
)
if rc_appsec_enabled is not None:
from ddtrace.appsec._constants import PRODUCTS

if rc_appsec_enabled and _appsec_rc_file_is_not_static():
remoteconfig_poller.register(PRODUCTS.ASM_DATA, pubsub_instance) # IP Blocking
remoteconfig_poller.register(PRODUCTS.ASM, pubsub_instance) # Exclusion Filters & Custom Rules
remoteconfig_poller.register(PRODUCTS.ASM_DD, pubsub_instance) # DD Rules
else:
remoteconfig_poller.unregister(PRODUCTS.ASM_DATA)
remoteconfig_poller.unregister(PRODUCTS.ASM)
remoteconfig_poller.unregister(PRODUCTS.ASM_DD)

features["asm"] = {"enabled": rc_appsec_enabled}
return features


def _appsec_1click_activation(features, test_tracer=None):
# type: (Mapping[str, Any], Optional[Tracer]) -> None
"""This callback updates appsec enabled in tracer and config instances following this logic:
```
| DD_APPSEC_ENABLED | RC Enabled | Result |
|-------------------|------------|----------|
| <not set> | <not set> | Disabled |
| <not set> | false | Disabled |
| <not set> | true | Enabled |
| false | <not set> | Disabled |
| true | <not set> | Enabled |
| false | true | Disabled |
| true | true | Enabled |
```
"""
if _appsec_rc_features_is_enabled():
# Tracer is a parameter for testing propose
# Import tracer here to avoid a circular import
if test_tracer is None:
from ddtrace import tracer
else:
tracer = test_tracer

log.debug("[%s][P: %s] ASM_FEATURES: %s", os.getpid(), os.getppid(), str(features)[:100])
if APPSEC_ENV in os.environ:
# no one click activation if var env is set
rc_appsec_enabled = asbool(os.environ.get(APPSEC_ENV))
elif features is False:
rc_appsec_enabled = False
else:
rc_appsec_enabled = features.get("asm", {}).get("enabled")
rc_appsec_enabled = features.get("asm", {}).get("enabled", False)

log.debug("APPSEC_ENABLED: %s", rc_appsec_enabled)
if rc_appsec_enabled is not None:
from ddtrace.appsec._constants import PRODUCTS
from ddtrace.internal.remoteconfig import RemoteConfig

log.debug("Updating ASM Remote Configuration ASM_FEATURES: %s", rc_appsec_enabled)
log.debug(
"[%s][P: %s] Updating ASM Remote Configuration ASM_FEATURES: %s",
os.getpid(),
os.getppid(),
rc_appsec_enabled,
)

if rc_appsec_enabled:
if _appsec_rc_file_is_not_static():
asm_dd_callback = RCASMDDCallBack(self.tracer)
asm_callback = RCAppSecCallBack(self.tracer)
RemoteConfig.register(PRODUCTS.ASM_DATA, asm_callback) # IP Blocking
RemoteConfig.register(PRODUCTS.ASM, asm_callback) # Exclusion Filters & Custom Rules
RemoteConfig.register(PRODUCTS.ASM_DD, asm_dd_callback) # DD Rules
if not self.tracer._appsec_enabled:
self.tracer.configure(appsec_enabled=True)
if not tracer._appsec_enabled:
tracer.configure(appsec_enabled=True)
else:
config._appsec_enabled = True

else:
if _appsec_rc_file_is_not_static():
RemoteConfig.unregister(PRODUCTS.ASM_DATA)
RemoteConfig.unregister(PRODUCTS.ASM)
RemoteConfig.unregister(PRODUCTS.ASM_DD)
if self.tracer._appsec_enabled:
self.tracer.configure(appsec_enabled=False)
if tracer._appsec_enabled:
tracer.configure(appsec_enabled=False)
else:
config._appsec_enabled = False


class RCAppSecCallBack(RemoteConfigCallBackAfterMerge):
def __init__(self, tracer):
# type: (Tracer) -> None
super(RCAppSecCallBack, self).__init__()
self.tracer = tracer

def __call__(self, target, features):
# type: (str, Any) -> None
if features is not None:
_appsec_rules_data(self.tracer, features)
15 changes: 15 additions & 0 deletions ddtrace/bootstrap/sitecustomize.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

log = get_logger(__name__)


if os.environ.get("DD_GEVENT_PATCH_ALL") is not None:
deprecate(
"The environment variable DD_GEVENT_PATCH_ALL is deprecated and will be removed in a future version. ",
Expand Down Expand Up @@ -248,6 +249,20 @@ def _(threading):
else:
log.debug("additional sitecustomize found in: %s", sys.path)

if asbool(os.environ.get("DD_REMOTE_CONFIGURATION_ENABLED", "true")):
from ddtrace.internal.remoteconfig.worker import remoteconfig_poller

remoteconfig_poller.enable()

should_start_appsec_remoteconfig = config._appsec_enabled or asbool(
os.environ.get("DD_REMOTE_CONFIGURATION_ENABLED", "true")
)

if should_start_appsec_remoteconfig:
from ddtrace.appsec._remoteconfiguration import enable_appsec_rc

enable_appsec_rc()

# Loading status used in tests to detect if the `sitecustomize` has been
# properly loaded without exceptions. This must be the last action in the module
# when the execution ends with a success.
Expand Down
Loading