pySigma 2.0.0__tar.gz → 2.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {pysigma-2.0.0 → pysigma-2.0.1}/PKG-INFO +1 -1
  2. {pysigma-2.0.0 → pysigma-2.0.1}/pyproject.toml +1 -1
  3. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/collection.py +1 -0
  4. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/conditions.py +2 -2
  5. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/conversion/base.py +4 -2
  6. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/filters.py +5 -2
  7. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/modifiers.py +18 -5
  8. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/policy/__init__.py +5 -0
  9. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/finalization.py +1 -1
  10. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/pipeline.py +10 -5
  11. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/regex.py +2 -2
  12. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/external.py +2 -0
  13. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/rule/detection.py +11 -7
  14. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/types.py +17 -9
  15. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validation.py +3 -0
  16. pysigma-2.0.0/sigma/__init__.py +0 -6
  17. {pysigma-2.0.0 → pysigma-2.0.1}/LICENSE +0 -0
  18. {pysigma-2.0.0 → pysigma-2.0.1}/README.md +0 -0
  19. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/backends/test/__init__.py +0 -0
  20. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/backends/test/backend.py +0 -0
  21. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/conversion/__init__.py +0 -0
  22. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/conversion/deferred.py +0 -0
  23. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/conversion/state.py +0 -0
  24. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/correlations.py +0 -0
  25. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/data/mitre_attack.py +0 -0
  26. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/data/mitre_d3fend.py +0 -0
  27. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/exceptions.py +0 -0
  28. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/pipelines/base.py +0 -0
  29. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/pipelines/common.py +0 -0
  30. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/pipelines/test/__init__.py +0 -0
  31. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/pipelines/test/pipeline.py +0 -0
  32. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/plugins.py +0 -0
  33. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/policy/profiles.py +0 -0
  34. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/policy/regex_engine.py +0 -0
  35. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/__init__.py +0 -0
  36. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/condition_expressions.py +0 -0
  37. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/conditions/__init__.py +0 -0
  38. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/conditions/base.py +0 -0
  39. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/conditions/fields.py +0 -0
  40. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/conditions/rule.py +0 -0
  41. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/conditions/state.py +0 -0
  42. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/conditions/values.py +0 -0
  43. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/postprocessing.py +0 -0
  44. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/resolver.py +0 -0
  45. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/templates.py +0 -0
  46. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/tracking.py +0 -0
  47. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/__init__.py +0 -0
  48. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/base.py +0 -0
  49. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/condition.py +0 -0
  50. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/detection_item.py +0 -0
  51. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/failure.py +0 -0
  52. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/fields.py +0 -0
  53. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/meta.py +0 -0
  54. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/placeholder.py +0 -0
  55. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/rule.py +0 -0
  56. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/state.py +0 -0
  57. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/processing/transformations/values.py +0 -0
  58. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/py.typed +0 -0
  59. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/rule/__init__.py +0 -0
  60. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/rule/attributes.py +0 -0
  61. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/rule/base.py +0 -0
  62. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/rule/logsource.py +0 -0
  63. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/rule/rule.py +0 -0
  64. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/base.py +0 -0
  65. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/__init__.py +0 -0
  66. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/condition.py +0 -0
  67. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/logsources.py +0 -0
  68. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/metadata.py +0 -0
  69. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/modifiers.py +0 -0
  70. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/tags.py +0 -0
  71. {pysigma-2.0.0 → pysigma-2.0.1}/sigma/validators/core/values.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pySigma
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Sigma rule processing and conversion tools
5
5
  License-Expression: LGPL-2.1-only
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pySigma"
3
- version = "2.0.0"
3
+ version = "2.0.1"
4
4
  license = "LGPL-2.1-only"
5
5
  description = "Sigma rule processing and conversion tools"
6
6
  authors = [
@@ -205,6 +205,7 @@ class SigmaCollection:
205
205
  rule,
206
206
  collect_errors,
207
207
  source,
208
+ policy=policy,
208
209
  )
209
210
  parsed_rules.append(parsed_filter_rule)
210
211
  errors.extend(parsed_filter_rule.errors) # Propagate errors from rule
@@ -248,10 +248,10 @@ class ConditionSelector(ConditionItem):
248
248
  """
249
249
  Resolve all detection identifiers referenced by the selector.
250
250
  """
251
- import sigma
251
+ from sigma.policy import default_policy
252
252
 
253
253
  policy = detections.policy
254
- engine = (policy or sigma.default_policy).regex_engine
254
+ engine = (policy or default_policy).regex_engine
255
255
  if self.pattern == "them":
256
256
  r = engine.compile(".*")
257
257
  else:
@@ -767,8 +767,10 @@ class Backend(ABC):
767
767
  ]
768
768
  rule.set_conversion_result(finalized_queries)
769
769
  rule.set_conversion_states(states)
770
-
771
- return finalized_queries
770
+ if rule._output:
771
+ return finalized_queries
772
+ else:
773
+ return []
772
774
 
773
775
  @abstractmethod
774
776
  def convert_correlation_event_count_rule(
@@ -71,7 +71,7 @@ class SigmaGlobalFilter(SigmaDetections):
71
71
 
72
72
  return cls(
73
73
  detections={
74
- name: SigmaDetection.from_definition(definition, source)
74
+ name: SigmaDetection.from_definition(definition, source, policy)
75
75
  for name, definition in detections.items()
76
76
  if name
77
77
  not in (
@@ -82,6 +82,7 @@ class SigmaGlobalFilter(SigmaDetections):
82
82
  rules=rules,
83
83
  condition=condition,
84
84
  source=source,
85
+ policy=policy,
85
86
  )
86
87
 
87
88
  def to_dict(self: Self) -> dict[str, Any]:
@@ -163,7 +164,9 @@ class SigmaFilter(SigmaRuleBase):
163
164
 
164
165
  # parse detections
165
166
  try:
166
- filter_global_filter = SigmaGlobalFilter.from_dict(sigma_filter["filter"], source)
167
+ filter_global_filter = SigmaGlobalFilter.from_dict(
168
+ sigma_filter["filter"], source, policy=policy
169
+ )
167
170
  except KeyError:
168
171
  filter_global_filter = EmptySigmaGlobalFilter()
169
172
  errors.append(
@@ -40,7 +40,7 @@ from sigma.types import (
40
40
  TimestampPart,
41
41
  SigmaStringPartType,
42
42
  )
43
- from sigma.exceptions import SigmaRuleLocation, SigmaTypeError, SigmaValueError
43
+ from sigma.exceptions import SigmaModifiedError, SigmaRuleLocation, SigmaTypeError, SigmaValueError
44
44
 
45
45
  if TYPE_CHECKING:
46
46
  from .rule import SigmaDetectionItem
@@ -418,6 +418,7 @@ class SigmaWindowsDashModifier(SigmaValueModifier[SigmaString, SigmaExpansion]):
418
418
  en_dash = chr(int("2013", 16))
419
419
  em_dash = chr(int("2014", 16))
420
420
  horizontal_bar = chr(int("2015", 16))
421
+ max_expanded_dashes = 3
421
422
 
422
423
  def modify(self, val: SigmaString) -> SigmaExpansion:
423
424
  def callback(p: Placeholder) -> Iterator[str | Placeholder]:
@@ -426,12 +427,24 @@ class SigmaWindowsDashModifier(SigmaValueModifier[SigmaString, SigmaExpansion]):
426
427
  else:
427
428
  yield p
428
429
 
430
+ with_placeholders = val.replace_with_placeholder(re.compile("\\B[-/]\\b"), "_windash")
431
+ expanded_dashes = sum(
432
+ 1
433
+ for part in with_placeholders.s
434
+ if isinstance(part, Placeholder) and part.name == "_windash"
435
+ )
436
+ if expanded_dashes > self.max_expanded_dashes:
437
+ raise SigmaModifiedError(
438
+ "windash modifier expands at most three dash occurrences in one value; "
439
+ "split multiple dash expansions into separate ORed string match conditions "
440
+ "with one dash expanded",
441
+ source=self.source,
442
+ )
443
+
429
444
  return SigmaExpansion(
430
445
  cast(
431
446
  list[SigmaType],
432
- val.replace_with_placeholder(
433
- re.compile("\\B[-/]\\b"), "_windash"
434
- ).replace_placeholders(callback),
447
+ with_placeholders.replace_placeholders(callback),
435
448
  )
436
449
  )
437
450
 
@@ -445,7 +458,7 @@ class SigmaRegularExpressionModifier(SigmaValueModifier[SigmaString, SigmaRegula
445
458
  "Regular expression modifier only applicable to unmodified values",
446
459
  source=self.source,
447
460
  )
448
- return SigmaRegularExpression(val.original)
461
+ return SigmaRegularExpression(val.original, policy=self.detection_item.policy)
449
462
 
450
463
 
451
464
  class SigmaRegularExpressionFlagModifier(
@@ -18,3 +18,8 @@ class SigmaPolicy:
18
18
  allow_template_vars: bool = False
19
19
  vars_allowed_paths: tuple[str, ...] | None = None
20
20
  allow_external_sources: bool = False
21
+
22
+
23
+ from sigma.policy.profiles import SafePolicy # noqa: E402
24
+
25
+ default_policy: SigmaPolicy = SafePolicy
@@ -132,7 +132,7 @@ class NestedFinalizer(Finalizer):
132
132
  finalizer_cls = finalizers[finalizer_type]
133
133
  import sigma as _sigma
134
134
 
135
- effective_policy = policy or _sigma.default_policy
135
+ effective_policy = policy or _sigma.policy.default_policy
136
136
  if issubclass(finalizer_cls, TemplateBase):
137
137
  finalizer["policy"] = policy
138
138
  finalizer["restrict_template_path"] = not effective_policy.allow_external_sources
@@ -27,6 +27,7 @@ from sigma.processing.tracking import FieldMappingTracking
27
27
  from sigma.processing.transformations import transformations
28
28
  from sigma.processing.transformations.external import ExternalSourceBaseTransformation
29
29
  from sigma.rule import SigmaDetectionItem, SigmaRule
30
+ from sigma.rule.base import check_alias_expansion
30
31
  from sigma.correlations import SigmaCorrelationRule
31
32
  from sigma.processing.transformations.base import PreprocessingTransformation, Transformation
32
33
  from sigma.processing.postprocessing import (
@@ -353,7 +354,7 @@ class ProcessingItemBase:
353
354
  }
354
355
  import sigma as _sigma
355
356
 
356
- effective_policy = policy or _sigma.default_policy
357
+ effective_policy = policy or _sigma.policy.default_policy
357
358
  if issubclass(transformation_class, TemplateBase):
358
359
  params["policy"] = policy
359
360
  params["restrict_template_path"] = not effective_policy.allow_external_sources
@@ -810,9 +811,9 @@ class ProcessingPipeline:
810
811
  Prefer the policy attached to this pipeline and fall back to the
811
812
  global default policy only if no pipeline policy is set.
812
813
  """
813
- import sigma
814
+ from sigma.policy import default_policy
814
815
 
815
- return self.policy or sigma.default_policy
816
+ return self.policy or default_policy
816
817
 
817
818
  def resolve_regex_engine(self) -> "RegexEngine":
818
819
  """Return the effective regex engine for this pipeline."""
@@ -826,6 +827,10 @@ class ProcessingPipeline:
826
827
  ) -> "ProcessingPipeline":
827
828
  """Instantiate processing pipeline from a parsed processing item description."""
828
829
 
830
+ # Validate aliases once at the pipeline root so nested from_dict calls don't
831
+ # repeatedly traverse already checked substructures.
832
+ check_alias_expansion(d, SigmaConfigurationError)
833
+
829
834
  custom_keys = [
830
835
  k
831
836
  for k in d.keys()
@@ -845,7 +850,7 @@ class ProcessingPipeline:
845
850
 
846
851
  import sigma as _sigma
847
852
 
848
- effective_policy = policy or _sigma.default_policy
853
+ effective_policy = policy or _sigma.policy.default_policy
849
854
 
850
855
  vars = d.get("vars", dict()) # default: no variables
851
856
 
@@ -938,7 +943,7 @@ class ProcessingPipeline:
938
943
  import dataclasses
939
944
  import sigma as _sigma
940
945
 
941
- effective_policy = policy or _sigma.default_policy
946
+ effective_policy = policy or _sigma.policy.default_policy
942
947
  if effective_policy.vars_allowed_paths is None and source_path is not None:
943
948
  policy = dataclasses.replace(
944
949
  effective_policy,
@@ -24,14 +24,14 @@ class ProcessingRegularExpressionMixin:
24
24
 
25
25
  def resolve_regex_engine(self) -> RegexEngine:
26
26
  """Return the effective regex engine for this processing context."""
27
- import sigma
27
+ from sigma.policy import default_policy
28
28
 
29
29
  _pipeline = getattr(self, "_pipeline", None)
30
30
  if _pipeline is None:
31
31
  _policy = getattr(self, "policy", None)
32
32
  if _policy is not None:
33
33
  return _policy.regex_engine # type: ignore[no-any-return]
34
- return sigma.default_policy.regex_engine
34
+ return default_policy.regex_engine
35
35
  return _pipeline.resolve_regex_engine() # type: ignore[no-any-return]
36
36
 
37
37
  def compile_regex(self, pattern: str) -> RegexPattern:
@@ -27,6 +27,7 @@ import yaml
27
27
  from sigma.exceptions import SigmaConfigurationError, SigmaSecurityError, SigmaValueError
28
28
  from sigma.policy.regex_engine import RegexPattern
29
29
  from sigma.processing.transformations.placeholder import BasePlaceholderTransformation
30
+ from sigma.rule.base import check_alias_expansion
30
31
  from sigma.types import Placeholder, SigmaString
31
32
  from typing import TYPE_CHECKING
32
33
 
@@ -207,6 +208,7 @@ class ExternalSourceBaseTransformation(BasePlaceholderTransformation):
207
208
  parsed = yaml.safe_load(data)
208
209
  except yaml.YAMLError as e:
209
210
  raise SigmaValueError(f"Failed to parse YAML data: {e}") from e
211
+ check_alias_expansion(parsed, SigmaValueError)
210
212
  try:
211
213
  result = jq.all(self.jq_expression, parsed)
212
214
  except ValueError as e:
@@ -76,6 +76,7 @@ class SigmaDetectionItem(ProcessingItemTrackingMixin, ParentChainMixin):
76
76
  init=False, repr=False, hash=False, compare=False
77
77
  ) # Copy of original values for conversion back to data structures (and YAML/JSON)
78
78
  auto_modifiers: bool = dataclasses.field(default=True, compare=False, repr=False)
79
+ policy: "SigmaPolicy | None" = dataclasses.field(default=None, compare=False, repr=False)
79
80
 
80
81
  def __post_init__(self: Self) -> None:
81
82
  if not isinstance(self.value, list) or not all(
@@ -116,6 +117,7 @@ class SigmaDetectionItem(ProcessingItemTrackingMixin, ParentChainMixin):
116
117
  key: str | None,
117
118
  val: list[float | str | bool | None] | float | str | bool | None,
118
119
  source: SigmaRuleLocation | None = None,
120
+ policy: "SigmaPolicy | None" = None,
119
121
  ) -> Self:
120
122
  """
121
123
  Constructs SigmaDetectionItem object from a mapping between field name containing
@@ -155,16 +157,17 @@ class SigmaDetectionItem(ProcessingItemTrackingMixin, ParentChainMixin):
155
157
  for v in val_list
156
158
  ]
157
159
 
158
- return cls(field, modifiers, sigma_val, source=source)
160
+ return cls(field, modifiers, sigma_val, source=source, policy=policy)
159
161
 
160
162
  @classmethod
161
163
  def from_value(
162
164
  cls: type[Self],
163
165
  val: list[float | str | bool | None] | float | str | bool | None,
164
166
  source: SigmaRuleLocation | None = None,
167
+ policy: "SigmaPolicy | None" = None,
165
168
  ) -> Self:
166
169
  """Convenience method for from_mapping(None, value)."""
167
- return cls.from_mapping(None, val, source=source)
170
+ return cls.from_mapping(None, val, source=source, policy=policy)
168
171
 
169
172
  def disable_conversion_to_plain(self: Self) -> None:
170
173
  """
@@ -315,19 +318,20 @@ class SigmaDetection(ParentChainMixin):
315
318
  Mapping[str, Any] | list[int | float | str | bool | None] | float | str | bool | None
316
319
  ),
317
320
  source: SigmaRuleLocation | None = None,
321
+ policy: "SigmaPolicy | None" = None,
318
322
  ) -> Self:
319
323
  """Instantiate an appropriate SigmaDetection object from a parsed Sigma detection definition."""
320
324
  if isinstance(definition, Mapping): # key-value-definition (case 1)
321
325
  return cls(
322
326
  detection_items=[
323
- SigmaDetectionItem.from_mapping(key, val, source)
327
+ SigmaDetectionItem.from_mapping(key, val, source, policy)
324
328
  for key, val in definition.items()
325
329
  ],
326
330
  source=source,
327
331
  )
328
332
  elif isinstance(definition, (str, int, float, bool, type(None))): # plain value (case 2)
329
333
  return cls(
330
- detection_items=[SigmaDetectionItem.from_value(definition, source)],
334
+ detection_items=[SigmaDetectionItem.from_value(definition, source, policy)],
331
335
  source=source,
332
336
  )
333
337
  elif isinstance(definition, list): # list of items (case 3)
@@ -335,14 +339,14 @@ class SigmaDetection(ParentChainMixin):
335
339
  {str, int, float, bool, type(None)}
336
340
  ): # list of values: create one detection item containing all values
337
341
  return cls(
338
- detection_items=[SigmaDetectionItem.from_value(definition, source)],
342
+ detection_items=[SigmaDetectionItem.from_value(definition, source, policy)],
339
343
  source=source,
340
344
  )
341
345
  else:
342
346
  return cls(
343
347
  detection_items=[
344
348
  SigmaDetection.from_definition(
345
- item, source
349
+ item, source, policy
346
350
  ) # nested SigmaDetection in other cases
347
351
  for item in definition
348
352
  ],
@@ -548,7 +552,7 @@ class SigmaDetections:
548
552
  check_alias_expansion(detections, sigma_exceptions.SigmaDetectionError, source)
549
553
  return cls(
550
554
  detections={
551
- name: SigmaDetection.from_definition(definition, source)
555
+ name: SigmaDetection.from_definition(definition, source, policy)
552
556
  for name, definition in detections.items()
553
557
  if name not in ("condition",)
554
558
  },
@@ -128,6 +128,7 @@ class SigmaString(SigmaType):
128
128
  s: list[
129
129
  SigmaStringPartType
130
130
  ] # the string is represented as sequence of strings and characters with special meaning
131
+ max_placeholder_expansions: ClassVar[int] = 200
131
132
 
132
133
  def __init__(self, s: str | None = None, escape: bool = True):
133
134
  """
@@ -544,6 +545,8 @@ class SigmaString(SigmaType):
544
545
 
545
546
  The callback can return a plain string, a SpecialChars instance (for insertion of wildcards) or a Placeholder (e.g. to keep
546
547
  the placeholder for later processing pipeline items).
548
+
549
+ The total number of expanded strings is limited to max_placeholder_expansions.
547
550
  """
548
551
  if (
549
552
  not self.contains_placeholder()
@@ -558,15 +561,20 @@ class SigmaString(SigmaType):
558
561
  placeholder = s[i]
559
562
  suffix = SigmaString()
560
563
  suffix.s = s[i + 1 :]
561
- return [
562
- prefix + replacement + result_suffix
563
- for replacement in callback(
564
- cast(Placeholder, placeholder)
565
- ) # iterate over all callback result values
564
+ results: list[SigmaString] = []
565
+ for replacement in callback(
566
+ cast(Placeholder, placeholder)
567
+ ): # iterate over all callback result values
566
568
  for result_suffix in suffix.replace_placeholders(
567
569
  callback
568
- ) # iterate over all result values of calling this method with the SigmaString remainder
569
- ]
570
+ ): # iterate over all result values of calling this method with the SigmaString remainder
571
+ results.append(prefix + replacement + result_suffix)
572
+ if len(results) > self.max_placeholder_expansions:
573
+ raise SigmaValueError(
574
+ "Placeholder expansion exceeds maximum of "
575
+ f"{self.max_placeholder_expansions} items"
576
+ )
577
+ return results
570
578
  return [self]
571
579
 
572
580
  def __iter__(self) -> Iterable[SigmaStringPartType]:
@@ -828,9 +836,9 @@ class SigmaRegularExpression(SigmaType):
828
836
 
829
837
  def compile(self) -> None:
830
838
  """Verify if regular expression is valid by compiling it"""
831
- import sigma
839
+ from sigma.policy import default_policy
832
840
 
833
- engine = (self.policy or sigma.default_policy).regex_engine
841
+ engine = (self.policy or default_policy).regex_engine
834
842
  try:
835
843
  flags = 0
836
844
  for flag in self.flags:
@@ -3,6 +3,7 @@ from typing import Any, DefaultDict, Iterable, Iterator, Type
3
3
  from uuid import UUID
4
4
  from sigma.exceptions import SigmaConfigurationError, SigmaValidatorConfigurationParsingError
5
5
  from sigma.rule import SigmaRule
6
+ from sigma.rule.base import check_alias_expansion
6
7
  from sigma.validators.base import SigmaRuleValidator, SigmaValidationIssue
7
8
  import yaml
8
9
 
@@ -56,6 +57,8 @@ class SigmaValidator:
56
57
  :return: Instantiated SigmaValidator
57
58
  :rtype: SigmaValidator
58
59
  """
60
+ check_alias_expansion(d, SigmaConfigurationError)
61
+
59
62
  # Build validator class set
60
63
  vs = set()
61
64
  for v in d.get("validators", []):
@@ -1,6 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from sigma.policy import SigmaPolicy
4
- from sigma.policy.profiles import SafePolicy
5
-
6
- default_policy: SigmaPolicy = SafePolicy
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes