diff mbox series

[error-report-web,2/2] Remove bleach and store submitted data as sent.

Message ID 20261018020518.76802-5-tim.orling@konsulko.com
State New
Headers show
Series Don't render submitted data as HTML | expand

Commit Message

Tim Orling Oct. 18, 2026, 2:03 a.m. UTC
bleach stored escaped text, so "<" or "&" showed as "&lt;" or "&amp;".
Escaping on output covers every place the data is shown, and bleach is
deprecated. Existing reports keep their escaped text.

AI-Generated: Claude Opus 5.5
Signed-off-by: Tim Orling <tim.orling@konsulko.com>
---
 Post/parser.py   | 10 ----------
 Post/test.py     | 10 ++++++++++
 requirements.txt |  1 -
 3 files changed, 10 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/Post/parser.py b/Post/parser.py
index 092ce24..e221bcf 100644
--- a/Post/parser.py
+++ b/Post/parser.py
@@ -10,7 +10,6 @@ 
 
 import json
 import re
-import bleach
 from Post.models import Build, BuildFailure, ErrorType
 from Post.validators import clean_link_back
 from django.conf import settings
@@ -30,15 +29,6 @@  class Parser:
         except Exception:
              return  { 'error' : 'Invalid json' }
 
-        # Bleach data going directly into the database so that
-        # displaying in any of the graphing doesn't introduce XSS
-        for key,val in jsondata.items():
-            if key == 'failures':
-                continue
-            if not isinstance(val, str):
-                continue
-            jsondata[key] = bleach.clean(val)
-
         b = Build.objects.create()
         try:
             b.MACHINE = str(jsondata['machine'])
diff --git a/Post/test.py b/Post/test.py
index 0a358d1..51ae0b9 100755
--- a/Post/test.py
+++ b/Post/test.py
@@ -462,6 +462,16 @@  class SubmittedHtmlTest(TestCase):
         self.assertNotContains(response, "data-content")
         self.assertNotContains(response, "data-html")
 
+    def test_build_fields_are_stored_as_sent_and_escaped(self):
+        client, bf = self.submit(machine="<script>alert(1)</script>")
+        # Stored as sent; escaped on output.
+        self.assertEqual(bf.BUILD.MACHINE, "<script>alert(1)</script>")
+        for url in ("/Errors/Latest/", "/Errors/Details/%d/" % bf.id,
+                    "/Errors/Statistics/MACHINE"):
+            response = client.get(url)
+            self.assertEqual(response.status_code, 200, url)
+            self.assertNotContains(response, "<script>alert", msg_prefix=url)
+
     def test_tooltips_are_not_html(self):
         with open("Post/static/js/main.js") as f:
             self.assertNotRegex(f.read(), r"tooltip\(\{[^}]*html: true")
diff --git a/requirements.txt b/requirements.txt
index 40f3433..59c10a9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@ 
 Django>=5.2.18,<5.3
 python-Levenshtein==0.27.4
-bleach==6.4.0
 mysqlclient==2.3.0