Skip to content

Commit

Permalink
Merge pull request #159 from frack113/related_validator
Browse files Browse the repository at this point in the history
Chore: add new validator
  • Loading branch information
thomaspatzke authored Nov 5, 2023
2 parents 5938f0c + c6bd038 commit a973b97
Show file tree
Hide file tree
Showing 3 changed files with 372 additions and 161 deletions.
75 changes: 75 additions & 0 deletions sigma/validators/core/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
)


def is_uuid_v4(val: str) -> bool:
try:
id = UUID(str(val))
if id.version == 4:
return True
else:
return False
except ValueError:
return False


@dataclass
class IdentifierExistenceIssue(SigmaValidationIssue):
description = "Rule has no identifier (UUID)"
Expand Down Expand Up @@ -114,3 +125,67 @@ def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
for reference, count in references.items()
if count > 1
]


@dataclass
class InvalidRelatedTypeIssue(SigmaValidationIssue):
description: ClassVar[str] = "Invalid related type"
severity: ClassVar[SigmaValidationIssueSeverity] = SigmaValidationIssueSeverity.MEDIUM
type: str


class InvalidRelatedTypeValidator(SigmaRuleValidator):
"""Validate rule related type."""

def __init__(self) -> None:
self.allowed_type = {"derived", "obsoletes", "merged", "renamed", "similar"}

def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
if rule.custom_attributes["related"]:
return [
InvalidRelatedTypeIssue([rule], value["type"])
for value in rule.custom_attributes["related"]
if value["type"] not in self.allowed_type
]
return []


@dataclass
class InvalidRelatedIdIssue(SigmaValidationIssue):
description: ClassVar[str] = "Invalid related id format"
severity: ClassVar[SigmaValidationIssueSeverity] = SigmaValidationIssueSeverity.MEDIUM
id: str


class InvalidRelatedIdValidator(SigmaRuleValidator):
"""Validate rule related id format."""

def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
if rule.custom_attributes["related"]:
return [
InvalidRelatedIdIssue([rule], value["id"])
for value in rule.custom_attributes["related"]
if not is_uuid_v4(value["id"])
]
return []


@dataclass
class InvalidRelatedSubfieldIssue(SigmaValidationIssue):
description: ClassVar[str] = "Invalid related Subfield name"
severity: ClassVar[SigmaValidationIssueSeverity] = SigmaValidationIssueSeverity.MEDIUM
subfield: str


class InvalidRelatedSubfieldValidator(SigmaRuleValidator):
"""Validate rule related subfield name."""

def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
if rule.custom_attributes["related"]:
return [
InvalidRelatedSubfieldIssue([rule], value_key)
for value in rule.custom_attributes["related"]
for value_key in value.keys()
if value_key not in ["id", "type"]
]
return []
162 changes: 1 addition & 161 deletions tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,7 @@
SpecificInsteadOfGenericLogsourceValidator,
SpecificInsteadOfGenericLogsourceIssue,
)
from sigma.validators.core.metadata import (
IdentifierCollisionIssue,
IdentifierExistenceIssue,
IdentifierExistenceValidator,
IdentifierUniquenessValidator,
TitleLengthIssue,
TitleLengthValidator,
DuplicateTitleIssue,
DuplicateTitleValidator,
DuplicateReferencesIssue,
DuplicateReferencesValidator,
)

from sigma.validators.core.condition import (
AllOfThemConditionIssue,
AllOfThemConditionValidator,
Expand Down Expand Up @@ -125,30 +114,6 @@ def rules_with_id_collision():
]


def test_validator_identifier_existence(rule_without_id):
validator = IdentifierExistenceValidator()
assert (
validator.validate(rule_without_id) == [IdentifierExistenceIssue([rule_without_id])]
and validator.finalize() == []
)


def test_validator_identifier_existence_valid(rule_with_id):
validator = IdentifierExistenceValidator()
assert validator.validate(rule_with_id) == [] and validator.finalize() == []


def test_validator_identifier_uniqueness(rules_with_id_collision):
validator = IdentifierUniquenessValidator()
assert [
issue for rule in rules_with_id_collision for issue in validator.validate(rule)
] == [] and validator.finalize() == [
IdentifierCollisionIssue(
rules_with_id_collision, UUID("32532a0b-e56c-47c9-bcbb-3d88bd670c37")
)
]


def test_validator_dangling_detection():
validator = DanglingDetectionValidator()
rule = SigmaRule.from_yaml(
Expand Down Expand Up @@ -874,128 +839,3 @@ def test_validator_escaped_wildcard_valid():
"""
)
assert validator.validate(rule) == []


def test_validator_lengthy_title():
validator = TitleLengthValidator()
rule = SigmaRule.from_yaml(
"""
title: ThisIsAVeryLongTitleThisIsAVeryLongTitleThisIsAVeryLongTitleThisIsAVeryLongTitleThisIsAVeryLongTitleT
status: test
logsource:
category: test
detection:
sel:
field: path\\*something
condition: sel
"""
)
assert validator.validate(rule) == [TitleLengthIssue([rule])]


def test_validator_lengthy_title_valid():
validator = TitleLengthValidator()
rule = SigmaRule.from_yaml(
"""
title: Test
status: test
logsource:
category: test
detection:
sel:
field: path\\*something
condition: sel
"""
)
assert validator.validate(rule) == []


def test_validator_duplicate_title():
validator = DuplicateTitleValidator()
rule1 = SigmaRule.from_yaml(
"""
title: Test
status: test
logsource:
category: test
detection:
sel:
field: value
condition: sel
"""
)

rule2 = SigmaRule.from_yaml(
"""
title: Test
status: test
logsource:
category: test
detection:
sel:
field: value
condition: sel
"""
)
assert validator.validate(rule1) == []
assert validator.validate(rule2) == []
assert validator.finalize() == [DuplicateTitleIssue([rule1, rule2], "Test")]


def test_validator_duplicate_title_valid():
validator = DuplicateTitleValidator()
rule = SigmaRule.from_yaml(
"""
title: Test
status: test
logsource:
category: test
detection:
sel:
field: value
condition: sel
"""
)
assert validator.validate(rule) == []


def test_validator_duplicate_references():
validator = DuplicateReferencesValidator()
rule = SigmaRule.from_yaml(
"""
title: Test
references:
- ref_a
- ref_b
- ref_a
status: test
logsource:
category: test
detection:
sel:
field: value
condition: sel
"""
)
assert validator.validate(rule) == [DuplicateReferencesIssue([rule], "ref_a")]


def test_validator_duplicate_references_valid():
validator = DuplicateReferencesValidator()
rule = SigmaRule.from_yaml(
"""
title: Test
references:
- ref_a
- ref_b
- ref_c
status: test
logsource:
category: test
detection:
sel:
field: value
condition: sel
"""
)
assert validator.validate(rule) == []
Loading

0 comments on commit a973b97

Please sign in to comment.