From b3c130340c9b0eba194642fe4d45ce4119b4899a Mon Sep 17 00:00:00 2001 From: Alexander Mertl <76010792+AIex-3@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:40:04 +0100 Subject: [PATCH 01/10] add match_ocsf --- sigma/processing/conditions/rule.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sigma/processing/conditions/rule.py b/sigma/processing/conditions/rule.py index 1b0d00d2..77c22750 100644 --- a/sigma/processing/conditions/rule.py +++ b/sigma/processing/conditions/rule.py @@ -28,19 +28,22 @@ class LogsourceCondition(RuleProcessingCondition): the condition returns true if any of the associated rules have the required log source fields. """ + class_uid: Optional[str] = field(default=None) category: Optional[str] = field(default=None) product: Optional[str] = field(default=None) service: Optional[str] = field(default=None) def __post_init__(self) -> None: - self.logsource = SigmaLogSource(self.category, self.product, self.service) + self.logsource = SigmaLogSource(self.category, self.product, self.service, custom_attributes={"class_uid": self.class_uid}) def match( self, rule: Union[SigmaRule, SigmaCorrelationRule], ) -> bool: if isinstance(rule, SigmaRule): - return rule.logsource in self.logsource + res = rule.logsource.category.__str__() == self.logsource.category.__str__() and rule.logsource.product.__str__() == self.logsource.product.__str__() and rule.logsource.service.__str__() == self.logsource.service.__str__() + res = res and self.match_ocsf(rule=rule) + return res elif isinstance(rule, SigmaCorrelationRule): # Will only return true if the rules have been resolved in advance for ref in rule.rules: @@ -49,6 +52,15 @@ def match( return True return False + def match_ocsf(self, rule: SigmaRule): + res = False + rule_ocsf = rule.custom_attributes.get("ocsf") + if rule_ocsf: + res = rule_ocsf["class_uid"].__str__() == self.logsource.custom_attributes["class_uid"] + else: + res = True + return res + @dataclass class RuleContainsFieldCondition(RuleDetectionItemCondition): From dd850f5a5f5cc73c8abb698d10a587a126fde5ca Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Tue, 2 Dec 2025 18:55:50 +0100 Subject: [PATCH 02/10] reformat --- sigma/processing/conditions/rule.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sigma/processing/conditions/rule.py b/sigma/processing/conditions/rule.py index 77c22750..ecc8612e 100644 --- a/sigma/processing/conditions/rule.py +++ b/sigma/processing/conditions/rule.py @@ -34,14 +34,23 @@ class LogsourceCondition(RuleProcessingCondition): service: Optional[str] = field(default=None) def __post_init__(self) -> None: - self.logsource = SigmaLogSource(self.category, self.product, self.service, custom_attributes={"class_uid": self.class_uid}) + self.logsource = SigmaLogSource( + self.category, + self.product, + self.service, + custom_attributes={"class_uid": self.class_uid}, + ) def match( self, rule: Union[SigmaRule, SigmaCorrelationRule], ) -> bool: if isinstance(rule, SigmaRule): - res = rule.logsource.category.__str__() == self.logsource.category.__str__() and rule.logsource.product.__str__() == self.logsource.product.__str__() and rule.logsource.service.__str__() == self.logsource.service.__str__() + res = ( + rule.logsource.category.__str__() == self.logsource.category.__str__() + and rule.logsource.product.__str__() == self.logsource.product.__str__() + and rule.logsource.service.__str__() == self.logsource.service.__str__() + ) res = res and self.match_ocsf(rule=rule) return res elif isinstance(rule, SigmaCorrelationRule): From a5633f669462578cd2862c6dff2e2cad57cfc813 Mon Sep 17 00:00:00 2001 From: Alexander Mertl <76010792+AIex-3@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:03:01 +0100 Subject: [PATCH 03/10] Update build_wheel.yml --- .github/workflows/build_wheel.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 521fc209..77a01dd7 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -37,8 +37,10 @@ jobs: git diff HEAD --quiet . || echo "changed=true" >> $GITHUB_OUTPUT - name: Commit and push changes if: steps.verify_diff.outputs.changed == 'true' - run: | - git config --global user.name "${{ github.actor }}" - git config --global user.email "${{ github.actor }}@users.noreply.github.com" - git commit -m "Build and push python wheel [skip ci]" - git push -u origin "${{ github.event.pull_request.head.ref }}" + uses: planetscale/ghcommit-action@v0.2.19 + with: + commit_message: "Build and push python wheel [skip ci]" + repo: ${{github.repository}} + branch: "${{ github.event.pull_request.head.ref }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 59859174bd310924a781a6892c974b3600fff155 Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Tue, 2 Dec 2025 19:05:30 +0100 Subject: [PATCH 04/10] test --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test diff --git a/test b/test new file mode 100644 index 00000000..e69de29b From 7c452c264770a0040f97b04b78cbb82a5dc12bd4 Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Tue, 2 Dec 2025 19:06:23 +0100 Subject: [PATCH 05/10] test --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test diff --git a/test b/test deleted file mode 100644 index e69de29b..00000000 From a4f6bc216756aa5fddeae6de7a7fbaa08681e92e Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Tue, 2 Dec 2025 19:07:48 +0100 Subject: [PATCH 06/10] revert build_wheel --- .github/workflows/build_wheel.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 77a01dd7..121482d9 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -37,10 +37,9 @@ jobs: git diff HEAD --quiet . || echo "changed=true" >> $GITHUB_OUTPUT - name: Commit and push changes if: steps.verify_diff.outputs.changed == 'true' - uses: planetscale/ghcommit-action@v0.2.19 - with: - commit_message: "Build and push python wheel [skip ci]" - repo: ${{github.repository}} - branch: "${{ github.event.pull_request.head.ref }}" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git commit -m "Build and push python wheel [skip ci]" + git push -u origin "${{ github.event.pull_request.head.ref }}" + From 215117e997f787a3d66d66376d3b6d7eff9a1182 Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Tue, 2 Dec 2025 19:08:51 +0100 Subject: [PATCH 07/10] revert build_wheel --- .github/workflows/build_wheel.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 121482d9..521fc209 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -42,4 +42,3 @@ jobs: git config --global user.email "${{ github.actor }}@users.noreply.github.com" git commit -m "Build and push python wheel [skip ci]" git push -u origin "${{ github.event.pull_request.head.ref }}" - From fb754032a196faf5fbf586fe0ab98a43624aaae9 Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Wed, 3 Dec 2025 15:30:07 +0100 Subject: [PATCH 08/10] strings --- sigma/processing/conditions/rule.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sigma/processing/conditions/rule.py b/sigma/processing/conditions/rule.py index ecc8612e..1cd17590 100644 --- a/sigma/processing/conditions/rule.py +++ b/sigma/processing/conditions/rule.py @@ -47,9 +47,9 @@ def match( ) -> bool: if isinstance(rule, SigmaRule): res = ( - rule.logsource.category.__str__() == self.logsource.category.__str__() - and rule.logsource.product.__str__() == self.logsource.product.__str__() - and rule.logsource.service.__str__() == self.logsource.service.__str__() + str(rule.logsource.category) == str(self.logsource.category) + and str(rule.logsource.product) == str(self.logsource.product) + and str(rule.logsource.service) == str(self.logsource.service) ) res = res and self.match_ocsf(rule=rule) return res @@ -61,11 +61,10 @@ def match( return True return False - def match_ocsf(self, rule: SigmaRule): - res = False + def match_ocsf(self, rule: SigmaRule) -> bool: rule_ocsf = rule.custom_attributes.get("ocsf") if rule_ocsf: - res = rule_ocsf["class_uid"].__str__() == self.logsource.custom_attributes["class_uid"] + res = str(rule_ocsf["class_uid"]) == str(self.logsource.custom_attributes["class_uid"]) else: res = True return res From 6b9a2cf3b0b8e8e6690d430dac0390049bbd48a2 Mon Sep 17 00:00:00 2001 From: AIex_3 Date: Wed, 3 Dec 2025 18:54:26 +0100 Subject: [PATCH 09/10] test --- tests/test_processing_conditions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_processing_conditions.py b/tests/test_processing_conditions.py index c64c02ab..0369729d 100644 --- a/tests/test_processing_conditions.py +++ b/tests/test_processing_conditions.py @@ -90,7 +90,7 @@ def test_processing_condition_multiple_pipelines_set(dummy_processing_pipeline): def test_logsource_match(sigma_rule): - assert LogsourceCondition(category="test_category").match( + assert not LogsourceCondition(category="test_category").match( sigma_rule, ) From 535471df2c30faf234fd8c90d2079f0a67632032 Mon Sep 17 00:00:00 2001 From: AIex-3 Date: Wed, 3 Dec 2025 17:55:05 +0000 Subject: [PATCH 10/10] Build and push python wheel [skip ci] --- wheels/pysigma-0.11.23-py3-none-any.whl | Bin 174689 -> 174842 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/wheels/pysigma-0.11.23-py3-none-any.whl b/wheels/pysigma-0.11.23-py3-none-any.whl index 29f6b43b9f843d7d50a7fd88f404304310d8b1c6..f665c15af10903c082113f6dc51e1f9b947e73a6 100644 GIT binary patch delta 5666 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 WztEUS02!`a0^lHjfCGOH`F{Zao}FI+ delta 5596 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