From 926c48c498e9d8e9b8230eb44c95088f89e40d62 Mon Sep 17 00:00:00 2001 From: dmnk <4406409+dmnk@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:12:10 +0100 Subject: [PATCH 1/8] extract validator setup --- sigma/cli/check.py | 59 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index 33cc5fb..e276dea 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -19,6 +19,33 @@ severity_color = {"low": "green", "medium": "yellow", "high": "red"} +def setup_validator(validation_config, excluded, exclude, validator, name): + if ( + validation_config is None + ): # no validation config provided, use basic config with all validators + exclude_lower = [excluded.lower() for excluded in exclude] + exclude_invalid = [ + excluded for excluded in exclude_lower if excluded not in validators.keys() + ] + exclude_valid = [ + excluded for excluded in exclude_lower if excluded not in exclude_invalid + ] + + report_config_warnings(exclude_invalid, exclude_valid) + + validators_filtered = [ + validator + for name, validator in validators.items() + if name.lower() not in exclude_valid + ] + rule_validator = SigmaValidator(validators_filtered) + else: + if exclude: + click.echo( + f"A configuration file and the `--exclude` parameter was set, ignoring the `--exclude` parameter." + ) + rule_validator = SigmaValidator.from_yaml(validation_config.read(), validators) + return rule_validator @click.command() @click.option( @@ -66,36 +93,8 @@ def check( input, validation_config, file_pattern, fail_on_error, fail_on_issues, exclude ): """Check Sigma rules for validity and best practices (not yet implemented).""" - if ( - validation_config is None - ): # no validation config provided, use basic config with all validators - exclude_lower = [excluded.lower() for excluded in exclude] - exclude_invalid = [ - excluded for excluded in exclude_lower if excluded not in validators.keys() - ] - exclude_valid = [ - excluded for excluded in exclude_lower if excluded not in exclude_invalid - ] - - if len(exclude_invalid) > 0: - click.echo( - f"Invalid validators name : {exclude_invalid} use 'sigma list validators'" - ) - if len(exclude_valid) > 0: - click.echo(f"Ignoring these validators : {exclude_valid}'") - - validators_filtered = [ - validator - for name, validator in validators.items() - if name.lower() not in exclude_valid - ] - rule_validator = SigmaValidator(validators_filtered) - else: - if exclude: - click.echo( - f"A configuration file and the `--exclude` parameter was set, ignoring the `--exclude` parameter." - ) - rule_validator = SigmaValidator.from_yaml(validation_config.read(), validators) + + rule_validator = setup_validator(validation_config, excluded, exclude, validator, name) try: rule_collection = load_rules(input, file_pattern) From db51dbfaca59c8258a49f26f14da0e4711170cac Mon Sep 17 00:00:00 2001 From: dmnk <4406409+dmnk@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:14:51 +0100 Subject: [PATCH 2/8] added report_config_warnings function --- sigma/cli/check.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index e276dea..bc358cd 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -19,6 +19,9 @@ severity_color = {"low": "green", "medium": "yellow", "high": "red"} +# ========================================== +# Data Processing & Extraction Functions +# ========================================== def setup_validator(validation_config, excluded, exclude, validator, name): if ( validation_config is None @@ -46,6 +49,17 @@ def setup_validator(validation_config, excluded, exclude, validator, name): ) rule_validator = SigmaValidator.from_yaml(validation_config.read(), validators) return rule_validator + +# ========================================== +# Reporting & Output Functions +# ========================================== + +def report_config_warnings(exclude_invalid, exclude_valid): + """Prints warnings regarding invalid or excluded validators.""" + if len(exclude_invalid) > 0: + click.echo(f"Invalid validators name : {exclude_invalid} use 'sigma list validators'") + if len(exclude_valid) > 0: + click.echo(f"Ignoring these validators : {exclude_valid}'") @click.command() @click.option( From c8e1177f3ed4f2fea323928a6e0e03ed2476e5f0 Mon Sep 17 00:00:00 2001 From: dmnk <4406409+dmnk@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:27:06 +0100 Subject: [PATCH 3/8] fixed improper parameters validator is global available --- sigma/cli/check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index bc358cd..3ba89c9 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -22,7 +22,7 @@ # ========================================== # Data Processing & Extraction Functions # ========================================== -def setup_validator(validation_config, excluded, exclude, validator, name): +def setup_validator(validation_config, exclude): if ( validation_config is None ): # no validation config provided, use basic config with all validators @@ -108,7 +108,7 @@ def check( ): """Check Sigma rules for validity and best practices (not yet implemented).""" - rule_validator = setup_validator(validation_config, excluded, exclude, validator, name) + rule_validator = setup_validator(validation_config, exclude) try: rule_collection = load_rules(input, file_pattern) From 37247592a2b4bd205174322dfff560dd9e1cff36 Mon Sep 17 00:00:00 2001 From: dmnk <4406409+dmnk@users.noreply.github.com> Date: Fri, 20 Mar 2026 08:17:55 +0100 Subject: [PATCH 4/8] relocate the global plugins and validators to the function requiring them --- sigma/cli/check.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index 3ba89c9..c0fa789 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -14,15 +14,16 @@ from sigma.validation import SigmaValidator from sigma.rule import SigmaRule -plugins = InstalledSigmaPlugins.autodiscover() -validators = plugins.validators - severity_color = {"low": "green", "medium": "yellow", "high": "red"} # ========================================== # Data Processing & Extraction Functions # ========================================== def setup_validator(validation_config, exclude): + + plugins = InstalledSigmaPlugins.autodiscover() + validators = plugins.validators + if ( validation_config is None ): # no validation config provided, use basic config with all validators From 237a9bf0ebdc12c703c02cf458ef08e4fc39f0a4 Mon Sep 17 00:00:00 2001 From: esoc_dominik Date: Fri, 20 Mar 2026 08:35:47 +0100 Subject: [PATCH 5/8] avoided reuse as different object of the rules variable --- sigma/cli/check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index c0fa789..5f80113 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -157,7 +157,7 @@ def check( click.echo("=== Issues ===") for issue in issues: # Need to split SigmaValidationIssue __str__ - rules = ", ".join( + formatted_rules_output = ", ".join( [ str(rule.source) if rule.source is not None @@ -185,7 +185,7 @@ def check( + " description=" + click.style(issue.description, bold=True, fg="blue") + " rule=" - + click.style(rules, bold=True, fg="blue") + + click.style(formatted_rules_output, bold=True, fg="blue") + f" {additional_fields}" ) issue_counter.update((issue.__class__,)) From 5d07c9e75914b9b5a06f5a110558a869eaa6c558 Mon Sep 17 00:00:00 2001 From: esoc_dominik Date: Fri, 20 Mar 2026 08:38:55 +0100 Subject: [PATCH 6/8] extracted rule validation function --- sigma/cli/check.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index 5f80113..1c3c765 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -62,6 +62,14 @@ def report_config_warnings(exclude_invalid, exclude_valid): if len(exclude_valid) > 0: click.echo(f"Ignoring these validators : {exclude_valid}'") +def validate_loaded_rules(check_rules, rule_validator): + with click.progressbar( + check_rules, label="Checking Sigma rules", file=stderr + ) as rules: + issues = rule_validator.validate_rules(rules) + return issues + + @click.command() @click.option( "--validation-config", @@ -146,10 +154,7 @@ def check( rule_error_count = sum(rule_errors.values()) # rule_error_count = rule_errors.total() - with click.progressbar( - check_rules, label="Checking Sigma rules", file=stderr - ) as rules: - issues = rule_validator.validate_rules(rules) + issues = validate_loaded_rules(check_rules, rule_validator) issue_count = len(issues) issue_counter = Counter() From 981ff3751814d32adb1e57653141b4f92f6dfd7b Mon Sep 17 00:00:00 2001 From: esoc_dominik Date: Fri, 20 Mar 2026 09:04:51 +0100 Subject: [PATCH 7/8] use overlap free variable name in the for loop (even if technically correctly scoped) --- sigma/cli/check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index 1c3c765..8eba9df 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -164,10 +164,10 @@ def check( # Need to split SigmaValidationIssue __str__ formatted_rules_output = ", ".join( [ - str(rule.source) - if rule.source is not None - else str(rule.id) or rule.title - for rule in issue.rules + str(rule_with_issue.source) + if rule_with_issue.source is not None + else str(rule_with_issue.id) or rule_with_issue.title + for rule_with_issue in issue.rules ] ) additional_fields = " ".join( From e45bd8d93ada8eb7111eeae884e6b47d8097faf7 Mon Sep 17 00:00:00 2001 From: esoc_dominik Date: Fri, 20 Mar 2026 09:10:35 +0100 Subject: [PATCH 8/8] extracted the load and check part --- sigma/cli/check.py | 58 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/sigma/cli/check.py b/sigma/cli/check.py index 8eba9df..b2565cd 100644 --- a/sigma/cli/check.py +++ b/sigma/cli/check.py @@ -70,6 +70,36 @@ def validate_loaded_rules(check_rules, rule_validator): return issues +def load_and_check_rules(input, file_pattern, rule_errors, cond_errors): + rule_collection = load_rules(input, file_pattern) + check_rules = list() + first_error = True + for rule in rule_collection.rules: + if ( + len(rule.errors) > 0 + ): # rule has errors: print errors and skip further checking of rule + if first_error: + click.echo("=== Sigma Rule Errors ===") + first_error = False + + for error in rule.errors: + click.echo(error) + rule_errors.update((error.__class__.__name__,)) + elif isinstance(rule, SigmaRule): # rule has no errors, parse condition + try: + for condition in rule.detection.parsed_condition: + condition.parse() + check_rules.append(rule) + except SigmaConditionError as e: # Error in condition + error = str(e) + click.echo( + f"Condition error in { str(condition.source) }:{ error }" + ) + cond_errors.update((error,)) + else: + check_rules.append(rule) + return check_rules + @click.command() @click.option( "--validation-config", @@ -120,35 +150,9 @@ def check( rule_validator = setup_validator(validation_config, exclude) try: - rule_collection = load_rules(input, file_pattern) rule_errors = Counter() cond_errors = Counter() - check_rules = list() - first_error = True - for rule in rule_collection.rules: - if ( - len(rule.errors) > 0 - ): # rule has errors: print errors and skip further checking of rule - if first_error: - click.echo("=== Sigma Rule Errors ===") - first_error = False - - for error in rule.errors: - click.echo(error) - rule_errors.update((error.__class__.__name__,)) - elif isinstance(rule, SigmaRule): # rule has no errors, parse condition - try: - for condition in rule.detection.parsed_condition: - condition.parse() - check_rules.append(rule) - except SigmaConditionError as e: # Error in condition - error = str(e) - click.echo( - f"Condition error in { str(condition.source) }:{ error }" - ) - cond_errors.update((error,)) - else: - check_rules.append(rule) + check_rules = load_and_check_rules(input, file_pattern, rule_errors, cond_errors) # TODO: From Python 3.10 the commented line below can be used. rule_error_count = sum(rule_errors.values())