diff --git a/intelmq/bots/experts/sieve/expert.py b/intelmq/bots/experts/sieve/expert.py index 995c2689a5..942d4cccee 100644 --- a/intelmq/bots/experts/sieve/expert.py +++ b/intelmq/bots/experts/sieve/expert.py @@ -537,6 +537,11 @@ def validate_numeric_match(num_match) -> None: if type not in valid_types: raise TextXSemanticError(f"Incompatible type: {type}.", **position) except KeyError: + if any( + num_match.key.startswith(f"{key}.") and value["type"] == "JSONDict" + for key, value in SieveExpertBot._harmonization.items() + ): + return raise TextXSemanticError(f"Invalid key: {num_match.key}.", **position) @staticmethod diff --git a/intelmq/tests/bots/experts/sieve/test_expert.py b/intelmq/tests/bots/experts/sieve/test_expert.py index 20023b4137..875cbf8142 100644 --- a/intelmq/tests/bots/experts/sieve/test_expert.py +++ b/intelmq/tests/bots/experts/sieve/test_expert.py @@ -585,6 +585,21 @@ def test_numeric_invalid_key(self): exception = context.exception self.assertRegex(str(exception), r".*Incompatible type: FQDN\.$") + def test_numeric_extra_jsondict_match(self): + """Test numeric match for dynamic extra.* fields.""" + self.sysconfig["file"] = os.path.join( + os.path.dirname(__file__), + "test_sieve_files/test_numeric_extra_jsondict.sieve", + ) + + event = EXAMPLE_INPUT.copy() + event["extra.min_amplification"] = 6 + expected = event.copy() + expected["comment"] = "matched extra numeric field" + self.input_message = event + self.run_bot() + self.assertMessageEqual(0, expected) + def test_exists_match(self): """Test :exists match""" self.sysconfig["file"] = os.path.join( diff --git a/intelmq/tests/bots/experts/sieve/test_sieve_files/test_numeric_extra_jsondict.sieve b/intelmq/tests/bots/experts/sieve/test_sieve_files/test_numeric_extra_jsondict.sieve new file mode 100644 index 0000000000..0ef7abc8f7 --- /dev/null +++ b/intelmq/tests/bots/experts/sieve/test_sieve_files/test_numeric_extra_jsondict.sieve @@ -0,0 +1,3 @@ +if extra.min_amplification > 5 { + add comment = "matched extra numeric field" +}