diff --git a/benchmarks/appsec_iast_propagation/scenario.py b/benchmarks/appsec_iast_propagation/scenario.py index 65853d1873e..56ac67128b7 100644 --- a/benchmarks/appsec_iast_propagation/scenario.py +++ b/benchmarks/appsec_iast_propagation/scenario.py @@ -2,14 +2,18 @@ import bm -from ddtrace.appsec._iast._taint_tracking import OriginType -from ddtrace.appsec._iast._taint_tracking import Source -from ddtrace.appsec._iast._taint_tracking import TaintRange -from ddtrace.appsec._iast._taint_tracking import create_context -from ddtrace.appsec._iast._taint_tracking import reset_context -from ddtrace.appsec._iast._taint_tracking import set_ranges -from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect -from ddtrace.appsec._iast._taint_tracking.aspects import join_aspect +from tests.utils import override_env + + +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import Source + from ddtrace.appsec._iast._taint_tracking import TaintRange + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import reset_context + from ddtrace.appsec._iast._taint_tracking import set_ranges + from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect + from ddtrace.appsec._iast._taint_tracking.aspects import join_aspect TAINT_ORIGIN = Source(name="sample_name", value="sample_value", origin=OriginType.PARAMETER) diff --git a/ddtrace/appsec/_iast/_taint_tracking/_native.cpp b/ddtrace/appsec/_iast/_taint_tracking/_native.cpp index af973ecd7e9..dd7b4a67ab3 100644 --- a/ddtrace/appsec/_iast/_taint_tracking/_native.cpp +++ b/ddtrace/appsec/_iast/_taint_tracking/_native.cpp @@ -61,6 +61,20 @@ static struct PyModuleDef ops = { PyModuleDef_HEAD_INIT, PYBIND11_MODULE(_native, m) { + const char* env_iast_enabled = std::getenv("DD_IAST_ENABLED"); + if (env_iast_enabled == nullptr) { + throw py::import_error("IAST not enabled"); + return; + } + + std::string iast_enabled = std::string(env_iast_enabled); + std::transform( + iast_enabled.begin(), iast_enabled.end(), iast_enabled.begin(), [](unsigned char c) { return std::tolower(c); }); + if (iast_enabled != "true" && iast_enabled != "1") { + throw py::import_error("IAST not enabled"); + return; + } + initializer = make_unique(); initializer->create_context(); diff --git a/ddtrace/appsec/_iast/processor.py b/ddtrace/appsec/_iast/processor.py index 7f72709cb37..ee2c284adbc 100644 --- a/ddtrace/appsec/_iast/processor.py +++ b/ddtrace/appsec/_iast/processor.py @@ -15,7 +15,6 @@ from ._metrics import _set_metric_iast_request_tainted from ._metrics import _set_span_tag_iast_executed_sink from ._metrics import _set_span_tag_iast_request_tainted -from ._utils import _iast_report_to_str from ._utils import _is_iast_enabled @@ -75,6 +74,7 @@ def on_span_finish(self, span): return from ._taint_tracking import reset_context # noqa: F401 + from ._utils import _iast_report_to_str span.set_metric(IAST.ENABLED, 1.0) diff --git a/ddtrace/appsec/_iast/taint_sinks/ssrf.py b/ddtrace/appsec/_iast/taint_sinks/ssrf.py index 1deb8bb7c16..f114998605a 100644 --- a/ddtrace/appsec/_iast/taint_sinks/ssrf.py +++ b/ddtrace/appsec/_iast/taint_sinks/ssrf.py @@ -9,8 +9,8 @@ from ..._constants import IAST_SPAN_TAGS from .. import oce from .._metrics import increment_iast_span_metric -from .._taint_tracking import taint_ranges_as_evidence_info from .._utils import _has_to_scrub +from .._utils import _is_iast_enabled from .._utils import _scrub from .._utils import _scrub_get_tokens_positions from ..constants import EVIDENCE_SSRF @@ -38,6 +38,11 @@ class SSRF(VulnerabilityBase): @classmethod def report(cls, evidence_value=None, sources=None): + if not _is_iast_enabled(): + return + + from .._taint_tracking import taint_ranges_as_evidence_info + if isinstance(evidence_value, (str, bytes, bytearray)): evidence_value, sources = taint_ranges_as_evidence_info(evidence_value) super(SSRF, cls).report(evidence_value=evidence_value, sources=sources) diff --git a/releasenotes/notes/iast-fix-avoid-native-module-load-ccb79bd350dc3621.yaml b/releasenotes/notes/iast-fix-avoid-native-module-load-ccb79bd350dc3621.yaml new file mode 100644 index 00000000000..50eae7f7312 --- /dev/null +++ b/releasenotes/notes/iast-fix-avoid-native-module-load-ccb79bd350dc3621.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + Vulnerability Management for Code-level (IAST): Addresses an issue where the IAST native module was imported even though IAST was not enabled. diff --git a/tests/appsec/iast/conftest.py b/tests/appsec/iast/conftest.py index 1025f672015..e006ec279d0 100644 --- a/tests/appsec/iast/conftest.py +++ b/tests/appsec/iast/conftest.py @@ -3,8 +3,6 @@ from ddtrace.appsec._iast import oce from ddtrace.appsec._iast._patches.json_tainting import patch as json_patch from ddtrace.appsec._iast._patches.json_tainting import unpatch_iast as json_unpatch -from ddtrace.appsec._iast._taint_tracking import create_context -from ddtrace.appsec._iast._taint_tracking import reset_context from ddtrace.appsec._iast.processor import AppSecIastSpanProcessor from ddtrace.appsec._iast.taint_sinks._base import VulnerabilityBase from ddtrace.appsec._iast.taint_sinks.command_injection import patch as cmdi_patch @@ -20,6 +18,11 @@ from tests.utils import override_global_config +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import reset_context + + def iast_span(tracer, env, request_sampling="100", deduplication="false"): try: from ddtrace.contrib.langchain.patch import patch as langchain_patch diff --git a/tests/appsec/iast/taint_tracking/test_native_taint_range.py b/tests/appsec/iast/taint_tracking/test_native_taint_range.py index 5b504146dba..cb38cf7257d 100644 --- a/tests/appsec/iast/taint_tracking/test_native_taint_range.py +++ b/tests/appsec/iast/taint_tracking/test_native_taint_range.py @@ -4,26 +4,30 @@ import sys from ddtrace.appsec._iast import oce -from ddtrace.appsec._iast._taint_tracking import OriginType -from ddtrace.appsec._iast._taint_tracking import Source -from ddtrace.appsec._iast._taint_tracking import TaintRange -from ddtrace.appsec._iast._taint_tracking import are_all_text_all_ranges -from ddtrace.appsec._iast._taint_tracking import create_context -from ddtrace.appsec._iast._taint_tracking import debug_taint_map -from ddtrace.appsec._iast._taint_tracking import get_range_by_hash -from ddtrace.appsec._iast._taint_tracking import get_ranges -from ddtrace.appsec._iast._taint_tracking import is_notinterned_notfasttainted_unicode -from ddtrace.appsec._iast._taint_tracking import num_objects_tainted -from ddtrace.appsec._iast._taint_tracking import reset_context -from ddtrace.appsec._iast._taint_tracking import set_fast_tainted_if_notinterned_unicode -from ddtrace.appsec._iast._taint_tracking import set_ranges -from ddtrace.appsec._iast._taint_tracking import shift_taint_range -from ddtrace.appsec._iast._taint_tracking import shift_taint_ranges -from ddtrace.appsec._iast._taint_tracking import taint_pyobject -from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect -from ddtrace.appsec._iast._taint_tracking.aspects import bytearray_extend_aspect as extend_aspect -from ddtrace.appsec._iast._taint_tracking.aspects import format_aspect -from ddtrace.appsec._iast._taint_tracking.aspects import join_aspect +from tests.utils import override_env + + +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import Source + from ddtrace.appsec._iast._taint_tracking import TaintRange + from ddtrace.appsec._iast._taint_tracking import are_all_text_all_ranges + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import debug_taint_map + from ddtrace.appsec._iast._taint_tracking import get_range_by_hash + from ddtrace.appsec._iast._taint_tracking import get_ranges + from ddtrace.appsec._iast._taint_tracking import is_notinterned_notfasttainted_unicode + from ddtrace.appsec._iast._taint_tracking import num_objects_tainted + from ddtrace.appsec._iast._taint_tracking import reset_context + from ddtrace.appsec._iast._taint_tracking import set_fast_tainted_if_notinterned_unicode + from ddtrace.appsec._iast._taint_tracking import set_ranges + from ddtrace.appsec._iast._taint_tracking import shift_taint_range + from ddtrace.appsec._iast._taint_tracking import shift_taint_ranges + from ddtrace.appsec._iast._taint_tracking import taint_pyobject + from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect + from ddtrace.appsec._iast._taint_tracking.aspects import bytearray_extend_aspect as extend_aspect + from ddtrace.appsec._iast._taint_tracking.aspects import format_aspect + from ddtrace.appsec._iast._taint_tracking.aspects import join_aspect def setup(): diff --git a/tests/appsec/iast/taint_tracking/test_native_taint_source.py b/tests/appsec/iast/taint_tracking/test_native_taint_source.py index b7fb3448f45..797d4370b79 100644 --- a/tests/appsec/iast/taint_tracking/test_native_taint_source.py +++ b/tests/appsec/iast/taint_tracking/test_native_taint_source.py @@ -1,5 +1,9 @@ -from ddtrace.appsec._iast._taint_tracking import OriginType -from ddtrace.appsec._iast._taint_tracking import Source +from tests.utils import override_env + + +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import Source def test_all_params_and_tostring(): diff --git a/tests/appsec/iast/taint_tracking/test_taint_tracking.py b/tests/appsec/iast/taint_tracking/test_taint_tracking.py index 9b9fb1dfb9a..09cf2ba7991 100644 --- a/tests/appsec/iast/taint_tracking/test_taint_tracking.py +++ b/tests/appsec/iast/taint_tracking/test_taint_tracking.py @@ -1,17 +1,15 @@ #!/usr/bin/env python3 -import pytest from ddtrace.appsec._iast import oce +from tests.utils import override_env -try: +with override_env({"DD_IAST_ENABLED": "True"}): from ddtrace.appsec._iast._taint_tracking import OriginType from ddtrace.appsec._iast._taint_tracking import Source from ddtrace.appsec._iast._taint_tracking import taint_pyobject from ddtrace.appsec._iast._taint_tracking import taint_ranges_as_evidence_info from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect -except (ImportError, AttributeError): - pytest.skip("IAST not supported for this Python version", allow_module_level=True) def setup(): diff --git a/tests/appsec/iast_memcheck/test_iast_mem_check.py b/tests/appsec/iast_memcheck/test_iast_mem_check.py index ff9ed44c10c..04e2d8d3694 100644 --- a/tests/appsec/iast_memcheck/test_iast_mem_check.py +++ b/tests/appsec/iast_memcheck/test_iast_mem_check.py @@ -6,19 +6,23 @@ from ddtrace.appsec._constants import IAST from ddtrace.appsec._iast._stacktrace import get_info_frame -from ddtrace.appsec._iast._taint_tracking import OriginType -from ddtrace.appsec._iast._taint_tracking import active_map_addreses_size -from ddtrace.appsec._iast._taint_tracking import create_context -from ddtrace.appsec._iast._taint_tracking import get_tainted_ranges -from ddtrace.appsec._iast._taint_tracking import initializer_size -from ddtrace.appsec._iast._taint_tracking import num_objects_tainted -from ddtrace.appsec._iast._taint_tracking import reset_context -from ddtrace.appsec._iast._taint_tracking import taint_pyobject from ddtrace.internal import core from tests.appsec.iast.aspects.conftest import _iast_patched_module from tests.appsec.iast_memcheck._stacktrace_py import get_info_frame as get_info_frame_py from tests.appsec.iast_memcheck.fixtures.stacktrace import func_1 from tests.utils import flaky +from tests.utils import override_env + + +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import active_map_addreses_size + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import get_tainted_ranges + from ddtrace.appsec._iast._taint_tracking import initializer_size + from ddtrace.appsec._iast._taint_tracking import num_objects_tainted + from ddtrace.appsec._iast._taint_tracking import reset_context + from ddtrace.appsec._iast._taint_tracking import taint_pyobject FIXTURES_PATH = "tests/appsec/iast/fixtures/propagation_path.py" diff --git a/tests/appsec/iast_packages/packages/template.py.tpl b/tests/appsec/iast_packages/packages/template.py.tpl index df6d6b2d360..d280d2fc74d 100644 --- a/tests/appsec/iast_packages/packages/template.py.tpl +++ b/tests/appsec/iast_packages/packages/template.py.tpl @@ -6,7 +6,10 @@ https://pypi.org/project/[package_name]/ [Description] """ from flask import Blueprint, request -from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted +from tests.utils import override_env + +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted pkg_[package_name] = Blueprint('package_[package_name]', __name__) diff --git a/tests/appsec/iast_packages/packages/utils.py b/tests/appsec/iast_packages/packages/utils.py index 28faa94792d..c36c6966f9e 100644 --- a/tests/appsec/iast_packages/packages/utils.py +++ b/tests/appsec/iast_packages/packages/utils.py @@ -1,4 +1,8 @@ -from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted +from tests.utils import override_env + + +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted class ResultResponse: diff --git a/tests/appsec/iast_tdd_propagation/flask_orm_app.py b/tests/appsec/iast_tdd_propagation/flask_orm_app.py index 11369847fc5..5e2915fa353 100644 --- a/tests/appsec/iast_tdd_propagation/flask_orm_app.py +++ b/tests/appsec/iast_tdd_propagation/flask_orm_app.py @@ -14,10 +14,13 @@ from ddtrace import tracer from ddtrace.appsec._constants import IAST from ddtrace.appsec._iast import ddtrace_iast_flask_patch -from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted from ddtrace.internal import core +from tests.utils import override_env +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted + import ddtrace.auto # noqa: F401 # isort: skip orm = os.getenv("FLASK_ORM", "sqlite") diff --git a/tests/appsec/integrations/test_langchain.py b/tests/appsec/integrations/test_langchain.py index 6a4d49075b2..d1e86e6ab68 100644 --- a/tests/appsec/integrations/test_langchain.py +++ b/tests/appsec/integrations/test_langchain.py @@ -1,19 +1,22 @@ import pytest from ddtrace.appsec._constants import IAST -from ddtrace.appsec._iast._taint_tracking import OriginType -from ddtrace.appsec._iast._taint_tracking import taint_pyobject from ddtrace.appsec._iast.constants import VULN_CMDI from ddtrace.internal import core from ddtrace.internal.module import is_module_installed from tests.appsec.iast.aspects.conftest import _iast_patched_module from tests.appsec.iast.conftest import iast_span_defaults # noqa: F401 from tests.appsec.iast.iast_utils import get_line_and_hash +from tests.utils import override_env FIXTURES_PATH = "tests/appsec/integrations/fixtures/patch_langchain.py" FIXTURES_MODULE = "tests.appsec.integrations.fixtures.patch_langchain" +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import taint_pyobject + @pytest.mark.skipif(not is_module_installed("langchain"), reason="Langchain tests work on 3.9 or higher") def test_openai_llm_appsec_iast_cmdi(iast_span_defaults): # noqa: F811 diff --git a/tests/appsec/integrations/test_psycopg2.py b/tests/appsec/integrations/test_psycopg2.py index d69bb05aa1e..99d8790c728 100644 --- a/tests/appsec/integrations/test_psycopg2.py +++ b/tests/appsec/integrations/test_psycopg2.py @@ -1,13 +1,17 @@ import psycopg2.extensions as ext from ddtrace.appsec._iast import oce -from ddtrace.appsec._iast._taint_tracking import OriginType -from ddtrace.appsec._iast._taint_tracking import create_context -from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted from ddtrace.appsec._iast._taint_utils import LazyTaintList +from tests.utils import override_env from tests.utils import override_global_config +with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted + + def setup(): create_context() oce._enabled = True diff --git a/tests/contrib/dbapi/test_dbapi_appsec.py b/tests/contrib/dbapi/test_dbapi_appsec.py index 64a4c1f2d6d..819f969ede6 100644 --- a/tests/contrib/dbapi/test_dbapi_appsec.py +++ b/tests/contrib/dbapi/test_dbapi_appsec.py @@ -8,6 +8,7 @@ from ddtrace.settings import Config from ddtrace.settings.integration import IntegrationConfig from tests.utils import TracerTestCase +from tests.utils import override_env class TestTracedCursor(TracerTestCase): @@ -18,8 +19,9 @@ def setUp(self): @pytest.mark.skipif(not _is_python_version_supported(), reason="IAST compatible versions") def test_tainted_query(self): - from ddtrace.appsec._iast._taint_tracking import OriginType - from ddtrace.appsec._iast._taint_tracking import taint_pyobject + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import taint_pyobject with mock.patch("ddtrace.contrib.dbapi._is_iast_enabled", return_value=True), mock.patch( "ddtrace.appsec._iast.taint_sinks.sql_injection.SqlInjection.report" @@ -38,8 +40,9 @@ def test_tainted_query(self): @pytest.mark.skipif(not _is_python_version_supported(), reason="IAST compatible versions") def test_tainted_query_args(self): - from ddtrace.appsec._iast._taint_tracking import OriginType - from ddtrace.appsec._iast._taint_tracking import taint_pyobject + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import taint_pyobject with mock.patch("ddtrace.contrib.dbapi._is_iast_enabled", return_value=True), mock.patch( "ddtrace.appsec._iast.taint_sinks.sql_injection.SqlInjection.report" @@ -61,7 +64,9 @@ def test_tainted_query_args(self): @pytest.mark.skipif(not _is_python_version_supported(), reason="IAST compatible versions") def test_untainted_query(self): - with mock.patch("ddtrace.contrib.dbapi._is_iast_enabled", return_value=True), mock.patch( + with override_env({"DD_IAST_ENABLED": "True"}), mock.patch( + "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True + ), mock.patch( "ddtrace.appsec._iast.taint_sinks.sql_injection.SqlInjection.report" ) as mock_sql_injection_report: query = "SELECT * FROM db;" @@ -76,7 +81,9 @@ def test_untainted_query(self): @pytest.mark.skipif(not _is_python_version_supported(), reason="IAST compatible versions") def test_untainted_query_and_args(self): - with mock.patch("ddtrace.contrib.dbapi._is_iast_enabled", return_value=True), mock.patch( + with override_env({"DD_IAST_ENABLED": "True"}), mock.patch( + "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True + ), mock.patch( "ddtrace.appsec._iast.taint_sinks.sql_injection.SqlInjection.report" ) as mock_sql_injection_report: query = "SELECT ? FROM db;" @@ -92,8 +99,9 @@ def test_untainted_query_and_args(self): @pytest.mark.skipif(not _is_python_version_supported(), reason="IAST compatible versions") def test_tainted_query_iast_disabled(self): - from ddtrace.appsec._iast._taint_tracking import OriginType - from ddtrace.appsec._iast._taint_tracking import taint_pyobject + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import taint_pyobject with mock.patch("ddtrace.contrib.dbapi._is_iast_enabled", return_value=False), mock.patch( "ddtrace.appsec._iast.taint_sinks.sql_injection.SqlInjection.report" diff --git a/tests/contrib/django/django_app/appsec_urls.py b/tests/contrib/django/django_app/appsec_urls.py index 0ccdc649c80..9a90d6fd790 100644 --- a/tests/contrib/django/django_app/appsec_urls.py +++ b/tests/contrib/django/django_app/appsec_urls.py @@ -10,11 +10,13 @@ from ddtrace.appsec import _asm_request_context from ddtrace.appsec._iast._utils import _is_python_version_supported as python_supported_by_iast from ddtrace.appsec._trace_utils import block_request_if_user_blocked +from tests.utils import override_env try: - from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect - from ddtrace.appsec._iast._taint_tracking.aspects import decode_aspect + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect + from ddtrace.appsec._iast._taint_tracking.aspects import decode_aspect except ImportError: # Python 2 compatibility from operator import add as add_aspect @@ -105,7 +107,8 @@ def sqli_http_request_header_value(request): def sqli_http_path_parameter(request, q_http_path_parameter): - from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect with connection.cursor() as cursor: query = add_aspect("SELECT 1 from ", q_http_path_parameter) @@ -117,9 +120,10 @@ def sqli_http_path_parameter(request, q_http_path_parameter): def taint_checking_enabled_view(request): if python_supported_by_iast(): - from ddtrace.appsec._iast._taint_tracking import OriginType - from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted - from ddtrace.appsec._iast._taint_tracking import taint_ranges_as_evidence_info + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import OriginType + from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted + from ddtrace.appsec._iast._taint_tracking import taint_ranges_as_evidence_info def assert_origin_path(path): # type: (Any) -> None assert is_pyobject_tainted(path) @@ -149,7 +153,8 @@ def is_pyobject_tainted(pyobject): # type: (Any) -> bool def taint_checking_disabled_view(request): if python_supported_by_iast(): - from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import is_pyobject_tainted else: def is_pyobject_tainted(pyobject): # type: (Any) -> bool diff --git a/tests/contrib/django/test_django_appsec_iast.py b/tests/contrib/django/test_django_appsec_iast.py index 4af1e6364ae..fb16955f612 100644 --- a/tests/contrib/django/test_django_appsec_iast.py +++ b/tests/contrib/django/test_django_appsec_iast.py @@ -21,8 +21,9 @@ @pytest.fixture(autouse=True) def reset_context(): - from ddtrace.appsec._iast._taint_tracking import create_context - from ddtrace.appsec._iast._taint_tracking import reset_context + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import reset_context yield reset_context() @@ -62,7 +63,7 @@ def _aux_appsec_get_root_span( @pytest.mark.skipif(not python_supported_by_iast(), reason="Python version not supported by IAST") def test_django_weak_hash(client, test_spans, tracer): - with override_global_config(dict(_asm_enabled=True, _iast_enabled=True)): + with override_global_config(dict(_asm_enabled=True, _iast_enabled=True)), override_env({"DD_IAST_ENABLED": "True"}): oce.reconfigure() patch_iast({"weak_hash": True}) root_span, _ = _aux_appsec_get_root_span(client, test_spans, tracer, url="/appsec/weak-hash/") @@ -75,7 +76,7 @@ def test_django_weak_hash(client, test_spans, tracer): @pytest.mark.skipif(not python_supported_by_iast(), reason="Python version not supported by IAST") def test_django_tainted_user_agent_iast_enabled(client, test_spans, tracer): - with override_global_config(dict(_iast_enabled=True)): + with override_global_config(dict(_iast_enabled=True)), override_env({"DD_IAST_ENABLED": "True"}): oce.reconfigure() tracer._iast_enabled = True @@ -95,7 +96,7 @@ def test_django_tainted_user_agent_iast_enabled(client, test_spans, tracer): @pytest.mark.skipif(not python_supported_by_iast(), reason="Python version not supported by IAST") def test_django_tainted_user_agent_iast_disabled(client, test_spans, tracer): - with override_global_config(dict(_iast_enabled=False)): + with override_global_config(dict(_iast_enabled=False)), override_env({"DD_IAST_ENABLED": "True"}): oce.reconfigure() root_span, response = _aux_appsec_get_root_span( @@ -119,7 +120,7 @@ def test_django_tainted_user_agent_iast_disabled(client, test_spans, tracer): def test_django_tainted_user_agent_iast_enabled_sqli_http_request_parameter(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -160,7 +161,7 @@ def test_django_tainted_user_agent_iast_enabled_sqli_http_request_parameter(clie def test_django_tainted_user_agent_iast_enabled_sqli_http_request_header_value(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -201,7 +202,7 @@ def test_django_tainted_user_agent_iast_enabled_sqli_http_request_header_value(c def test_django_tainted_user_agent_iast_disabled_sqli_http_request_header_value(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=False)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=False - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -223,7 +224,7 @@ def test_django_tainted_user_agent_iast_disabled_sqli_http_request_header_value( def test_django_tainted_user_agent_iast_enabled_sqli_http_request_header_name(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -265,7 +266,7 @@ def test_django_tainted_user_agent_iast_enabled_sqli_http_request_header_name(cl def test_django_tainted_user_agent_iast_disabled_sqli_http_request_header_name(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=False)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -287,7 +288,7 @@ def test_django_tainted_user_agent_iast_disabled_sqli_http_request_header_name(c def test_django_iast_enabled_full_sqli_http_path_parameter(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -328,7 +329,7 @@ def test_django_iast_enabled_full_sqli_http_path_parameter(client, test_spans, t def test_django_iast_disabled_full_sqli_http_path_parameter(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=False)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=False - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -348,7 +349,7 @@ def test_django_iast_disabled_full_sqli_http_path_parameter(client, test_spans, def test_django_tainted_user_agent_iast_enabled_sqli_http_cookies_name(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -392,7 +393,7 @@ def test_django_tainted_user_agent_iast_enabled_sqli_http_cookies_name(client, t def test_django_tainted_iast_disabled_sqli_http_cookies_name(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=False)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=False - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -412,7 +413,7 @@ def test_django_tainted_iast_disabled_sqli_http_cookies_name(client, test_spans, def test_django_tainted_user_agent_iast_enabled_sqli_http_cookies_value(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=True - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -454,7 +455,7 @@ def test_django_tainted_user_agent_iast_enabled_sqli_http_cookies_value(client, def test_django_tainted_iast_disabled_sqli_http_cookies_value(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=False)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=False - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -480,7 +481,7 @@ def test_django_tainted_iast_disabled_sqli_http_cookies_value(client, test_spans @pytest.mark.skipif(not python_supported_by_iast(), reason="Python version not supported by IAST") def test_django_tainted_user_agent_iast_enabled_sqli_http_body(client, test_spans, tracer, payload, content_type): with override_global_config(dict(_iast_enabled=True)), override_env( - dict(_DD_APPSEC_DEDUPLICATION_ENABLED="false") + dict(_DD_APPSEC_DEDUPLICATION_ENABLED="false", DD_IAST_ENABLED="True") ), mock.patch("ddtrace.contrib.dbapi._is_iast_enabled", return_value=True): root_span, response = _aux_appsec_get_root_span( client, @@ -518,7 +519,7 @@ def test_django_tainted_user_agent_iast_enabled_sqli_http_body(client, test_span def test_django_tainted_iast_disabled_sqli_http_body(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=False)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=False - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, @@ -538,7 +539,7 @@ def test_django_tainted_iast_disabled_sqli_http_body(client, test_spans, tracer) def test_querydict_django_with_iast(client, test_spans, tracer): with override_global_config(dict(_iast_enabled=True)), mock.patch( "ddtrace.contrib.dbapi._is_iast_enabled", return_value=False - ): + ), override_env({"DD_IAST_ENABLED": "True"}): root_span, response = _aux_appsec_get_root_span( client, test_spans, diff --git a/tests/contrib/flask/test_flask_appsec_iast.py b/tests/contrib/flask/test_flask_appsec_iast.py index 3a49228c857..9cd97c2e0e9 100644 --- a/tests/contrib/flask/test_flask_appsec_iast.py +++ b/tests/contrib/flask/test_flask_appsec_iast.py @@ -24,8 +24,9 @@ @pytest.fixture(autouse=True) def reset_context(): - from ddtrace.appsec._iast._taint_tracking import create_context - from ddtrace.appsec._iast._taint_tracking import reset_context + with override_env({"DD_IAST_ENABLED": "True"}): + from ddtrace.appsec._iast._taint_tracking import create_context + from ddtrace.appsec._iast._taint_tracking import reset_context yield reset_context() diff --git a/tests/smoke_test.py b/tests/smoke_test.py index 19b66aae0be..5e991782b86 100644 --- a/tests/smoke_test.py +++ b/tests/smoke_test.py @@ -1,3 +1,4 @@ +import os from platform import system import sys @@ -17,6 +18,18 @@ def mac_supported_iast_version(): if __name__ == "__main__": # ASM IAST smoke test if (3, 6, 0) <= sys.version_info < (3, 12) and system() != "Windows" and mac_supported_iast_version(): + # ASM IAST import error test + import_error = False + try: + from ddtrace.appsec._iast._taint_tracking._native import ops + except ImportError: + import_error = True + + assert import_error + assert "ddtrace.appsec._iast._taint_tracking._native.ops" not in sys.modules + + os.environ["DD_IAST_ENABLED"] = "True" + from ddtrace.appsec._iast._taint_tracking._native import ops assert ops