From 6cfc4c70e3b662f024e6abe62254c6b8756b90a9 Mon Sep 17 00:00:00 2001 From: Philipp Hagemeister Date: Thu, 7 Nov 2024 08:58:08 +0100 Subject: [PATCH 1/2] Do not raise AttributeError when parsing non-string UUIDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a user sends a dictionary or other object as a UUID variable like `{[123]}`, previously graphene crashed with an `AttributeError`, like this: ``` (…) File "…/lib/python3.12/site-packages/graphql/utils/is_valid_value.py", line 78, in is_valid_value parse_result = type.parse_value(value) ^^^^^^^^^^^^^^^^^^^^^^^ File "…/lib/python3.12/site-packages/graphene/types/uuid.py", line 33, in parse_value return _UUID(value) ^^^^^^^^^^^^ File "/usr/lib/python3.12/uuid.py", line 175, in __init__ hex = hex.replace('urn:', '').replace('uuid:', '') ^^^^^^^^^^^ AttributeError: 'dict' object has no attribute 'replace' ``` But an `AttributeError` makes it seem like this is the server's fault, when it's obviously the client's. Report a proper GraphQLError. --- graphene/types/tests/test_uuid.py | 15 +++++++++++++++ graphene/types/uuid.py | 3 +++ 2 files changed, 18 insertions(+) diff --git a/graphene/types/tests/test_uuid.py b/graphene/types/tests/test_uuid.py index d34f16642..c8f3947ee 100644 --- a/graphene/types/tests/test_uuid.py +++ b/graphene/types/tests/test_uuid.py @@ -36,6 +36,21 @@ def test_uuidstring_query_variable(): assert result.data == {"uuid": uuid_value} +def test_uuidstring_invalid_argument(): + uuid_value = {"not": "a string"} + + result = schema.execute( + """query Test($uuid: UUID){ uuid(input: $uuid) }""", + variables={"uuid": uuid_value}, + ) + assert result.errors + assert len(result.errors) == 1 + assert ( + result.errors[0].message + == "Variable '$uuid' got invalid value {'not': 'a string'}; UUID must be a string" + ) + + def test_uuidstring_optional_uuid_input(): """ Test that we can provide a null value to an optional input diff --git a/graphene/types/uuid.py b/graphene/types/uuid.py index 773e31c73..32f390d13 100644 --- a/graphene/types/uuid.py +++ b/graphene/types/uuid.py @@ -1,5 +1,6 @@ from uuid import UUID as _UUID +from graphql.error import GraphQLError from graphql.language.ast import StringValueNode from graphql import Undefined @@ -28,4 +29,6 @@ def parse_literal(node, _variables=None): @staticmethod def parse_value(value): + if not isinstance(value, (str, _UUID)): + raise GraphQLError("UUID must be a string") return _UUID(value) From e354759708497895a1503a2160c8233f45127409 Mon Sep 17 00:00:00 2001 From: Erik Wrede Date: Sat, 9 Nov 2024 18:38:36 +0100 Subject: [PATCH 2/2] fix: adjust exception message structure --- graphene/types/tests/test_uuid.py | 2 +- graphene/types/uuid.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/graphene/types/tests/test_uuid.py b/graphene/types/tests/test_uuid.py index c8f3947ee..d031387b8 100644 --- a/graphene/types/tests/test_uuid.py +++ b/graphene/types/tests/test_uuid.py @@ -47,7 +47,7 @@ def test_uuidstring_invalid_argument(): assert len(result.errors) == 1 assert ( result.errors[0].message - == "Variable '$uuid' got invalid value {'not': 'a string'}; UUID must be a string" + == "Variable '$uuid' got invalid value {'not': 'a string'}; UUID cannot represent value: {'not': 'a string'}" ) diff --git a/graphene/types/uuid.py b/graphene/types/uuid.py index 32f390d13..5f10a22e2 100644 --- a/graphene/types/uuid.py +++ b/graphene/types/uuid.py @@ -29,6 +29,9 @@ def parse_literal(node, _variables=None): @staticmethod def parse_value(value): - if not isinstance(value, (str, _UUID)): - raise GraphQLError("UUID must be a string") - return _UUID(value) + if isinstance(value, _UUID): + return value + try: + return _UUID(value) + except (ValueError, AttributeError): + raise GraphQLError(f"UUID cannot represent value: {repr(value)}")