diff --git a/backend/infrahub/core/schema/node_schema.py b/backend/infrahub/core/schema/node_schema.py index b6645fad13..a642ef5964 100644 --- a/backend/infrahub/core/schema/node_schema.py +++ b/backend/infrahub/core/schema/node_schema.py @@ -41,12 +41,18 @@ def validate_inheritance(self, interface: GenericSchema) -> None: raise ValueError( f"{self.kind}'s attribute {attribute.name} inherited from {interface.kind} cannot be overriden" ) + + interface_attr = interface.get_attribute(attribute.name) # Check existing inherited attribute kind is the same as the incoming inherited attribute - interface_attr_kind = interface.get_attribute(attribute.name).kind - if attribute.kind != interface_attr_kind: + if attribute.kind != interface_attr.kind: raise ValueError( f"{self.kind}.{attribute.name} inherited from {interface.namespace}{interface.name} must be the same kind " - f'["{interface_attr_kind}", "{attribute.kind}"]' + f'["{interface_attr.kind}", "{attribute.kind}"]' + ) + if attribute.optional != interface_attr.optional: + raise ValueError( + f"{self.kind}.{attribute.name} inherited from {interface.namespace}{interface.name} must have the same value for property " + f'"optional" ["{interface_attr.optional}", "{attribute.optional}"]' ) for relationship in self.relationships: diff --git a/backend/tests/unit/core/schema_manager/test_manager_schema.py b/backend/tests/unit/core/schema_manager/test_manager_schema.py index bcbf8a9a7c..1b1f4bce9c 100644 --- a/backend/tests/unit/core/schema_manager/test_manager_schema.py +++ b/backend/tests/unit/core/schema_manager/test_manager_schema.py @@ -146,6 +146,26 @@ async def test_schema_process_inheritance_different_generic_attribute_types_on_n assert exc.value.args[0] == 'TestWidget.choice inherited from TestAdapter must be the same kind ["Text", "List"]' +async def test_schema_process_inheritance_different_generic_attribute_optional_on_node( + schema_diff_attr_inheritance_types, +): + """Test that we raise an exception if a node is inheriting an attribute changing its optional property value.""" + schema = SchemaBranch(cache={}, name="test") + schema_new = copy.deepcopy(schema_diff_attr_inheritance_types) + schema_new["generics"].pop() + schema_new["nodes"][0]["inherit_from"].pop() + schema_new["nodes"][0]["attributes"].append({"name": "choice", "kind": "Text", "optional": False}) + schema.load_schema(schema=SchemaRoot(**schema_new)) + + with pytest.raises(ValueError) as exc: + schema.process_inheritance() + + assert ( + exc.value.args[0] + == 'TestWidget.choice inherited from TestAdapter must have the same value for property "optional" ["True", "False"]' + ) + + async def test_schema_branch_process_inheritance_node_level(animal_person_schema_dict): schema = SchemaBranch(cache={}, name="test") schema.load_schema(schema=SchemaRoot(**animal_person_schema_dict)) diff --git a/changelog/4936.fixed.md b/changelog/4936.fixed.md new file mode 100644 index 0000000000..c1093a288a --- /dev/null +++ b/changelog/4936.fixed.md @@ -0,0 +1 @@ +Forbid changing the "optional" property of an inherited attribute to not break GraphQL schema generation \ No newline at end of file