Skip to content

Commit

Permalink
chore: migrate appsec django tests to appsec integration folder
Browse files Browse the repository at this point in the history
  • Loading branch information
avara1986 committed Jan 16, 2025
1 parent c46c302 commit 4a5e1f3
Show file tree
Hide file tree
Showing 11 changed files with 398 additions and 87 deletions.
4 changes: 2 additions & 2 deletions ddtrace/appsec/_iast/_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,6 @@ def _on_django_func_wrapped(fn_args, fn_kwargs, first_arg_expected_type, *_):
http_req = fn_args[0]

http_req.COOKIES = taint_structure(http_req.COOKIES, OriginType.COOKIE_NAME, OriginType.COOKIE)
http_req.GET = taint_structure(http_req.GET, OriginType.PARAMETER_NAME, OriginType.PARAMETER)
http_req.POST = taint_structure(http_req.POST, OriginType.BODY, OriginType.BODY)
if (
getattr(http_req, "_body", None) is not None
and len(getattr(http_req, "_body", None)) > 0
Expand Down Expand Up @@ -202,6 +200,8 @@ def _on_django_func_wrapped(fn_args, fn_kwargs, first_arg_expected_type, *_):
except AttributeError:
log.debug("IAST can't set attribute http_req.body", exc_info=True)

http_req.GET = taint_structure(http_req.GET, OriginType.PARAMETER_NAME, OriginType.PARAMETER)
http_req.POST = taint_structure(http_req.POST, OriginType.PARAMETER_NAME, OriginType.BODY)
http_req.headers = taint_structure(http_req.headers, OriginType.HEADER_NAME, OriginType.HEADER)
http_req.path = taint_pyobject(
http_req.path, source_name="path", source_value=http_req.path, source_origin=OriginType.PATH
Expand Down
32 changes: 32 additions & 0 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,36 @@ test = [
[[envs.appsec_iast_packages.matrix]]
python = ["3.9", "3.10", "3.11", "3.12"]

## ASM appsec_integrations_django

[envs.appsec_integrations_django]
template = "appsec_integrations_django"
dependencies = [
"pytest",
"pytest-cov",
"requests",
"hypothesis",
"pylibmc",
"bcrypt==4.2.1",
"pytest-django[testing]==3.10.0",
"Django{matrix:django}",
]

[envs.appsec_integrations_django.scripts]
test = [
"uname -a",
"pip freeze",
"DD_CIVISIBILITY_ITR_ENABLED=0 DD_IAST_REQUEST_SAMPLING=100 _DD_APPSEC_DEDUPLICATION_ENABLED=false python -m pytest -vvv {args:tests/appsec/integrations/django_tests/}",
]

[[envs.appsec_integrations_django.matrix]]
python = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
django = ["~=4.0"]

[[envs.appsec_integrations_django.matrix]]
python = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
django = ["~=3.2"]

## ASM appsec_integrations_flask

[envs.appsec_integrations_flask]
Expand Down Expand Up @@ -369,6 +399,8 @@ flask = ["~=2.2"]
python = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
flask = ["~=3.0"]



## ASM FastAPI

[envs.appsec_threats_fastapi]
Expand Down
45 changes: 45 additions & 0 deletions tests/appsec/integrations/django_tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os

import django
from django.conf import settings
import pytest

from ddtrace import Pin
from ddtrace.contrib.internal.django.patch import patch
from tests.utils import DummyTracer
from tests.utils import TracerSpanContainer


os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.appsec.integrations.django_tests.django_app.settings")


# `pytest` automatically calls this function once when tests are run.
def pytest_configure():
settings.DEBUG = False
patch()
django.setup()


@pytest.fixture
def tracer():
tracer = DummyTracer()
# Patch Django and override tracer to be our test tracer
pin = Pin.get_from(django)
original_tracer = pin.tracer
Pin.override(django, tracer=tracer)

# Yield to our test
yield tracer
tracer.pop()

# Reset the tracer pinned to Django and unpatch
# DEV: unable to properly unpatch and reload django app with each test
# unpatch()
Pin.override(django, tracer=original_tracer)


@pytest.fixture
def test_spans(tracer):
container = TracerSpanContainer(tracer)
yield container
container.reset()
Empty file.
77 changes: 77 additions & 0 deletions tests/appsec/integrations/django_tests/django_app/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import os

from ddtrace import tracer
from tests.webclient import PingFilter


tracer.configure(
settings={
"FILTERS": [PingFilter()],
}
)


ALLOWED_HOSTS = [
"testserver",
"localhost",
]

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

DATABASES = {
"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"},
}


CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "unique-snowflake",
},
"pylibmc": {
"BACKEND": "django.core.cache.backends.memcached.PyLibMCCache",
"LOCATION": "127.0.0.1:11211",
},
}

SITE_ID = 1
SECRET_KEY = "not_very_secret_in_tests"
USE_I18N = True
USE_L10N = True
STATIC_URL = "/static/"
ROOT_URLCONF = "tests.appsec.integrations.django_tests.django_app.urls"

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
os.path.join(BASE_DIR, "templates"),
],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]

MIDDLEWARE = [
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.security.SecurityMiddleware",
]

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
]
84 changes: 84 additions & 0 deletions tests/appsec/integrations/django_tests/django_app/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import django
from django.http import HttpResponse
from django.urls import path

from ddtrace import tracer
from tests.appsec.integrations.django_tests.django_app import views


# django.conf.urls.url was deprecated in django 3 and removed in django 4
if django.VERSION < (4, 0, 0):
from django.conf.urls import url as handler
else:
from django.urls import re_path as handler


def shutdown(request):
# Endpoint used to flush traces to the agent when doing snapshots.
tracer.shutdown()
return HttpResponse(status=200)


urlpatterns = [
handler(r"^$", views.index),
# This must precede composed-view.
handler("appsec/response-header/$", views.magic_header_key, name="response-header"),
handler("appsec/body/$", views.body_view, name="body_view"),
handler("appsec/view_with_exception/$", views.view_with_exception, name="view_with_exception"),
handler("appsec/weak-hash/$", views.weak_hash_view, name="weak_hash"),
handler("appsec/block/$", views.block_callable_view, name="block"),
handler("appsec/command-injection/$", views.command_injection, name="command_injection"),
handler("appsec/header-injection/$", views.header_injection, name="header_injection"),
handler("appsec/taint-checking-enabled/$", views.taint_checking_enabled_view, name="taint_checking_enabled_view"),
handler(
"appsec/taint-checking-disabled/$", views.taint_checking_disabled_view, name="taint_checking_disabled_view"
),
handler(
"appsec/sqli_http_request_parameter/$", views.sqli_http_request_parameter, name="sqli_http_request_parameter"
),
handler(
"appsec/sqli_http_request_parameter_name_get/$",
views.sqli_http_request_parameter_name_get,
name="sqli_http_request_parameter_name_get",
),
handler(
"appsec/sqli_http_request_parameter_name_post/$",
views.sqli_http_request_parameter_name_post,
name="sqli_http_request_parameter_name_post",
),
handler(
"appsec/sqli_http_request_header_name/$",
views.sqli_http_request_header_name,
name="sqli_http_request_header_name",
),
handler(
"appsec/sqli_http_request_header_value/$",
views.sqli_http_request_header_value,
name="sqli_http_request_header_value",
),
handler(
"appsec/sqli_http_request_cookie_name/$",
views.sqli_http_request_cookie_name,
name="sqli_http_request_cookie_name",
),
handler(
"appsec/sqli_http_request_cookie_value/$",
views.sqli_http_request_cookie_value,
name="sqli_http_request_cookie_value",
),
handler("appsec/sqli_http_request_body/$", views.sqli_http_request_body, name="sqli_http_request_body"),
handler("appsec/source/body/$", views.source_body_view, name="source_body"),
handler("appsec/insecure-cookie/test_insecure_2_1/$", views.view_insecure_cookies_two_insecure_one_secure),
handler("appsec/insecure-cookie/test_insecure_special/$", views.view_insecure_cookies_insecure_special_chars),
handler("appsec/insecure-cookie/test_insecure/$", views.view_insecure_cookies_insecure),
handler("appsec/insecure-cookie/test_secure/$", views.view_insecure_cookies_secure),
handler("appsec/insecure-cookie/test_empty_cookie/$", views.view_insecure_cookies_empty),
path(
"appsec/sqli_http_path_parameter/<str:q_http_path_parameter>/",
views.sqli_http_path_parameter,
name="sqli_http_path_parameter",
),
handler("appsec/validate_querydict/$", views.validate_querydict, name="validate_querydict"),
path("appsec/path-params/<int:year>/<str:month>/", views.path_params_view, name="path-params-view"),
path("appsec/checkuser/<str:user_id>/", views.checkuser_view, name="checkuser"),
]
Loading

0 comments on commit 4a5e1f3

Please sign in to comment.