Skip to content

Commit

Permalink
Add condition errors to check failure
Browse files Browse the repository at this point in the history
  • Loading branch information
frack113 committed Nov 10, 2023
1 parent 34ec3cc commit 2811c73
Showing 1 changed file with 71 additions and 27 deletions.
98 changes: 71 additions & 27 deletions sigma/cli/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,31 @@
plugins = InstalledSigmaPlugins.autodiscover()
validators = plugins.validators


@click.command()
@click.option(
"--validation-config", "-c",
"--validation-config",
"-c",
type=click.File("r"),
help="Validation configuration file in YAML format.",
)
@click.option(
"--file-pattern", "-P",
"--file-pattern",
"-P",
default="*.yml",
show_default=True,
help="Pattern for file names to be included in recursion into directories.",
)
@click.option(
"--fail-on-error/--pass-on-error", "-e/-E",
"--fail-on-error/--pass-on-error",
"-e/-E",
default=True,
show_default=True,
help="Fail on Sigma rule parsing errors.",
)
@click.option(
"--fail-on-issues/--pass-on-issues", "-i/-I",
"--fail-on-issues/--pass-on-issues",
"-i/-I",
default=False,
show_default=True,
help="Fail on Sigma rule validation issues.",
Expand All @@ -43,9 +48,17 @@
required=True,
type=click.Path(exists=True, allow_dash=True, path_type=pathlib.Path),
)
def check(input, validation_config, file_pattern, fail_on_error, fail_on_issues):
def check(
input,
validation_config,
file_pattern,
fail_on_error,
fail_on_issues,
):
"""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
if (
validation_config is None
): # no validation config provided, use basic config with all validators
rule_validator = SigmaValidator(validators.values())
else:
rule_validator = SigmaValidator.from_yaml(validation_config.read(), validators)
Expand All @@ -57,29 +70,35 @@ def check(input, validation_config, file_pattern, fail_on_error, fail_on_issues)
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 (
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__,))
else: # rule has no errors, parse condition
else: # 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
except SigmaConditionError as e: # Error in condition
error = str(e)
click.echo(f"Condition error in { str(condition.source) }:{ error }")
click.echo(
f"Condition error in { str(condition.source) }:{ error }"
)
cond_errors.update((error,))

# TODO: From Python 3.10 the commented line below can be used.
rule_error_count = sum(rule_errors.values())
#rule_error_count = rule_errors.total()
# rule_error_count = rule_errors.total()

with click.progressbar(check_rules, label="Checking Sigma rules", file=stderr) as rules:
with click.progressbar(
check_rules, label="Checking Sigma rules", file=stderr
) as rules:
issues = rule_validator.validate_rules(rules)

issue_count = len(issues)
Expand All @@ -92,21 +111,27 @@ def check(input, validation_config, file_pattern, fail_on_error, fail_on_issues)

# TODO: From Python 3.10 the commented line below can be used.
cond_error_count = sum(cond_errors.values())
#cond_error_count = cond_errors.total()
# cond_error_count = cond_errors.total()
click.echo()
click.echo("=== Summary ===")
click.echo(f"Found {rule_error_count} errors, { cond_error_count } condition errors and { issue_count } issues.")
click.echo(
f"Found {rule_error_count} errors, { cond_error_count } condition errors and { issue_count } issues."
)

if rule_error_count > 0:
click.echo("\nRule error summary:")
rule_error_table = PrettyTable(
field_names=("Count", "Rule Error"),
align="l",
)
rule_error_table.add_rows([
(count, fill(error, width=60))
for error, count in sorted(rule_errors.items(), key=lambda item: item[1], reverse=True)
])
rule_error_table.add_rows(
[
(count, fill(error, width=60))
for error, count in sorted(
rule_errors.items(), key=lambda item: item[1], reverse=True
)
]
)
click.echo(rule_error_table.get_string())
else:
click.echo("No rule errors found.")
Expand All @@ -117,10 +142,14 @@ def check(input, validation_config, file_pattern, fail_on_error, fail_on_issues)
field_names=("Count", "Condition Error"),
align="l",
)
cond_error_table.add_rows([
(count, fill(error, width=60))
for error, count in sorted(cond_errors.items(), key=lambda item: item[1], reverse=True)
])
cond_error_table.add_rows(
[
(count, fill(error, width=60))
for error, count in sorted(
cond_errors.items(), key=lambda item: item[1], reverse=True
)
]
)
click.echo(cond_error_table.get_string())
else:
click.echo("No condition errors found.")
Expand All @@ -131,15 +160,30 @@ def check(input, validation_config, file_pattern, fail_on_error, fail_on_issues)
field_names=("Count", "Issue", "Severity", "Description"),
align="l",
)
validation_issue_summary.add_rows([
(count, issue.__name__, issue.severity.name, fill(issue.description, width=60))
for issue, count in sorted(issue_counter.items(), key=lambda item: item[1], reverse=True)
])
validation_issue_summary.add_rows(
[
(
count,
issue.__name__,
issue.severity.name,
fill(issue.description, width=60),
)
for issue, count in sorted(
issue_counter.items(), key=lambda item: item[1], reverse=True
)
]
)
click.echo(validation_issue_summary.get_string())
else:
click.echo("No validation issues found.")

if fail_on_error and rule_error_count > 0 or fail_on_issues and issue_count > 0:
if (
fail_on_error
and (rule_error_count > 0 or cond_error_count > 0)
or fail_on_issues
and issue_count > 0
):
click.echo("Check failure")
click.get_current_context().exit(1)
except SigmaError as e:
click.echo("Check error: " + str(e), err=True)

0 comments on commit 2811c73

Please sign in to comment.