From f97e1361cf85273e30a83dfdc5ceb9ec4d028b94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 00:07:35 +0000 Subject: [PATCH 1/5] Bump cryptography from 41.0.4 to 41.0.6 in /server/installer Bumps [cryptography](https://github.com/pyca/cryptography) from 41.0.4 to 41.0.6. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/41.0.4...41.0.6) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- server/installer/installer_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/installer/installer_requirements.txt b/server/installer/installer_requirements.txt index b4c2a6eb6..701b21a4c 100644 --- a/server/installer/installer_requirements.txt +++ b/server/installer/installer_requirements.txt @@ -1,7 +1,7 @@ # dev only flake8 -cryptography==41.0.4 +cryptography==41.0.6 python-on-whales==0.50.0 prompt-toolkit==3.0.30 semantic_version==2.10.0 From 159182892394f349321ef79667d5265cd3107d19 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Fri, 22 Dec 2023 10:25:58 +0000 Subject: [PATCH 2/5] Remove invalid assertion following SQLAlchemy upgrade Since SQLAlchemy 1.4, the return value from Session.execute() is now a CursorResult object and the type of CursorResult.inserted_primary_key is now a tuple, not a list. --- server/camcops_server/cc_modules/client_api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/server/camcops_server/cc_modules/client_api.py b/server/camcops_server/cc_modules/client_api.py index 46a70df7a..735ec3935 100644 --- a/server/camcops_server/cc_modules/client_api.py +++ b/server/camcops_server/cc_modules/client_api.py @@ -1688,7 +1688,6 @@ def insert_record( table.insert().values(valuedict) ) # type: CursorResult inserted_pks = rp.inserted_primary_key - assert isinstance(inserted_pks, list) and len(inserted_pks) == 1 return inserted_pks[0] From 75f57e04fe168681ec306fc65c593282976e3e6c Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Fri, 20 Oct 2023 16:30:24 +0100 Subject: [PATCH 3/5] Bump urllib3 to fix CVE-2023-45803 --- server/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/setup.py b/server/setup.py index 8ec63e37c..740432b2e 100644 --- a/server/setup.py +++ b/server/setup.py @@ -120,7 +120,7 @@ "sqlalchemy==1.4.49", # database access "statsmodels==0.13.5", # e.g. logistic regression "twilio==7.9.3", # SMS backend for Multi-factor authentication - "urllib3==1.26.17", # dependency, pinned to avoid vulnerabilities + "urllib3==1.26.18", # dependency, pinned to avoid vulnerabilities "Wand==0.6.1", # ImageMagick binding # ------------------------------------------------------------------------- # Not installed here From 0c82c340580aaf665041387bc01d6f20d7726c23 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Thu, 23 Nov 2023 10:26:52 +0000 Subject: [PATCH 4/5] Bump pypdf to fix CVE-2023-46250 --- server/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/setup.py b/server/setup.py index 740432b2e..d132f8872 100644 --- a/server/setup.py +++ b/server/setup.py @@ -150,7 +150,7 @@ "prettytable==0.7.2", "psutil==5.7.0", "pyparsing==2.4.7", - "pypdf==3.9.0", # Used by cardinal_pythonlib.pdf + "pypdf==3.17.0", # Used by cardinal_pythonlib.pdf "python-dateutil==2.8.1", # date/time extensions. "sqlparse==0.4.4", # extra From 4b258b9ace248ddc3c410aab4c8db816351e5552 Mon Sep 17 00:00:00 2001 From: Rudolf Cardinal Date: Wed, 27 Dec 2023 15:06:14 +0000 Subject: [PATCH 5/5] Add comment about inserted_primary_key checks, and shorten code very slightly --- .../camcops_server/cc_modules/client_api.py | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/server/camcops_server/cc_modules/client_api.py b/server/camcops_server/cc_modules/client_api.py index 735ec3935..655aa984a 100644 --- a/server/camcops_server/cc_modules/client_api.py +++ b/server/camcops_server/cc_modules/client_api.py @@ -1687,8 +1687,25 @@ def insert_record( rp = req.dbsession.execute( table.insert().values(valuedict) ) # type: CursorResult - inserted_pks = rp.inserted_primary_key - return inserted_pks[0] + # In SQLAlchemy 1.3, execute() returned a ResultProxy, and after an + # insert() call, ResultProxy.inserted_primary_key was a list of scalars, + # corresponding to the list of primary key columns in the target table, + # representing the primary key of the row just inserted (a list because a + # primary key can be a composite of many columns) [1]. We then asserted it + # was a list of length 1, and returned the first element. In SQLAlchemy + # 1.4+, we get a CursorResult back instead, and its inserted_primary_key is + # a named tuple of primary key values, for that single inserted row [2] (or + # None if there was not a valid single-row insert, or raises an exception + # after a multi-row insert) [3]. The previous length check was likely an + # inaccurate attempt to check that 1 row had been inserted (rather than + # that there was 1 primary key column). If the insert fails, however, the + # database call will raise an exception; and even if it didn't, the attempt + # to access rp.inserted_primary_key[0] as None[0] would raise a TypeError. + # So the additional assertion was a waste of time. + # [1] https://docs.sqlalchemy.org/en/13/core/connections.html#sqlalchemy.engine.ResultProxy.inserted_primary_key # noqa: E501 + # [2] https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.BaseCursorResult.inserted_primary_key # noqa: E501 + # [3] see sqlalchemy/engine/cursor.py + return rp.inserted_primary_key[0] def audit_upload( @@ -3377,7 +3394,7 @@ def main_client_api(req: "CamcopsRequest") -> Dict[str, str]: def client_api(req: "CamcopsRequest") -> Response: """ View for client API. All tablet interaction comes through here. - Wraps :func:`main_client_api`. + Wraps :func:`main_client_api`. Handles exceptions. Internally, replies are managed as dictionaries. For the final reply, the dictionary is converted to text in this format: