mirror of
https://github.com/django/django.git
synced 2025-06-30 07:49:19 +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:
parent
d63241ebc7
commit
ff0ff98d42
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user