Skip to content

Commit

Permalink
merg confs
Browse files Browse the repository at this point in the history
  • Loading branch information
lievan committed Jan 10, 2025
2 parents 715bebc + 5e68823 commit 94a4a34
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 102 deletions.
52 changes: 48 additions & 4 deletions ddtrace/appsec/_iast/_ast/ast_patching.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from sys import version_info
import textwrap
from types import ModuleType
from typing import Iterable
from typing import Optional
from typing import Text
from typing import Tuple
Expand Down Expand Up @@ -327,6 +328,49 @@
log = get_logger(__name__)


class _TrieNode:
__slots__ = ("children", "is_end")

def __init__(self):
self.children = {}
self.is_end = False

def __iter__(self):
if self.is_end:
yield ("", None)
else:
for k, v in self.children.items():
yield (k, dict(v))


def build_trie(words: Iterable[str]) -> _TrieNode:
root = _TrieNode()
for word in words:
node = root
for char in word:
if char not in node.children:
node.children[char] = _TrieNode()
node = node.children[char]
node.is_end = True
return root


_TRIE_ALLOWLIST = build_trie(IAST_ALLOWLIST)
_TRIE_DENYLIST = build_trie(IAST_DENYLIST)


def _trie_has_prefix_for(trie: _TrieNode, string: str) -> bool:
node = trie
for char in string:
node = node.children.get(char)
if not node:
return False

if node.is_end:
return True
return node.is_end


def get_encoding(module_path: Text) -> Text:
"""
First tries to detect the encoding for the file,
Expand All @@ -341,11 +385,11 @@ def get_encoding(module_path: Text) -> Text:
return ENCODING


_NOT_PATCH_MODULE_NAMES = _stdlib_for_python_version() | set(builtin_module_names)
_NOT_PATCH_MODULE_NAMES = {i.lower() for i in _stdlib_for_python_version() | set(builtin_module_names)}


def _in_python_stdlib(module_name: str) -> bool:
return module_name.split(".")[0].lower() in [x.lower() for x in _NOT_PATCH_MODULE_NAMES]
return module_name.split(".")[0].lower() in _NOT_PATCH_MODULE_NAMES


def _should_iast_patch(module_name: Text) -> bool:
Expand All @@ -359,10 +403,10 @@ def _should_iast_patch(module_name: Text) -> bool:
# diff = max_allow - max_deny
# return diff > 0 or (diff == 0 and not _in_python_stdlib_or_third_party(module_name))
dotted_module_name = module_name.lower() + "."
if dotted_module_name.startswith(IAST_ALLOWLIST):
if _trie_has_prefix_for(_TRIE_ALLOWLIST, dotted_module_name):
log.debug("IAST: allowing %s. it's in the IAST_ALLOWLIST", module_name)
return True
if dotted_module_name.startswith(IAST_DENYLIST):
if _trie_has_prefix_for(_TRIE_DENYLIST, dotted_module_name):
log.debug("IAST: denying %s. it's in the IAST_DENYLIST", module_name)
return False
if _in_python_stdlib(module_name):
Expand Down
2 changes: 1 addition & 1 deletion ddtrace/appsec/_python_info/stdlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
from .module_names_py312 import STDLIB_MODULE_NAMES


def _stdlib_for_python_version(): # type: () -> set
def _stdlib_for_python_version(): # type: () -> set[str]
return STDLIB_MODULE_NAMES
14 changes: 7 additions & 7 deletions ddtrace/llmobs/_evaluators/ragas/context_precision.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def __init__(self, llmobs_service):
"""
super().__init__(llmobs_service)
self.ragas_context_precision_instance = self._get_context_precision_instance()
self.context_precision_output_parser = self.mini_ragas.RagasoutputParser(
pydantic_object=self.mini_ragas.ContextPrecisionVerification
self.context_precision_output_parser = self.ragas_dependencies.RagasoutputParser(
pydantic_object=self.ragas_dependencies.ContextPrecisionVerification
)

def _get_context_precision_instance(self):
Expand All @@ -55,11 +55,11 @@ def _get_context_precision_instance(self):
ragas evaluator is updated with the latest ragas context precision instance
instance AND has an non-null llm
"""
if self.mini_ragas.context_precision is None:
if self.ragas_dependencies.context_precision is None:
return None
ragas_context_precision_instance = self.mini_ragas.context_precision
ragas_context_precision_instance = self.ragas_dependencies.context_precision
if not ragas_context_precision_instance.llm:
ragas_context_precision_instance.llm = self.mini_ragas.llm_factory()
ragas_context_precision_instance.llm = self.ragas_dependencies.llm_factory()
return ragas_context_precision_instance

def evaluate(self, span_event: dict) -> Tuple[Union[float, str], Optional[dict]]:
Expand Down Expand Up @@ -125,10 +125,10 @@ def evaluate(self, span_event: dict) -> Tuple[Union[float, str], Optional[dict]]

answers = []
for response in responses:
agg_answer = self.mini_ragas.ensembler.from_discrete([response], "verdict")
agg_answer = self.ragas_dependencies.ensembler.from_discrete([response], "verdict")
if agg_answer:
try:
agg_answer = self.mini_ragas.ContextPrecisionVerification.parse_obj(agg_answer[0])
agg_answer = self.ragas_dependencies.ContextPrecisionVerification.parse_obj(agg_answer[0])
except Exception as e:
logger.debug(
"Failed to parse context precision verification for `ragas_context_precision`",
Expand Down
114 changes: 54 additions & 60 deletions ddtrace/profiling/collector/_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,69 +179,63 @@ def acquire(self, *args, **kwargs):

def _release(self, inner_func, *args, **kwargs):
# type (typing.Any, typing.Any) -> None

start = None
if hasattr(self, "_self_acquired_at"):
# _self_acquired_at is only set when the acquire was captured
# if it's not set, we're not capturing the release
start = self._self_acquired_at

try:
return inner_func(*args, **kwargs)
finally:
try:
if hasattr(self, "_self_acquired_at"):
try:
end = time.monotonic_ns()
thread_id, thread_name = _current_thread()
task_id, task_name, task_frame = _task.get_task(thread_id)
lock_name = (
"%s:%s" % (self._self_init_loc, self._self_name) if self._self_name else self._self_init_loc
)

if task_frame is None:
# See the comments in _acquire
frame = sys._getframe(2)
else:
frame = task_frame

frames, nframes = _traceback.pyframe_to_frames(frame, self._self_max_nframes)

if self._self_export_libdd_enabled:
thread_native_id = _threading.get_thread_native_id(thread_id)

handle = ddup.SampleHandle()
handle.push_monotonic_ns(end)
handle.push_lock_name(lock_name)
handle.push_release(
end - self._self_acquired_at, 1
) # AFAICT, capture_pct does not adjust anything here
handle.push_threadinfo(thread_id, thread_native_id, thread_name)
handle.push_task_id(task_id)
handle.push_task_name(task_name)

if self._self_tracer is not None:
handle.push_span(self._self_tracer.current_span())
for frame in frames:
handle.push_frame(frame.function_name, frame.file_name, 0, frame.lineno)
handle.flush_sample()
else:
event = self.RELEASE_EVENT_CLASS(
lock_name=lock_name,
frames=frames,
nframes=nframes,
thread_id=thread_id,
thread_name=thread_name,
task_id=task_id,
task_name=task_name,
locked_for_ns=end - self._self_acquired_at,
sampling_pct=self._self_capture_sampler.capture_pct,
)

if self._self_tracer is not None:
event.set_trace_info(
self._self_tracer.current_span(), self._self_endpoint_collection_enabled
)

self._self_recorder.push_event(event)
finally:
del self._self_acquired_at
except Exception as e:
LOG.warning("Error recording lock release event: %s", e)
pass # nosec
if start is not None:
end = time.monotonic_ns()
thread_id, thread_name = _current_thread()
task_id, task_name, task_frame = _task.get_task(thread_id)
lock_name = "%s:%s" % (self._self_init_loc, self._self_name) if self._self_name else self._self_init_loc

if task_frame is None:
# See the comments in _acquire
frame = sys._getframe(2)
else:
frame = task_frame

frames, nframes = _traceback.pyframe_to_frames(frame, self._self_max_nframes)

if self._self_export_libdd_enabled:
thread_native_id = _threading.get_thread_native_id(thread_id)

handle = ddup.SampleHandle()
handle.push_monotonic_ns(end)
handle.push_lock_name(lock_name)
handle.push_release(end - start, 1) # AFAICT, capture_pct does not adjust anything here
handle.push_threadinfo(thread_id, thread_native_id, thread_name)
handle.push_task_id(task_id)
handle.push_task_name(task_name)

if self._self_tracer is not None:
handle.push_span(self._self_tracer.current_span())
for frame in frames:
handle.push_frame(frame.function_name, frame.file_name, 0, frame.lineno)
handle.flush_sample()
else:
event = self.RELEASE_EVENT_CLASS(
lock_name=lock_name,
frames=frames,
nframes=nframes,
thread_id=thread_id,
thread_name=thread_name,
task_id=task_id,
task_name=task_name,
locked_for_ns=end - start,
sampling_pct=self._self_capture_sampler.capture_pct,
)

if self._self_tracer is not None:
event.set_trace_info(self._self_tracer.current_span(), self._self_endpoint_collection_enabled)

self._self_recorder.push_event(event)

def release(self, *args, **kwargs):
return self._release(self.__wrapped__.release, *args, **kwargs)
Expand Down
22 changes: 11 additions & 11 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -214,23 +214,23 @@ test = [
# if you add or remove a version here, please also update the parallelism parameter
# in .circleci/config.templ.yml
[[envs.appsec_threats_django.matrix]]
python = ["3.7", "3.9"]
python = ["3.8", "3.9"]
django = ["~=2.2"]

[[envs.appsec_threats_django.matrix]]
python = ["3.7", "3.9", "3.10"]
python = ["3.8", "3.9", "3.10"]
django = ["~=3.2"]

[[envs.appsec_threats_django.matrix]]
python = ["3.8", "3.10"]
django = ["==4.0.10"]

[[envs.appsec_threats_django.matrix]]
python = ["3.8", "3.10", "3.12"]
python = ["3.8", "3.11", "3.13"]
django = ["~=4.2"]

[[envs.appsec_threats_django.matrix]]
python = ["3.10", "3.12"]
python = ["3.10", "3.13"]
django = ["~=5.1"]


Expand Down Expand Up @@ -262,21 +262,21 @@ test = [
# if you add or remove a version here, please also update the parallelism parameter
# in .circleci/config.templ.yml
[[envs.appsec_threats_flask.matrix]]
python = ["3.7", "3.9"]
python = ["3.8", "3.9"]
flask = ["~=1.1"]
markupsafe = ["~=1.1"]

[[envs.appsec_threats_flask.matrix]]
python = ["3.7", "3.9"]
python = ["3.8", "3.9"]
flask = ["==2.1.3"]
werkzeug = ["<3.0"]

[[envs.appsec_threats_flask.matrix]]
python = ["3.8", "3.9", "3.12"]
python = ["3.8", "3.10", "3.13"]
flask = ["~=2.3"]

[[envs.appsec_threats_flask.matrix]]
python = ["3.8", "3.10", "3.12"]
python = ["3.8", "3.11", "3.13"]
flask = ["~=3.0"]

## ASM Native IAST module
Expand Down Expand Up @@ -327,16 +327,16 @@ test = [
# if you add or remove a version here, please also update the parallelism parameter
# in .circleci/config.templ.yml
[[envs.appsec_threats_fastapi.matrix]]
python = ["3.7", "3.9", "3.11"]
python = ["3.8", "3.10", "3.13"]
fastapi = ["==0.86.0"]
anyio = ["==3.7.1"]

[[envs.appsec_threats_fastapi.matrix]]
python = ["3.7", "3.9", "3.12"]
python = ["3.8", "3.10", "3.13"]
fastapi = ["==0.94.1"]

[[envs.appsec_threats_fastapi.matrix]]
python = ["3.8", "3.10", "3.12"]
python = ["3.8", "3.10", "3.13"]
fastapi = ["~=0.114.2"]


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
profiling: This fix resolves a data race issue accessing lock's acquired
time, leading to an ``AttributeError``: ``_Profiled_ThreadingLock`` object
has no attribute ``self_acquired_at``
Loading

0 comments on commit 94a4a34

Please sign in to comment.