diff options
| author | Rob Hudson <rob@cogit8.org> | 2025-08-23 12:23:53 -0700 |
|---|---|---|
| committer | nessita <124304+nessita@users.noreply.github.com> | 2025-08-28 17:23:48 -0300 |
| commit | 550822bceea227b07445d1852c4376b663c09ea4 (patch) | |
| tree | c7b9a032939c7611156b54767c10059d7d6e373c /tests/decorators | |
| parent | 292b9e6fe8f23491680d9cc60f328562e2b1c823 (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.py | 95 |
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) |
