Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This project has custom skills that provide specialized workflows. **Always chec
**Use whenever:** Formatting code, validating style/types/security, or before committing changes.

**Purpose:** Runs targeted linting and code quality checks using `hatch run lint:*`:
- Formats code with Black and Ruff auto-fixes
- Formats code with `ruff check` and `ruff format`
- Validates style, types, and security
- Checks spelling and documentation
- Validates test infrastructure (suitespec, riotfile, etc.)
Expand Down
13 changes: 7 additions & 6 deletions .claude/skills/lint/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ hatch run lint:typing -- path/to/file.py
### Code Formatting

#### `fmt` - Format code (recommended for most edits)
Formats and validates code style using Black and Ruff.
Formats and validates code style using Ruff.

**Usage:**
```bash
Expand All @@ -63,7 +63,7 @@ hatch run lint:fmt -- ddtrace/contrib/flask/
```

**What it does:**
1. Runs Black formatter
1. Runs the Ruff formatter
2. Runs Ruff with --fix to auto-fix issues
3. Re-validates with style checks

Expand Down Expand Up @@ -94,20 +94,21 @@ hatch run lint:style -- ddtrace/
```

**What it validates:**
- Black formatting
- Ruff formatting
- Ruff linting rules
- Cython linting
- C code formatting
- CMake formatting

**When to use:** To verify style compliance before committing without auto-fixes.

#### `black_check` - Check Black formatting
Validates Python code formatting with Black (no auto-fix).
#### `format_check` - Check formatting

Validates Python code formatting with `ruff format` (no auto-fix).

**Usage:**
```bash
hatch run lint:black_check -- ddtrace/tracer.py
hatch run lint:format_check -- ddtrace/tracer.py
```

**When to use:** Quick check of Python formatting before committing.
Expand Down
16 changes: 8 additions & 8 deletions benchmarks/bm/iast_fixtures/str_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ def get_random_string_join(mystring: str) -> Text:

def get_random_string_seed(
length=12,
allowed_chars="abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
allowed_chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
): # type: (int, str) -> str
"""
Returns a securely generated random string.
Expand Down Expand Up @@ -1180,13 +1180,13 @@ def do_add_re_compile():
import re

invalid_unicode_no_surrogate = (
"[\u0001-\u0008\u000B\u000E-\u001F\u007F-\u009F\uFDD0-\uFDEF"
"\uFFFE\uFFFF\U0001FFFE\U0001FFFF\U0002FFFE\U0002FFFF"
"\U0003FFFE\U0003FFFF\U0004FFFE\U0004FFFF\U0005FFFE\U0005FFFF"
"\U0006FFFE\U0006FFFF\U0007FFFE\U0007FFFF\U0008FFFE\U0008FFFF"
"\U0009FFFE\U0009FFFF\U000AFFFE\U000AFFFF\U000BFFFE\U000BFFFF"
"\U000CFFFE\U000CFFFF\U000DFFFE\U000DFFFF\U000EFFFE\U000EFFFF"
"\U000FFFFE\U000FFFFF\U0010FFFE\U0010FFFF]"
"[\u0001-\u0008\u000b\u000e-\u001f\u007f-\u009f\ufdd0-\ufdef"
"\ufffe\uffff\U0001fffe\U0001ffff\U0002fffe\U0002ffff"
"\U0003fffe\U0003ffff\U0004fffe\U0004ffff\U0005fffe\U0005ffff"
"\U0006fffe\U0006ffff\U0007fffe\U0007ffff\U0008fffe\U0008ffff"
"\U0009fffe\U0009ffff\U000afffe\U000affff\U000bfffe\U000bffff"
"\U000cfffe\U000cffff\U000dfffe\U000dffff\U000efffe\U000effff"
"\U000ffffe\U000fffff\U0010fffe\U0010ffff]"
) # noqa:F401
_ = re.compile(invalid_unicode_no_surrogate[:-1] + eval('"\\uD800-\\uDFFF"') + "]") # pylint:disable=eval-used

Expand Down
1 change: 1 addition & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Local plugins: https://docs.pytest.org/en/3.10.1/writing_plugins.html#local-conftest-plugins
Hook reference: https://docs.pytest.org/en/3.10.1/reference.html#hook-reference
"""

import os
import re
import sys
Expand Down
1 change: 1 addition & 0 deletions ddtrace/_trace/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Any `sampled = False` trace won't be written, and can be ignored by the instrumentation.
"""

import json
from json.decoder import JSONDecodeError
from typing import Dict
Expand Down
19 changes: 11 additions & 8 deletions ddtrace/_trace/utils_valkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,17 @@ def _set_span_tags(
@contextmanager
def _instrument_valkey_cmd(pin, config_integration, instance, args):
query = stringify_cache_args(args, cmd_max_len=config_integration.cmd_max_length)
with core.context_with_data(
"valkey.command",
span_name=schematize_cache_operation(valkeyx.CMD, cache_provider=valkeyx.APP),
pin=pin,
service=trace_utils.ext_service(pin, config_integration),
span_type=SpanTypes.VALKEY,
resource=query.split(" ")[0] if config_integration.resource_only_command else query,
) as ctx, ctx.span as span:
with (
core.context_with_data(
"valkey.command",
span_name=schematize_cache_operation(valkeyx.CMD, cache_provider=valkeyx.APP),
pin=pin,
service=trace_utils.ext_service(pin, config_integration),
span_type=SpanTypes.VALKEY,
resource=query.split(" ")[0] if config_integration.resource_only_command else query,
) as ctx,
ctx.span as span,
):
_set_span_tags(span, pin, config_integration, args, instance, query)
yield ctx

Expand Down
60 changes: 30 additions & 30 deletions ddtrace/appsec/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,43 +81,43 @@ class APPSEC(metaclass=Constant_Class):
USER_LOGIN_EVENT_PREFIX_PUBLIC: Literal["appsec.events.users.login"] = "appsec.events.users.login"
USER_LOGIN_USERID: Literal["_dd.appsec.usr.id"] = "_dd.appsec.usr.id"
USER_LOGIN_USERNAME: Literal["_dd.appsec.usr.login"] = "_dd.appsec.usr.login"
USER_LOGIN_EVENT_SUCCESS_TRACK: Literal[
USER_LOGIN_EVENT_SUCCESS_TRACK: Literal["appsec.events.users.login.success.track"] = (
"appsec.events.users.login.success.track"
] = "appsec.events.users.login.success.track"
USER_LOGIN_EVENT_FAILURE_TRACK: Literal[
)
USER_LOGIN_EVENT_FAILURE_TRACK: Literal["appsec.events.users.login.failure.track"] = (
"appsec.events.users.login.failure.track"
] = "appsec.events.users.login.failure.track"
)
USER_SIGNUP_EVENT: Literal["appsec.events.users.signup.track"] = "appsec.events.users.signup.track"
USER_SIGNUP_EVENT_USERNAME: Literal["appsec.events.users.signup.usr.login"] = "appsec.events.users.signup.usr.login"
USER_SIGNUP_EVENT_USERID: Literal["appsec.events.users.signup.usr.id"] = "appsec.events.users.signup.usr.id"
USER_SIGNUP_EVENT_MODE: Literal[
USER_SIGNUP_EVENT_MODE: Literal["_dd.appsec.events.users.signup.auto.mode"] = (
"_dd.appsec.events.users.signup.auto.mode"
] = "_dd.appsec.events.users.signup.auto.mode"
AUTO_LOGIN_EVENTS_SUCCESS_MODE: Literal[
)
AUTO_LOGIN_EVENTS_SUCCESS_MODE: Literal["_dd.appsec.events.users.login.success.auto.mode"] = (
"_dd.appsec.events.users.login.success.auto.mode"
] = "_dd.appsec.events.users.login.success.auto.mode"
AUTO_LOGIN_EVENTS_FAILURE_MODE: Literal[
)
AUTO_LOGIN_EVENTS_FAILURE_MODE: Literal["_dd.appsec.events.users.login.failure.auto.mode"] = (
"_dd.appsec.events.users.login.failure.auto.mode"
] = "_dd.appsec.events.users.login.failure.auto.mode"
)
AUTO_LOGIN_EVENTS_COLLECTION_MODE: Literal["_dd.appsec.user.collection_mode"] = "_dd.appsec.user.collection_mode"
BLOCKED: Literal["appsec.blocked"] = "appsec.blocked"
EVENT: Literal["appsec.event"] = "appsec.event"
AUTO_USER_INSTRUMENTATION_MODE: Literal[
AUTO_USER_INSTRUMENTATION_MODE: Literal["DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE"] = (
"DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE"
] = "DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE"
AUTO_USER_INSTRUMENTATION_MODE_ENABLED: Literal[
)
AUTO_USER_INSTRUMENTATION_MODE_ENABLED: Literal["DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING_ENABLED"] = (
"DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING_ENABLED"
] = "DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING_ENABLED"
)
USER_MODEL_LOGIN_FIELD: Literal["DD_USER_MODEL_LOGIN_FIELD"] = "DD_USER_MODEL_LOGIN_FIELD"
USER_MODEL_EMAIL_FIELD: Literal["DD_USER_MODEL_EMAIL_FIELD"] = "DD_USER_MODEL_EMAIL_FIELD"
USER_MODEL_NAME_FIELD: Literal["DD_USER_MODEL_NAME_FIELD"] = "DD_USER_MODEL_NAME_FIELD"
PROPAGATION_HEADER: Literal["_dd.p.ts"] = "_dd.p.ts"
OBFUSCATION_PARAMETER_KEY_REGEXP: Literal[
OBFUSCATION_PARAMETER_KEY_REGEXP: Literal["DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP"] = (
"DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP"
] = "DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP"
OBFUSCATION_PARAMETER_VALUE_REGEXP: Literal[
)
OBFUSCATION_PARAMETER_VALUE_REGEXP: Literal["DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP"] = (
"DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP"
] = "DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP"
)
RC_CLIENT_ID: Literal["_dd.rc.client_id"] = "_dd.rc.client_id"
WAF_ERROR: Literal["_dd.appsec.waf.error"] = "_dd.appsec.waf.error"
RASP_ERROR: Literal["_dd.appsec.rasp.error"] = "_dd.appsec.rasp.error"
Expand Down Expand Up @@ -148,9 +148,9 @@ class IAST(metaclass=Constant_Class):
ENV_SINK_POINTS_ENABLED: Literal["DD_IAST_SINK_POINTS_ENABLED"] = "DD_IAST_SINK_POINTS_ENABLED"
ENV_PROPAGATION_DEBUG: Literal["DD_IAST_PROPAGATION_DEBUG"] = "DD_IAST_PROPAGATION_DEBUG"
ENV_REQUEST_SAMPLING: Literal["DD_IAST_REQUEST_SAMPLING"] = "DD_IAST_REQUEST_SAMPLING"
DD_IAST_VULNERABILITIES_PER_REQUEST: Literal[
DD_IAST_VULNERABILITIES_PER_REQUEST: Literal["DD_IAST_VULNERABILITIES_PER_REQUEST"] = (
"DD_IAST_VULNERABILITIES_PER_REQUEST"
] = "DD_IAST_VULNERABILITIES_PER_REQUEST"
)
DD_IAST_MAX_CONCURRENT_REQUESTS: Literal["DD_IAST_MAX_CONCURRENT_REQUESTS"] = "DD_IAST_MAX_CONCURRENT_REQUESTS"
ENV_TELEMETRY_REPORT_LVL: Literal["DD_IAST_TELEMETRY_VERBOSITY"] = "DD_IAST_TELEMETRY_VERBOSITY"
LAZY_TAINT: Literal["_DD_IAST_LAZY_TAINT"] = "_DD_IAST_LAZY_TAINT"
Expand Down Expand Up @@ -185,9 +185,9 @@ class IAST_SPAN_TAGS(metaclass=Constant_Class):

TELEMETRY_REQUEST_TAINTED: Literal["_dd.iast.telemetry.request.tainted"] = "_dd.iast.telemetry.request.tainted"
TELEMETRY_EXECUTED_SINK: Literal["_dd.iast.telemetry.executed.sink"] = "_dd.iast.telemetry.executed.sink"
TELEMETRY_SUPPRESSED_VULNERABILITY: Literal[
TELEMETRY_SUPPRESSED_VULNERABILITY: Literal["_dd.iast.telemetry.suppressed.vulnerabilities"] = (
"_dd.iast.telemetry.suppressed.vulnerabilities"
] = "_dd.iast.telemetry.suppressed.vulnerabilities"
)
TELEMETRY_EXECUTED_SOURCE: Literal["_dd.iast.telemetry.executed.source"] = "_dd.iast.telemetry.executed.source"


Expand Down Expand Up @@ -252,9 +252,9 @@ class SPAN_DATA_NAMES(metaclass=Constant_Class):
REQUEST_BODY: Literal["http.request.body"] = "http.request.body"
REQUEST_QUERY: Literal["http.request.query"] = "http.request.query"
REQUEST_HEADERS_NO_COOKIES: Literal["http.request.headers"] = "http.request.headers"
REQUEST_HEADERS_NO_COOKIES_CASE: Literal[
REQUEST_HEADERS_NO_COOKIES_CASE: Literal["http.request.headers_case_sensitive"] = (
"http.request.headers_case_sensitive"
] = "http.request.headers_case_sensitive"
)
REQUEST_URI_RAW: Literal["http.request.uri"] = "http.request.uri"
REQUEST_ROUTE: Literal["http.request.route"] = "http.request.route"
REQUEST_METHOD: Literal["http.request.method"] = "http.request.method"
Expand Down Expand Up @@ -287,12 +287,12 @@ class API_SECURITY(metaclass=Constant_Class):
SAMPLE_RATE: Literal["DD_API_SECURITY_REQUEST_SAMPLE_RATE"] = "DD_API_SECURITY_REQUEST_SAMPLE_RATE"
SAMPLE_DELAY: Literal["DD_API_SECURITY_SAMPLE_DELAY"] = "DD_API_SECURITY_SAMPLE_DELAY"
MAX_PAYLOAD_SIZE: Literal[0x1000000] = 0x1000000 # 16MB maximum size
ENDPOINT_COLLECTION: Literal[
ENDPOINT_COLLECTION: Literal["DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED"] = (
"DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED"
] = "DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED"
ENDPOINT_COLLECTION_LIMIT: Literal[
)
ENDPOINT_COLLECTION_LIMIT: Literal["DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT"] = (
"DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT"
] = "DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT"
)


class WAF_CONTEXT_NAMES(metaclass=Constant_Class):
Expand Down Expand Up @@ -376,9 +376,9 @@ class EXPLOIT_PREVENTION(metaclass=Constant_Class):
STACK_TRACE_ENABLED: Literal["DD_APPSEC_STACK_TRACE_ENABLED"] = "DD_APPSEC_STACK_TRACE_ENABLED"
MAX_STACK_TRACES: Literal["DD_APPSEC_MAX_STACK_TRACES"] = "DD_APPSEC_MAX_STACK_TRACES"
MAX_STACK_TRACE_DEPTH: Literal["DD_APPSEC_MAX_STACK_TRACE_DEPTH"] = "DD_APPSEC_MAX_STACK_TRACE_DEPTH"
STACK_TOP_PERCENT: Literal[
STACK_TOP_PERCENT: Literal["DD_APPSEC_MAX_STACK_TRACE_DEPTH_TOP_PERCENT"] = (
"DD_APPSEC_MAX_STACK_TRACE_DEPTH_TOP_PERCENT"
] = "DD_APPSEC_MAX_STACK_TRACE_DEPTH_TOP_PERCENT"
)

class TYPE(metaclass=Constant_Class):
CMDI: Literal["command_injection"] = "command_injection"
Expand Down
1 change: 1 addition & 0 deletions ddtrace/appsec/_iast/_overhead_control_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
limit. It will measure operations being executed in a request and it will deactivate detection
(and therefore reduce the overhead to nearly 0) if a certain threshold is reached.
"""

from ddtrace._trace.sampler import RateSampler
from ddtrace._trace.span import Span
from ddtrace.appsec._iast._utils import _is_iast_debug_enabled
Expand Down
8 changes: 2 additions & 6 deletions ddtrace/appsec/_iast/_patch_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
The module uses wrapt's function wrapping capabilities to intercept calls to security-sensitive
functions and enable taint tracking and vulnerability detection.
"""

import functools
from typing import Callable
from typing import Optional
Expand Down Expand Up @@ -110,12 +111,7 @@ def unpatch(self):

def __repr__(self):
"""Return a string representation of the IASTFunction instance."""
return (
f"IASTFunction(name={self.name}, "
f"function={self.function}, "
f"hook={self.hook}, "
f"force={self.force})"
)
return f"IASTFunction(name={self.name}, function={self.function}, hook={self.hook}, force={self.force})"


class WrapFunctonsForIAST:
Expand Down
1 change: 1 addition & 0 deletions ddtrace/appsec/_iast/taint_sinks/header_injection.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
This module implements taint sink detection to track and block cases where tainted data
is passed to header-setting APIs without proper sanitization.
""" # noqa: D301

import typing
from typing import Text

Expand Down
1 change: 1 addition & 0 deletions ddtrace/appsec/trace_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Public API for User events"""

from functools import wraps

from ddtrace.appsec import _metrics
Expand Down
1 change: 1 addition & 0 deletions ddtrace/auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ def main():
If you'd like more granular control over instrumentation setup, you can call the `patch*` functions
directly.
"""

import ddtrace.bootstrap.sitecustomize # noqa:F401
1 change: 1 addition & 0 deletions ddtrace/contrib/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ async def home_handler(request):
:ref:`All HTTP tags <http-tagging>` are supported for this integration.

"""

from ddtrace.contrib.internal.aiohttp.middlewares import trace_app


Expand Down
1 change: 0 additions & 1 deletion ddtrace/contrib/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ def handle_request(scope, send):
.. __: https://asgi.readthedocs.io/
"""


from ddtrace.contrib.internal.asgi.middleware import TraceMiddleware
from ddtrace.contrib.internal.asgi.middleware import span_from_scope

Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/bottle.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
config.bottle['distributed_tracing'] = True

"""

from ddtrace.contrib.internal.bottle.trace import TracePlugin


Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def run(self):
Default: ``'celery-worker'``

"""

from ddtrace.contrib.internal.celery.app import patch_app
from ddtrace.contrib.internal.celery.app import unpatch_app

Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/cherrypy.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def index(self):

cherrypy.quickstart(HelloWorld())
"""

from ddtrace.contrib.internal.cherrypy.patch import TraceMiddleware


Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/dbapi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Generic dbapi tracing code.
"""

import wrapt

from ddtrace import config
Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/falcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def on_falcon_request(span, request, response):

:ref:`Headers tracing <http-headers-tracing>` is supported for this integration.
"""

from ddtrace.contrib.internal.falcon.middleware import TraceMiddleware


Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/flask_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def counter():
Cache = get_traced_cache(tracer, service='my-flask-cache-app', cache_cls=Cache)

"""

from ddtrace.contrib.internal.flask_cache.patch import get_traced_cache


Expand Down
Loading
Loading