diff test/rest_common.py @ 8268:05d8806b25ad

fix: issue2551387 - TypeError: not indexable. Fix crash due to uninitialized list element on a (Mini)FieldStorage when unexpected input is posted via wsgi. This doesn't happen when running roundup-server. It might happen under other front ends. Moved the code that sets '.list = [] if .list == None' to the main flow. Added an exception hander that logs the value of self.form if self.form.list raises an AttributeError. This exception should never happen if I understand the code correctly (but I probably don't). Fixed a number of test cases that were broken because I was calling Client and passing '[]' rather than a cgi.formStorage object. Added test cases: create a FileStorage (self.form) with .list = None. check AttributeError exception and verify logging. Problem reported and debugged by Christof Meerwald.
author John Rouillard <rouilj@ieee.org>
date Sun, 12 Jan 2025 12:34:52 -0500
parents 8c1e0459b73d
children 1ffa1f42e1da
line wrap: on
line diff
--- a/test/rest_common.py	Thu Jan 09 10:14:55 2025 -0500
+++ b/test/rest_common.py	Sun Jan 12 12:34:52 2025 -0500
@@ -3,6 +3,7 @@
 import shutil
 import sys
 import errno
+import logging
 
 from time import sleep
 from datetime import datetime, timedelta
@@ -76,6 +77,10 @@
 
 class TestCase():
 
+    @pytest.fixture(autouse=True)
+    def inject_fixtures(self, caplog):
+        self._caplog = caplog
+
     backend = None
     url_pfx = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/'
 
@@ -291,7 +296,8 @@
             'HTTP_ORIGIN': 'http://tracker.example'
         }
         self.dummy_client = client.Client(self.instance, MockNull(),
-                                          self.client_env, [], None)
+                                          self.client_env,
+                                          cgi.FieldStorage(), None)
         self.dummy_client.request.headers.get = self.get_header
         self.dummy_client.db = self.db
 
@@ -2294,6 +2300,30 @@
                 self.assertNotIn("X-Content-Type-Options", 
                               self.server.client.additional_headers)
 
+    def testBadFormAttributeErrorException(self):
+        env = {
+            'PATH_INFO': 'rest/data/user',
+            'HTTP_HOST': 'localhost',
+            'TRACKER_NAME': 'rounduptest',
+            "REQUEST_METHOD": "GET"
+        }
+
+
+        with self._caplog.at_level(logging.ERROR, logger="roundup"):
+            with self.assertRaises(AttributeError) as exc:
+                self.dummy_client = client.Client(
+                    self.instance, MockNull(), env, [], None)
+
+        self.assertEqual(exc.exception.args[0],
+                         "'list' object has no attribute 'list'")
+
+        # log should look like (with string not broken into parts):
+        #    [('roundup', 40, 
+        #       'Invalid self.form found (please report to the '
+        #       'roundup-users mailing list): []')]
+        log = self._caplog.record_tuples[:]
+        self.assertIn("Invalid self.form found", log[0][2])
+
     def testDispatchBadAccept(self):
         # simulate: /rest/data/issue expect failure unknown accept settings
         body=b'{ "title": "Joe Doe has problems", \
@@ -4508,8 +4538,9 @@
             'TRACKER_NAME': 'rounduptest',
             "REQUEST_METHOD": "GET"
         }
+
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4517,7 +4548,6 @@
         self.terse_form.list = [
             cgi.MiniFieldStorage('@verbose', '0'),
         ]
-        self.dummy_client.form = cgi.FieldStorage()
         self.dummy_client.form.list = [
             cgi.MiniFieldStorage('@fields', 'username,address'),
         ]
@@ -4575,7 +4605,7 @@
         )
 
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4645,7 +4675,7 @@
         }
 
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4710,7 +4740,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4781,7 +4811,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4849,7 +4879,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4891,7 +4921,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4930,7 +4960,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -4966,7 +4996,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -5003,7 +5033,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                          cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()
@@ -5039,7 +5069,7 @@
             "REQUEST_METHOD": "GET"
         }
         self.dummy_client = client.Client(self.instance, MockNull(), env,
-                                          [], None)
+                                           cgi.FieldStorage(), None)
         self.dummy_client.db = self.db
         self.dummy_client.request.headers.get = self.get_header
         self.empty_form = cgi.FieldStorage()

Roundup Issue Tracker: http://roundup-tracker.org/