From fbcf1c7c64ede7bb26b1afc06479239f0e169d04 Mon Sep 17 00:00:00 2001 From: brokensound77 Date: Wed, 24 Aug 2022 12:45:53 -0600 Subject: [PATCH 1/3] add test that newly introduced build-time fields for a min_stack for applicable rules. --- detection_rules/rule.py | 12 ++++++++++++ tests/test_all_rules.py | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/detection_rules/rule.py b/detection_rules/rule.py index 0d1d844d8fb..307b7edbb42 100644 --- a/detection_rules/rule.py +++ b/detection_rules/rule.py @@ -38,6 +38,7 @@ MIN_FLEET_PACKAGE_VERSION = '7.13.0' BUILD_FIELD_VERSIONS = { + "related_integrations": (Version('8.3'), None), "required_fields": (Version('8.3'), None), "setup": (Version("8.3"), None) } @@ -250,6 +251,17 @@ def parsed_note(self) -> Optional[MarkoDocument]: def is_elastic_rule(self): return 'elastic' in [a.lower() for a in self.author] + def get_build_fields(self) -> {}: + """Get a list of build-time fields along with the stack versions which they will build within.""" + build_fields = {} + rule_fields = {f.name: f for f in dataclasses.fields(self)} + + for fld in BUILD_FIELD_VERSIONS: + if fld in rule_fields: + build_fields[fld] = BUILD_FIELD_VERSIONS[fld] + + return build_fields + class DataValidator: """Additional validation beyond base marshmallow schema validation.""" diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py index a7aad48f215..0342deef458 100644 --- a/tests/test_all_rules.py +++ b/tests/test_all_rules.py @@ -696,3 +696,29 @@ def test_rule_backports_for_restricted_fields(self): err_msg = 'The following rules have min_stack_versions lower than allowed for restricted fields:\n' err_msg += invalid_str self.fail(err_msg) + + +class TestBuildTimeFields(BaseRuleTest): + """Test validity of build-time fields.""" + + def test_build_fields_min_stack(self): + """Test that newly introduced build-time fields for a min_stack for applicable rules.""" + invalids = [] + + for rule in self.production_rules: + min_stack = rule.contents.metadata.min_stack_version + build_fields = rule.contents.data.get_build_fields() + + errors = [] + for build_field, field_versions in build_fields.items(): + start_ver, end_ver = field_versions + if start_ver is not None and not Version(min_stack) >= start_ver: + errors.append(f'{build_field} >= {start_ver}') + + if errors: + err_str = ', '.join(errors) + invalids.append(f'{self.rule_str(rule)} uses a rule type with build fields requiring min_stack_versions' + f'to be set: {err_str}') + + if invalids: + self.fail(invalids) From 01a3b71573e76f08eb98c861c8da5baf17f31add Mon Sep 17 00:00:00 2001 From: brokensound77 Date: Thu, 25 Aug 2022 11:07:15 -0600 Subject: [PATCH 2/3] account for rules without min_stack_version --- tests/test_all_rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py index 0342deef458..eff8c8983c4 100644 --- a/tests/test_all_rules.py +++ b/tests/test_all_rules.py @@ -712,13 +712,13 @@ def test_build_fields_min_stack(self): errors = [] for build_field, field_versions in build_fields.items(): start_ver, end_ver = field_versions - if start_ver is not None and not Version(min_stack) >= start_ver: + if start_ver is not None and min_stack is None or not Version(min_stack) >= start_ver: errors.append(f'{build_field} >= {start_ver}') if errors: err_str = ', '.join(errors) invalids.append(f'{self.rule_str(rule)} uses a rule type with build fields requiring min_stack_versions' - f'to be set: {err_str}') + f' to be set: {err_str}') if invalids: self.fail(invalids) From b2bec63f38febd2788c07086428770e44e73f2d2 Mon Sep 17 00:00:00 2001 From: brokensound77 Date: Thu, 25 Aug 2022 21:04:28 -0600 Subject: [PATCH 3/3] limit test to >= stack ver --- tests/test_all_rules.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py index eff8c8983c4..29f57a07b23 100644 --- a/tests/test_all_rules.py +++ b/tests/test_all_rules.py @@ -14,6 +14,7 @@ from detection_rules import attack from detection_rules.beats import parse_beats_from_index +from detection_rules.packaging import current_stack_version from detection_rules.rule import QueryRuleData from detection_rules.rule_loader import FILE_PATTERN from detection_rules.schemas import definitions @@ -382,8 +383,6 @@ def test_updated_date_newer_than_creation(self): def test_deprecated_rules(self): """Test that deprecated rules are properly handled.""" - from detection_rules.packaging import current_stack_version - versions = default_version_lock.version_lock deprecations = load_etc_dump('deprecated_rules.json') deprecated_rules = {} @@ -703,6 +702,7 @@ class TestBuildTimeFields(BaseRuleTest): def test_build_fields_min_stack(self): """Test that newly introduced build-time fields for a min_stack for applicable rules.""" + current_stack_ver = Version(current_stack_version()) invalids = [] for rule in self.production_rules: @@ -712,8 +712,9 @@ def test_build_fields_min_stack(self): errors = [] for build_field, field_versions in build_fields.items(): start_ver, end_ver = field_versions - if start_ver is not None and min_stack is None or not Version(min_stack) >= start_ver: - errors.append(f'{build_field} >= {start_ver}') + if start_ver is not None and current_stack_ver >= start_ver: + if min_stack is None or not Version(min_stack) >= start_ver: + errors.append(f'{build_field} >= {start_ver}') if errors: err_str = ', '.join(errors)