summaryrefslogtreecommitdiff
path: root/tests/decorators
diff options
context:
space:
mode:
authorRob Hudson <rob@cogit8.org>2025-08-23 12:23:53 -0700
committernessita <124304+nessita@users.noreply.github.com>2025-08-28 17:23:48 -0300
commit550822bceea227b07445d1852c4376b663c09ea4 (patch)
treec7b9a032939c7611156b54767c10059d7d6e373c /tests/decorators
parent292b9e6fe8f23491680d9cc60f328562e2b1c823 (diff)
Fixed #36532 -- Added Content Security Policy view decorators to override or disable policies.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Diffstat (limited to 'tests/decorators')
-rw-r--r--tests/decorators/test_csp.py95
1 files changed, 95 insertions, 0 deletions
diff --git a/tests/decorators/test_csp.py b/tests/decorators/test_csp.py
new file mode 100644
index 0000000000..2def6b0f79
--- /dev/null
+++ b/tests/decorators/test_csp.py
@@ -0,0 +1,95 @@
+from itertools import product
+
+from asgiref.sync import iscoroutinefunction
+
+from django.http import HttpRequest, HttpResponse
+from django.test import SimpleTestCase
+from django.utils.csp import CSP
+from django.views.decorators.csp import csp_override, csp_report_only_override
+
+basic_config = {
+ "default-src": [CSP.SELF],
+}
+
+
+class CSPOverrideDecoratorTest(SimpleTestCase):
+ def test_wrapped_sync_function_is_not_coroutine_function(self):
+ def sync_view(request):
+ return HttpResponse()
+
+ wrapped_view = csp_override({})(sync_view)
+ self.assertIs(iscoroutinefunction(wrapped_view), False)
+
+ def test_wrapped_async_function_is_coroutine_function(self):
+ async def async_view(request):
+ return HttpResponse()
+
+ wrapped_view = csp_override({})(async_view)
+ self.assertIs(iscoroutinefunction(wrapped_view), True)
+
+ def test_decorator_requires_mapping(self):
+ for config, decorator in product(
+ [None, 0, False, [], [1, 2, 3], 42, {4, 5}],
+ (csp_override, csp_report_only_override),
+ ):
+ with (
+ self.subTest(config=config, decorator=decorator),
+ self.assertRaisesMessage(TypeError, "CSP config should be a mapping"),
+ ):
+ decorator(config)
+
+ def test_csp_override(self):
+ @csp_override(basic_config)
+ def sync_view(request):
+ return HttpResponse("OK")
+
+ response = sync_view(HttpRequest())
+ self.assertEqual(response._csp_config, basic_config)
+ self.assertIs(hasattr(response, "_csp_ro_config"), False)
+
+ async def test_csp_override_async_view(self):
+ @csp_override(basic_config)
+ async def async_view(request):
+ return HttpResponse("OK")
+
+ response = await async_view(HttpRequest())
+ self.assertEqual(response._csp_config, basic_config)
+ self.assertIs(hasattr(response, "_csp_ro_config"), False)
+
+ def test_csp_report_only_override(self):
+ @csp_report_only_override(basic_config)
+ def sync_view(request):
+ return HttpResponse("OK")
+
+ response = sync_view(HttpRequest())
+ self.assertEqual(response._csp_ro_config, basic_config)
+ self.assertIs(hasattr(response, "_csp_config"), False)
+
+ async def test_csp_report_only_override_async_view(self):
+ @csp_report_only_override(basic_config)
+ async def async_view(request):
+ return HttpResponse("OK")
+
+ response = await async_view(HttpRequest())
+ self.assertEqual(response._csp_ro_config, basic_config)
+ self.assertIs(hasattr(response, "_csp_config"), False)
+
+ def test_csp_override_both(self):
+ @csp_override(basic_config)
+ @csp_report_only_override(basic_config)
+ def sync_view(request):
+ return HttpResponse("OK")
+
+ response = sync_view(HttpRequest())
+ self.assertEqual(response._csp_config, basic_config)
+ self.assertEqual(response._csp_ro_config, basic_config)
+
+ async def test_csp_override_both_async_view(self):
+ @csp_override(basic_config)
+ @csp_report_only_override(basic_config)
+ async def async_view(request):
+ return HttpResponse("OK")
+
+ response = await async_view(HttpRequest())
+ self.assertEqual(response._csp_config, basic_config)
+ self.assertEqual(response._csp_ro_config, basic_config)