Skip to content

Commit cba8d01

Browse files
committed
Test CSP nonce support and require django-js-asset 4
The import-map rework now rides on js_asset.Media, so require django-js-asset>=4 and finalize the changelog accordingly. Add tests verifying the request nonce reaches the merged import map, the module scripts and the stylesheets through with_nonce(), render(nonce=) and render(attrs={"nonce": ...}) -- the last being the entry point Django 6.2's {% csp_nonce_attr %} tag uses. The tests are gated to Django 6.0+; the rendered output is identical on older versions but we only verify it on newer ones. Refs #34
1 parent 2bd89cc commit cba8d01

3 files changed

Lines changed: 48 additions & 8 deletions

File tree

CHANGELOG.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Change log
44
Next version
55
~~~~~~~~~~~~
66

7-
- The editor's import map is now carried by the widget and field media and
8-
merged through ``js_asset.Media`` instead of the global ``importmap`` object
9-
that ``django-js-asset`` has removed. Rendering ``{{ form.media }}`` now emits
10-
the ``<script type="importmap">`` automatically -- in the admin **and** in
11-
your own frontend templates -- so you can drop the
7+
- **Requires django-js-asset 4.0 or newer.** The editor's import map is now
8+
carried by the widget and field media and merged through ``js_asset.Media``
9+
instead of the global ``importmap`` object that django-js-asset 4.0 has
10+
removed. Rendering ``{{ form.media }}`` now emits the
11+
``<script type="importmap">`` automatically -- in the admin **and** in your
12+
own frontend templates -- so you can drop the
1213
``js_asset.context_processors.importmap`` context processor and the
13-
``{{ importmap }}`` tag from your templates. Requires the upcoming
14-
``django-js-asset`` release that ships ``js_asset.Media``.
14+
``{{ importmap }}`` tag from your templates.
1515
- Rewrote the ``Figure`` extension to handle both figure-wrapped images and
1616
standalone bare images. The caption field has been removed from the edit
1717
dialog (it stripped all formatting from the caption text). Instead, a

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ dynamic = [
3636
]
3737
dependencies = [
3838
"django>=4.2",
39-
"django-js-asset>=3.1.2", # FIXME bump once the js_asset.Media release is cut
39+
"django-js-asset>=4",
4040
]
4141
optional-dependencies.cabinet = [
4242
"django-cabinet>=0.19",

tests/testapp/test_prose_editor.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from unittest import skipUnless
2+
3+
import django
14
from django import test
25
from django.contrib.auth.models import User
36
from django.test import Client
@@ -85,3 +88,40 @@ def test_utilities(self):
8588
<script src="/static/django_prose_editor/editor.js" type="module"></script>
8689
<script src="/static/django_prose_editor/default.js" type="module"></script>"""
8790
)
91+
92+
93+
@skipUnless(
94+
django.VERSION >= (6, 0),
95+
"CSP nonce support is only verified on newer Django versions",
96+
)
97+
class CSPNonceTest(test.SimpleTestCase):
98+
"""
99+
The CSP nonce plumbing lives in ``js_asset.Media`` (which
100+
``prose_editor_media()`` returns); these tests make sure a nonce reaches
101+
every tag we render -- the import map, the module scripts and the
102+
stylesheets.
103+
"""
104+
105+
def test_with_nonce_applies_to_all_tags(self):
106+
html = prose_editor_media().with_nonce("r4nd0m").render()
107+
assert '<script type="importmap" nonce="r4nd0m">' in html
108+
assert (
109+
'<script src="/static/django_prose_editor/editor.js"'
110+
' nonce="r4nd0m" type="module"></script>' in html
111+
)
112+
assert (
113+
'<link href="/static/django_prose_editor/material-icons.css"'
114+
' media="all" nonce="r4nd0m" rel="stylesheet">' in html
115+
)
116+
117+
def test_render_nonce_keyword(self):
118+
html = prose_editor_media().render(nonce="abc")
119+
assert 'nonce="abc"' in html
120+
121+
def test_render_attrs_nonce(self):
122+
# This is exactly what Django 6.2's ``{% csp_nonce_attr %}`` tag calls.
123+
html = prose_editor_media().render(attrs={"nonce": "xyz"})
124+
assert 'nonce="xyz"' in html
125+
126+
def test_without_nonce_no_attribute(self):
127+
assert "nonce=" not in prose_editor_media().render()

0 commit comments

Comments
 (0)