Repository: sphinx-doc/sphinx

Issue:
Add support for verifying content downloaded from mathjax_path with the integrity html attribute
In order to guard web users from compromised CDN servers (which is a frightening concept), Mozilla and Chrome has added support for the browser to [verify the integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) of scripts and/or css used in a webpage by adding one or more space-separated hash digests to the `integrity` attribute of the `<script>` tag, like so:

    <script src="https://example.com/example-framework.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

I suggest adding a `mathjax_integrity` configuration value.

If set it must be a string like `"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"`, and this string, in quotes, will then be prepended with `integrity=` and added as an attribute to the mathjax script tag.

If `mathjax_integrity` it is not set then no `integrity` attribute will be added and things will work exactly as before.


Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index c2c0bd45c..a4beb3c7d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -137,6 +137,8 @@ Features added
 * html: Output ``canonical_url`` metadata if :confval:`html_baseurl` set (refs:
   #4193)
 * #5029: autosummary: expose ``inherited_members`` to template
+* #3784: mathjax: Add :confval:`mathjax_options` to give options to script tag
+  for mathjax
 
 Bugs fixed
 ----------
diff --git a/doc/ext/math.rst b/doc/ext/math.rst
index c00713a3d..c299b7bee 100644
--- a/doc/ext/math.rst
+++ b/doc/ext/math.rst
@@ -260,6 +260,16 @@ Sphinx.
 
    You can also give a full ``https://`` URL different from the CDN URL.
 
+.. confval:: mathjax_options
+
+   The options to script tag for mathjax.  For example, you can set integrity
+   option with following setting::
+
+       mathjax_options = {
+           'integrity': 'sha384-......',
+       }
+
+   The default is empty (``{}``).
 
 :mod:`sphinx.ext.jsmath` -- Render math via JavaScript
 ------------------------------------------------------
diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py
index 8aeafefc7..0d73f3d3d 100644
--- a/sphinx/ext/mathjax.py
+++ b/sphinx/ext/mathjax.py
@@ -74,6 +74,8 @@ def builder_inited(app):
                              'mathjax extension to work')
     if app.builder.format == 'html':
         options = {'async': 'async'}
+        if app.config.mathjax_options:
+            options.update(app.config.mathjax_options)
         app.builder.add_js_file(app.config.mathjax_path, **options)  # type: ignore
 
 
@@ -88,7 +90,8 @@ def setup(app):
     # https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn
     app.add_config_value('mathjax_path',
                          'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?'
-                         'config=TeX-AMS-MML_HTMLorMML', False)
+                         'config=TeX-AMS-MML_HTMLorMML', 'html')
+    app.add_config_value('mathjax_options', {}, 'html')
     app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
     app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
     app.connect('builder-inited', builder_inited)


Test patch:
diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py
index 47465f07e..99940977b 100644
--- a/tests/test_ext_math.py
+++ b/tests/test_ext_math.py
@@ -89,6 +89,18 @@ def test_imgmath_svg(app, status, warning):
     assert re.search(html, content, re.S)
 
 
+@pytest.mark.sphinx('html', testroot='ext-math',
+                    confoverrides={'extensions': ['sphinx.ext.mathjax'],
+                                   'mathjax_options': {'integrity': 'sha384-0123456789'}})
+def test_mathjax_options(app, status, warning):
+    app.builder.build_all()
+
+    content = (app.outdir / 'index.html').text()
+    assert ('<script async="async" integrity="sha384-0123456789" type="text/javascript" '
+            'src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?'
+            'config=TeX-AMS-MML_HTMLorMML"></script>' in content)
+
+
 @pytest.mark.sphinx('html', testroot='ext-math',
                     confoverrides={'extensions': ['sphinx.ext.mathjax']})
 def test_mathjax_align(app, status, warning):