Skip to content

Commit

Permalink
fix(mapping): exclude enrichment attributes when using &&
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren committed Sep 26, 2024
1 parent afe8c58 commit d5aa027
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 9 deletions.
11 changes: 8 additions & 3 deletions keep-ui/app/mapping/create-or-edit-mapping.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,14 @@ export default function CreateOrEditMapping({ editRule, editCallback }: Props) {
<Badge color="gray">...</Badge>
) : (
attributes
.filter(
(attribute) => !selectedLookupAttributes.includes(attribute)
)
.filter((attribute) => {
return !selectedLookupAttributes.some((lookupAttr) => {
const parts = lookupAttr
.split("&&")
.map((part) => part.trim());
return parts.includes(attribute);
});
})
.map((attribute) => (
<Badge key={attribute} color="orange">
{attribute}
Expand Down
15 changes: 10 additions & 5 deletions keep/api/bl/enrichments_bl.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,16 @@ def _check_alert_matches_rule(self, alert: AlertDto, rule: MappingRule) -> bool:
for matcher in rule.matchers
):
# Extract enrichments from the matched row
enrichments = {
key: value
for key, value in row.items()
if key not in rule.matchers and value is not None
}
enrichments = {}
for key, value in row.items():
if value is not None:
is_matcher = False
for matcher in rule.matchers:
if key in matcher.replace(" ", "").split("&&"):
is_matcher = True
break
if not is_matcher:
enrichments[key] = value
break

if enrichments:
Expand Down
7 changes: 6 additions & 1 deletion keep/api/routes/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ def get_rules(
attributes = []
if rule_dto.type == "csv":
attributes = [
key for key in rule.rows[0].keys() if key not in rule.matchers
key
for key in rule.rows[0].keys()
if not any(
key in matcher.replace(" ", "").split("&&")
for matcher in rule.matchers
)
]
elif rule_dto.type == "topology":
attributes = [
Expand Down
93 changes: 93 additions & 0 deletions tests/test_enrichments.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,3 +617,96 @@ def test_topology_mapping_rule_enrichment(mock_session, mock_alert_dto):
force=False,
audit_enabled=True,
)


def test_run_mapping_rules_with_complex_matchers(mock_session, mock_alert_dto):
# Setup a mapping rule with complex matchers
rule = MappingRule(
id=1,
tenant_id="test_tenant",
priority=1,
matchers=["name && severity", "source"],
rows=[
{
"name": "Test Alert",
"severity": "high",
"service": "high_priority_service",
},
{
"name": "Test Alert",
"severity": "low",
"service": "low_priority_service",
},
{"source": "test_source", "service": "source_specific_service"},
],
disabled=False,
type="csv",
)
mock_session.query.return_value.filter.return_value.filter.return_value.order_by.return_value.all.return_value = [
rule
]

enrichment_bl = EnrichmentsBl(tenant_id="test_tenant", db=mock_session)

# Test case 1: Matches "name && severity"
mock_alert_dto.name = "Test Alert"
mock_alert_dto.severity = "high"
enrichment_bl.run_mapping_rules(mock_alert_dto)
assert mock_alert_dto.service == "high_priority_service"

# Test case 2: Matches "name && severity" (different severity)
mock_alert_dto.severity = "low"
del mock_alert_dto.service
enrichment_bl.run_mapping_rules(mock_alert_dto)
assert mock_alert_dto.service == "low_priority_service"

# Test case 3: Matches "source"
mock_alert_dto.name = "Different Alert"
mock_alert_dto.severity = "medium"
mock_alert_dto.source = ["test_source"]
del mock_alert_dto.service
enrichment_bl.run_mapping_rules(mock_alert_dto)
assert mock_alert_dto.service == "source_specific_service"

# Test case 4: No match
mock_alert_dto.name = "Unmatched Alert"
mock_alert_dto.severity = "medium"
mock_alert_dto.source = ["different_source"]
del mock_alert_dto.service
enrichment_bl.run_mapping_rules(mock_alert_dto)
assert not hasattr(mock_alert_dto, "service")


def test_run_mapping_rules_enrichments_filtering(mock_session, mock_alert_dto):
# Setup a mapping rule with complex matchers and multiple enrichment fields
rule = MappingRule(
id=1,
tenant_id="test_tenant",
priority=1,
matchers=["name && severity"],
rows=[
{
"name": "Test Alert",
"severity": "high",
"service": "high_priority_service",
"team": "on-call",
"priority": "P1",
},
],
disabled=False,
type="csv",
)
mock_session.query.return_value.filter.return_value.filter.return_value.order_by.return_value.all.return_value = [
rule
]

enrichment_bl = EnrichmentsBl(tenant_id="test_tenant", db=mock_session)

# Test case: Matches "name && severity" and applies multiple enrichments
mock_alert_dto.name = "Test Alert"
mock_alert_dto.severity = "high"
enrichment_bl.run_mapping_rules(mock_alert_dto)

assert mock_alert_dto.service == "high_priority_service"
assert mock_alert_dto.team == "on-call"
assert mock_alert_dto.priority == "P1"

0 comments on commit d5aa027

Please sign in to comment.