Skip to content

Commit

Permalink
Merge branch 'main' into feat-e2e-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren authored Jan 31, 2025
2 parents 79ca01e + c0e2aa8 commit bd76ad1
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 7 deletions.
15 changes: 12 additions & 3 deletions keep/api/bl/maintenance_windows_bl.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,19 @@ def check_if_alert_in_maintenance_windows(self, alert: AlertDto) -> bool:
try:
cel_result = prgm.evaluate(activation)
except celpy.evaluation.CELEvalError as e:
if "no such member" in str(e):
error_msg = str(e).lower()
if "no such member" in error_msg or "undeclared reference" in error_msg:
self.logger.debug(
f"Skipping maintenance window rule due to missing field: {str(e)}",
extra={**extra, "maintenance_rule_id": maintenance_rule.id},
)
continue
# wtf
raise
# Log unexpected CEL errors but don't fail the entire event processing
self.logger.error(
f"Unexpected CEL evaluation error: {str(e)}",
extra={**extra, "maintenance_rule_id": maintenance_rule.id},
)
continue
if cel_result:
self.logger.info(
"Alert is in maintenance window",
Expand Down
4 changes: 2 additions & 2 deletions keep/api/routes/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ def get_metrics(
for label in labels:
label_value = chevron.render("{{ " + label + " }}", last_alert_dto)
label = label.replace(".", "_")
extra_labels += f' {label}="{label_value}"'
extra_labels += f',{label}="{label_value}"'

export += f'alerts_total{{incident_name="{incident_name}" incident_id="{incident.id}"{extra_labels}}} {incident.alerts_count}\n'
export += f'alerts_total{{incident_name="{incident_name}",incident_id="{incident.id}"{extra_labels}}} {incident.alerts_count}\n'

# Exporting stats about open incidents
export += "\n\n"
Expand Down
57 changes: 56 additions & 1 deletion keep/providers/kibana_provider/kibana_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class KibanaProvider(BaseProvider):
}
}
)
SIEM_WEBHOOK_PAYLOAD = """{{#context.alerts}}{{{.}}}{{/context.alerts}}"""

# Mock payloads for validating scopes
MOCK_ALERT_PAYLOAD = {
Expand Down Expand Up @@ -373,6 +374,7 @@ def __setup_webhook_alerts(self, tenant_id: str, keep_api_url: str, api_key: str
self.logger.info(f"Alert {alert_rule['id']} already updated, skipping")
continue

rule_type_id = alert_rule.get("rule_type_id")
action_groups = rule_types.get(alert_rule["rule_type_id"], {}).get(
"action_groups", []
)
Expand All @@ -381,7 +383,14 @@ def __setup_webhook_alerts(self, tenant_id: str, keep_api_url: str, api_key: str
{
"group": action_group.get("id"),
"id": connector_id,
"params": {"body": KibanaProvider.WEBHOOK_PAYLOAD},
"params": {
# SIEM can use a different payload for more context
"body": (
KibanaProvider.WEBHOOK_PAYLOAD
if "siem" not in rule_type_id
else KibanaProvider.SIEM_WEBHOOK_PAYLOAD
)
},
"frequency": {
"notify_when": "onActionGroupChange",
"throttle": None,
Expand Down Expand Up @@ -558,6 +567,49 @@ def _format_alert(
if "payload" in event:
return KibanaProvider.format_alert_from_watcher(event)

# SIEM alert
if "kibana" in event:
logger.info("Parsing SIEM Kibana alert")
description = (
event.get("kibana", {})
.get("alert", {})
.get("rule", {})
.get("description", "")
)
if not description:
logger.warning("Could not find description in SIEM Kibana alert")

name = (
event.get("kibana", {}).get("alert", {}).get("rule", {}).get("name", "")
)
if not name:
logger.warning("Could not find name in SIEM Kibana alert")
name = "SIEM Kibana Alert"

status = event.get("kibana", {}).get("alert", {}).get("status", "")
if not status:
logger.warning("Could not find status in SIEM Kibana alert")
name = "active"

# use map
status = KibanaProvider.STATUS_MAP.get(status, AlertStatus.FIRING)
severity = (
event.get("kibana", {})
.get("alert", {})
.get("severity", "could not find severity")
)
# use map
severity = KibanaProvider.SEVERITIES_MAP.get(severity, AlertSeverity.INFO)
alert_dto = AlertDto(
name=name,
description=description,
status=status,
severity=severity,
source=["kibana"],
**event,
)
logger.info("Finished to parse SIEM Kibana alert")
return alert_dto
# Check if this is the new webhook format
# New Kibana webhook format
if "webhook_body" in event:
Expand Down Expand Up @@ -624,6 +676,9 @@ def _format_alert(
if not event.get("url"):
event.pop("url", None)

if "name" not in event:
event["name"] = event.get("rule.name")

return AlertDto(
environment=environment,
labels=labels,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "keep"
version = "0.35.8"
version = "0.35.10"
description = "Alerting. for developers, by developers."
authors = ["Keep Alerting LTD"]
packages = [{include = "keep"}]
Expand Down
16 changes: 16 additions & 0 deletions tests/test_maintenance_windows_bl.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,19 @@ def test_alert_ignored_due_to_acknowledged_status(

# Should return False because the alert status is ACKNOWLEDGED
assert result is False


def test_alert_with_missing_cel_field(mock_session, active_maintenance_window_rule, alert_dto):
# Modify the cel_query to reference a non-existent field
active_maintenance_window_rule.cel_query = 'alertname == "test-alert"'
mock_session.query.return_value.filter.return_value.filter.return_value.filter.return_value.all.return_value = [
active_maintenance_window_rule
]

maintenance_window_bl = MaintenanceWindowsBl(
tenant_id="test-tenant", session=mock_session
)
result = maintenance_window_bl.check_if_alert_in_maintenance_windows(alert_dto)

# Should return False because the field doesn't exist
assert result is False

0 comments on commit bd76ad1

Please sign in to comment.