From 21527b209ac234d1e78777d31e4e9e261f5db312 Mon Sep 17 00:00:00 2001 From: Mika Ayenson Date: Thu, 20 Aug 2026 12:42:42 -0500 Subject: [PATCH 1/2] fix(tests): allow same-day rule tunings without updated_date bump When a modified rule already has metadata.updated_date set to today (UTC), skip requiring a new updated_date hunk in the git diff. Stale dates still fail. Reads updated_date via pytoml. --- tests/test_all_rules.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py index 44e7400ba10..7e2062c9d74 100644 --- a/tests/test_all_rules.py +++ b/tests/test_all_rules.py @@ -10,11 +10,13 @@ import unittest import uuid from collections import defaultdict +from datetime import UTC, date, datetime from pathlib import Path from typing import ClassVar import eql import kql +import pytoml from marshmallow import ValidationError from semver import Version @@ -928,7 +930,7 @@ def test_deprecated_rules_modified(self): @unittest.skipIf(os.getenv("GITHUB_EVENT_NAME") == "push", "Skipping this test when not running on pull requests.") def test_rule_change_has_updated_date(self): - """Test to ensure modified rules have updated_date field updated.""" + """Fail when a modified rule lacks an updated_date bump and is not same-day UTC.""" rules_path = get_path(["rules"]) rules_bbr_path = get_path(["rules_building_block"]) @@ -947,11 +949,38 @@ def test_rule_change_has_updated_date(self): if result: modified_rules = [path for path in result.splitlines() if path.endswith(".toml")] failed_rules = [] + today_utc = datetime.now(UTC).date() for modified_rule_path in modified_rules: diff_output = detection_rules_git("diff", "origin/main", modified_rule_path) - if not re.search(r"\+\s*updated_date =", diff_output): - # Rule has been modified but updated_date has not been changed, add to list of failed rules + if re.search(r"^\+\s*updated_date\s*=", diff_output, re.MULTILINE): + # updated_date has been modified in this PR + continue + + rule_path = get_path([modified_rule_path]) + metadata = pytoml.loads(rule_path.read_text(encoding="utf-8")).get("metadata") or {} + if "updated_date" not in metadata: + # Explicit updated_date was not found -> do not require a bump + continue + + updated_date = metadata["updated_date"] + if isinstance(updated_date, datetime): + if updated_date.tzinfo is None: + updated_date = updated_date.replace(tzinfo=UTC) + updated_date = updated_date.astimezone(UTC).date() + elif isinstance(updated_date, date): + pass + elif isinstance(updated_date, str): + updated_date = date.fromisoformat(updated_date.replace("/", "-").split("T")[0]) + else: failed_rules.append(f"{modified_rule_path}") + continue + + # Same-day follow-up tunings may leave updated_date unchanged. + # Compare in UTC so evening local edits still match CI runners. + if updated_date == today_utc: + continue + + failed_rules.append(f"{modified_rule_path}") if failed_rules: fail_msg = """ From ce8cce155f493415a58dd9251e427df3ae508320 Mon Sep 17 00:00:00 2001 From: Mika Ayenson Date: Thu, 20 Aug 2026 15:47:26 -0500 Subject: [PATCH 2/2] chore: bump detection_rules to 2.1.7 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3ab8d50b985..8a41b2bab86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "detection_rules" -version = "2.1.6" +version = "2.1.7" description = "Detection Rules is the home for rules used by Elastic Security. This repository is used for the development, maintenance, testing, validation, and release of rules for Elastic Security’s Detection Engine." readme = "README.md" requires-python = ">=3.12"