| 
2 | 2 | 
 
  | 
3 | 3 | import pytest  | 
4 | 4 | import numpy as np  | 
 | 5 | +import re  | 
5 | 6 | 
 
  | 
6 | 7 | 
 
  | 
7 | 8 | import plotly.graph_objs as go  | 
8 | 9 | import plotly.io as pio  | 
9 | 10 | from plotly.io._utils import plotly_cdn_url  | 
 | 11 | +from plotly.offline.offline import get_plotlyjs  | 
 | 12 | +from plotly.io._html import _generate_sri_hash  | 
10 | 13 | 
 
  | 
11 | 14 | 
 
  | 
12 | 15 | if sys.version_info >= (3, 3):  | 
@@ -46,3 +49,41 @@ def test_html_deterministic(fig1):  | 
46 | 49 |  assert pio.to_html(fig1, include_plotlyjs="cdn", div_id=div_id) == pio.to_html(  | 
47 | 50 |  fig1, include_plotlyjs="cdn", div_id=div_id  | 
48 | 51 |  )  | 
 | 52 | + | 
 | 53 | + | 
 | 54 | +def test_cdn_includes_integrity_attribute(fig1):  | 
 | 55 | + """Test that the CDN script tag includes an integrity attribute with SHA256 hash"""  | 
 | 56 | + html_output = pio.to_html(fig1, include_plotlyjs="cdn")  | 
 | 57 | + | 
 | 58 | + # Check that the script tag includes integrity attribute  | 
 | 59 | + assert 'integrity="sha256-' in html_output  | 
 | 60 | + assert 'crossorigin="anonymous"' in html_output  | 
 | 61 | + | 
 | 62 | + # Verify it's in the correct script tag  | 
 | 63 | + cdn_pattern = re.compile(  | 
 | 64 | + r'<script[^>]*src="'  | 
 | 65 | + + re.escape(plotly_cdn_url())  | 
 | 66 | + + r'"[^>]*integrity="sha256-[A-Za-z0-9+/=]+"[^>]*>'  | 
 | 67 | + )  | 
 | 68 | + match = cdn_pattern.search(html_output)  | 
 | 69 | + assert match is not None, "CDN script tag with integrity attribute not found"  | 
 | 70 | + | 
 | 71 | + | 
 | 72 | +def test_cdn_integrity_hash_matches_bundled_content(fig1):  | 
 | 73 | + """Test that the SRI hash in CDN script tag matches the bundled plotly.js content"""  | 
 | 74 | + html_output = pio.to_html(fig1, include_plotlyjs="cdn")  | 
 | 75 | + | 
 | 76 | + # Extract the integrity hash from the HTML output  | 
 | 77 | + integrity_pattern = re.compile(r'integrity="(sha256-[A-Za-z0-9+/=]+)"')  | 
 | 78 | + match = integrity_pattern.search(html_output)  | 
 | 79 | + assert match is not None, "Integrity attribute not found"  | 
 | 80 | + extracted_hash = match.group(1)  | 
 | 81 | + | 
 | 82 | + # Generate expected hash from bundled content  | 
 | 83 | + plotlyjs_content = get_plotlyjs()  | 
 | 84 | + expected_hash = _generate_sri_hash(plotlyjs_content)  | 
 | 85 | + | 
 | 86 | + # Verify they match  | 
 | 87 | + assert (  | 
 | 88 | + extracted_hash == expected_hash  | 
 | 89 | + ), f"Hash mismatch: expected {expected_hash}, got {extracted_hash}"  | 
0 commit comments