diff --git a/netbox/extras/conditions.py b/netbox/extras/conditions.py index 6aa6e776f..050d5564c 100644 --- a/netbox/extras/conditions.py +++ b/netbox/extras/conditions.py @@ -40,11 +40,24 @@ class Condition: EQ, NEQ, GT, GTE, LT, LTE, IN, CONTAINS ) + TYPES = { + str: (EQ, NEQ, CONTAINS), + bool: (EQ, NEQ, CONTAINS), + int: (EQ, NEQ, GT, GTE, LT, LTE, CONTAINS), + float: (EQ, NEQ, GT, GTE, LT, LTE, CONTAINS), + list: (EQ, NEQ, IN, CONTAINS) + } + def __init__(self, attr, value, op=EQ): + if op not in self.OPERATORS: + raise ValueError(f"Unknown operator: {op}. Must be one of: {', '.join(self.OPERATORS)}") + if type(value) not in self.TYPES: + raise ValueError(f"Unsupported value type: {type(value)}") + if op not in self.TYPES[type(value)]: + raise ValueError(f"Invalid type for {op} operation: {type(value)}") + self.attr = attr self.value = value - if op not in self.OPERATORS: - raise ValueError(f"Unknown operator: {op}") self.eval_func = getattr(self, f'eval_{op}') def eval(self, data): diff --git a/netbox/extras/tests/test_conditions.py b/netbox/extras/tests/test_conditions.py index 7defca5b5..2ce55c064 100644 --- a/netbox/extras/tests/test_conditions.py +++ b/netbox/extras/tests/test_conditions.py @@ -16,6 +16,25 @@ class ConditionTestCase(TestCase): self.assertFalse(c.eval({})) self.assertTrue(c.eval({'x': 1})) + # + # Validation tests + # + + def test_invalid_op(self): + with self.assertRaises(ValueError): + # 'blah' is not a valid operator + Condition('x', 1, 'blah') + + def test_invalid_type(self): + with self.assertRaises(ValueError): + # dict type is unsupported + Condition('x', 1, dict()) + + def test_invalid_op_type(self): + with self.assertRaises(ValueError): + # 'gt' supports only numeric values + Condition('x', 'foo', 'gt') + # # Operator tests #