Skip to content

Commit

Permalink
bug fix: include scope with multiple label values, was evaluating onl… (
Browse files Browse the repository at this point in the history
#1655)

* bug fix: include scope with multiple label values, was evaluating only the first one
In addition, if there was an error in sending to a sink, the "stop" wasn't respected

* fix typo in conf.py - remove `/`
  • Loading branch information
arikalon1 authored Dec 8, 2024
1 parent 998a241 commit 142ed7d
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 21 deletions.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"tutorials/playbook-track-secrets.html": "/master/playbook-reference/kubernetes-examples//playbook-track-secrets.html",
"tutorials/alert-remediation.html": "/master/playbook-reference/prometheus-examples/alert-remediation.html",
"tutorials/alert-custom-enrichment.html": "/master/playbook-reference/prometheus-examples/alert-custom-enrichment.html",
"/catalog/sinks/slack.html": "/master/configuration/sinks/slack.html"
"catalog/sinks/slack.html": "/master/configuration/sinks/slack.html"


}
Expand Down
21 changes: 13 additions & 8 deletions src/robusta/core/playbooks/playbooks_event_handler_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,14 +311,19 @@ def __handle_findings(self, execution_event: ExecutionBaseEvent):

# only write the finding if is matching against the sink matchers
if sink.accepts(finding):
# create deep copy, so that iterating on one sink enrichments won't affect the others
# Each sink has a different findings, but enrichments are shared
finding_copy = copy.deepcopy(finding)
sink.write_finding(finding_copy, self.registry.get_sinks().platform_enabled)

sink_info = sinks_info[sink_name]
sink_info.type = sink.__class__.__name__
sink_info.findings_count += 1
try:
# create deep copy, so that iterating on one sink enrichments won't affect the others
# Each sink has a different findings, but enrichments are shared
finding_copy = copy.deepcopy(finding)
sink.write_finding(finding_copy, self.registry.get_sinks().platform_enabled)

sink_info = sinks_info[sink_name]
sink_info.type = sink.__class__.__name__
sink_info.findings_count += 1
except Exception: # if we have an error, we should still respect stop
logging.exception(
f"Failed to send finding {finding.aggregation_key} to sink {sink.sink_name}"
)

if sink.params.stop:
return
Expand Down
26 changes: 14 additions & 12 deletions src/robusta/utils/scope.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
import re
from abc import abstractmethod, ABC
from typing import Dict, Optional, Union, List
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Union

from pydantic import BaseModel, root_validator

Expand Down Expand Up @@ -51,22 +51,24 @@ def scope_matches(self, scope: ScopeIncludeExcludeParamsT) -> bool:
return False
return True

def match_attribute(self, attr_name: str, attr_value, attr_matcher: str) -> bool:
if attr_name == "attributes":
return self.scope_match_attributes(attr_matcher, attr_value)
elif attr_name == "namespace_labels":
return self.scope_match_namespace_labels(attr_matcher, attr_value)
elif attr_name in ["labels", "annotations"]:
return self.match_labels_annotations(attr_matcher, attr_value)
elif re.fullmatch(attr_matcher, attr_value):
return True
return False

def scope_attribute_matches(self, attr_name: str, attr_matchers: List[str]) -> bool:
data = self.get_data()
if attr_name not in data:
logging.warning(f'Scope match on non-existent attribute "{attr_name}" ({data=})')
return False
attr_value = data[attr_name]
for attr_matcher in attr_matchers:
if attr_name == "attributes":
return self.scope_match_attributes(attr_matcher, attr_value)
elif attr_name == "namespace_labels":
return self.scope_match_namespace_labels(attr_matcher, attr_value)
elif attr_name in ["labels", "annotations"]:
return self.match_labels_annotations(attr_matcher, attr_value)
elif re.fullmatch(attr_matcher, attr_value):
return True
return False
return any([self.match_attribute(attr_name, attr_value, matcher) for matcher in attr_matchers])

def scope_match_attributes(self, attr_matcher: str, attr_value: Dict[str, Union[List, Dict]]) -> bool:
raise NotImplementedError
Expand Down

0 comments on commit 142ed7d

Please sign in to comment.