1
0
mirror of https://github.com/django/django.git synced 2025-06-30 15:59:11 +00:00

Refs #15727 -- Updated AdminSeleniumTestCase to use ContentSecurityPolicyMiddleware.

Replaced the custom CSP middleware previously used in the admin's
AdminSeleniumTestCase with the official ContentSecurityPolicyMiddleware.
This change ensures alignment with Django's built-in CSP support.

Also updates the test logic to inspect browser console logs to assert
that no CSP violations are triggered during Selenium admin tests.
This commit is contained in:
Natalia 2025-06-25 17:22:46 -03:00 committed by nessita
parent d63241ebc7
commit ff0ff98d42
2 changed files with 37 additions and 12 deletions

View File

@ -1,24 +1,27 @@
from contextlib import contextmanager
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test import modify_settings
from django.test import modify_settings, override_settings
from django.test.selenium import SeleniumTestCase
from django.utils.deprecation import MiddlewareMixin
from django.utils.csp import CSP
from django.utils.translation import gettext as _
# Make unittest ignore frames in this module when reporting failures.
__unittest = True
class CSPMiddleware(MiddlewareMixin):
"""The admin's JavaScript should be compatible with CSP."""
def process_response(self, request, response):
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response
@modify_settings(MIDDLEWARE={"append": "django.contrib.admin.tests.CSPMiddleware"})
@modify_settings(
MIDDLEWARE={"append": "django.middleware.csp.ContentSecurityPolicyMiddleware"}
)
@override_settings(
SECURE_CSP={
"default-src": [CSP.NONE],
"connect-src": [CSP.SELF],
"img-src": [CSP.SELF],
"script-src": [CSP.SELF],
"style-src": [CSP.SELF],
},
)
class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
available_apps = [
"django.contrib.admin",
@ -28,6 +31,11 @@ class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
"django.contrib.sites",
]
def tearDown(self):
# Ensure that no CSP violations were logged in the browser.
self.assertEqual(self.get_browser_logs(source="security"), [])
super().tearDown()
def wait_until(self, callback, timeout=10):
"""
Block the execution of the tests until the specified callback returns a

View File

@ -77,7 +77,11 @@ class SeleniumTestCaseBase(type(LiveServerTestCase)):
def get_capability(cls, browser):
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
return getattr(DesiredCapabilities, browser.upper())
caps = getattr(DesiredCapabilities, browser.upper())
if browser == "chrome":
caps["goog:loggingPrefs"] = {"browser": "ALL"}
return caps
def create_options(self):
options = self.import_options(self.browser)()
@ -237,6 +241,19 @@ class SeleniumTestCase(LiveServerTestCase, metaclass=SeleniumTestCaseBase):
path.parent.mkdir(exist_ok=True, parents=True)
self.selenium.save_screenshot(path)
def get_browser_logs(self, source=None, level="ALL"):
"""Return Chrome console logs filtered by level and optionally source."""
try:
logs = self.selenium.get_log("browser")
except AttributeError:
logs = []
return [
log
for log in logs
if (level == "ALL" or log["level"] == level)
and (source is None or log["source"] == source)
]
@classmethod
def _quit_selenium(cls):
# quit() the WebDriver before attempting to terminate and join the