Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c85decd
Add RSS feed endpoint for preset alerts with XML generation
cursoragent Jun 17, 2025
8daf143
Fix CEL filtering for expired alert dismissals
cursoragent Jun 17, 2025
b3198d6
Fix expired dismissal CEL filtering with enhanced time-travel testing
cursoragent Jun 17, 2025
a66c30c
Fix CEL filtering for expired alert dismissals with comprehensive tes…
cursoragent Jun 17, 2025
2bdc126
Remove expired dismissals cleanup from search engine query method
cursoragent Jun 17, 2025
88b2193
Remove unused import from preset route
cursoragent Jun 17, 2025
53e1dcd
Remove standalone test script for expired dismissal CEL filtering fix
cursoragent Jun 17, 2025
964627a
Remove f-strings from log messages and unused import
cursoragent Jun 17, 2025
8c20db6
Remove f-strings from log messages in cleanup_expired_dismissals
cursoragent Jun 17, 2025
7434f42
Checkpoint before follow-up message
cursoragent Jun 17, 2025
0f6075f
Checkpoint before follow-up message
cursoragent Jun 17, 2025
e5fee73
Refactor tests to use fingerprints directly instead of alert objects
cursoragent Jun 17, 2025
44e20a9
Clean up expired dismissals before fetching alerts in RulesEngine test
cursoragent Jun 17, 2025
b7b7d12
Fix expired dismissal tests and improve test coverage for RulesEngine
cursoragent Jun 17, 2025
38a5e71
Fix caplog level to capture INFO logs in time travel tests
cursoragent Jun 17, 2025
76942a8
Fix caplog level to DEBUG for log message verification in tests
cursoragent Jun 17, 2025
768384f
Fix cleanup test to handle "forever" dismissals correctly
cursoragent Jun 17, 2025
15baedf
Merge branch 'main' into cursor/resolve-ticket-and-implement-unit-tes…
shahargl Jun 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion keep/api/core/alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from keep.api.core.cel_to_sql.sql_providers.get_cel_to_sql_provider_for_dialect import (
get_cel_to_sql_provider,
)
from keep.api.core.db import engine
from keep.api.core.db import cleanup_expired_dismissals, engine

# This import is required to create the tables
from keep.api.core.facets import get_facet_options, get_facets
Expand Down Expand Up @@ -371,6 +371,16 @@
]

with Session(engine) as session:
# Clean up expired dismissals if CEL query involves dismissed field
if query_with_defaults.cel and "dismissed" in query_with_defaults.cel:
try:
cleanup_expired_dismissals(tenant_id, session)
except Exception as e:
logger.warning(

Check warning on line 379 in keep/api/core/alerts.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/alerts.py#L378-L379

Added lines #L378 - L379 were not covered by tests
f"Failed to cleanup expired dismissals: {e}",
extra={"tenant_id": tenant_id}
)

try:
total_count_query = build_total_alerts_query(
tenant_id=tenant_id, query=query_with_defaults
Expand Down
167 changes: 167 additions & 0 deletions keep/api/core/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -5911,3 +5911,170 @@
except Exception:
logger.exception("Failed to create single tenant")
pass


def cleanup_expired_dismissals(tenant_id: str, session: Session = None):
"""
Clean up expired alert dismissals by setting dismissed=false for alerts
where dismissedUntil time has passed.

This ensures that SQL-based CEL filtering works correctly for expired dismissals.
"""
logger = logging.getLogger(__name__)

logger.info(
"Starting cleanup of expired dismissals",
extra={"tenant_id": tenant_id}
)

with existed_or_new_session(session) as session:
try:
# Get current time in UTC
current_time = datetime.now(timezone.utc)

logger.debug(
"Checking for expired dismissals",
extra={
"tenant_id": tenant_id,
"current_time": current_time.isoformat()
}
)

# Get JSON extract function for the database dialect
dismissed_field = get_json_extract_field(session, AlertEnrichment.enrichments, "dismissed")
dismissed_until_field = get_json_extract_field(session, AlertEnrichment.enrichments, "dismissedUntil")

# Find enrichments where:
# 1. dismissed is true/True/"true"
# 2. dismissedUntil is not null/forever and is in the past
query = session.query(AlertEnrichment).filter(
and_(
AlertEnrichment.tenant_id == tenant_id,
dismissed_field.in_(['true', 'True', True, '1']),
dismissed_until_field.is_not(null()),
dismissed_until_field != 'forever'
)
)

expired_enrichments = query.all()

logger.debug(
f"Found {len(expired_enrichments)} potentially expired dismissals to check",
extra={
"tenant_id": tenant_id,
"total_dismissed_alerts": len(expired_enrichments)
}
)

updated_count = 0

for enrichment in expired_enrichments:
try:
dismissed_until_str = enrichment.enrichments.get("dismissedUntil")
if not dismissed_until_str or dismissed_until_str == "forever":
continue

Check warning on line 5975 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L5972-L5975

Added lines #L5972 - L5975 were not covered by tests

logger.debug(

Check warning on line 5977 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L5977

Added line #L5977 was not covered by tests
"Checking dismissal expiration for alert",
extra={
"tenant_id": tenant_id,
"fingerprint": enrichment.alert_fingerprint,
"dismissed_until": dismissed_until_str,
"current_time": current_time.isoformat()
}
)

# Parse the dismissedUntil datetime
dismissed_until_datetime = datetime.strptime(

Check warning on line 5988 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L5988

Added line #L5988 was not covered by tests
dismissed_until_str, "%Y-%m-%dT%H:%M:%S.%fZ"
).replace(tzinfo=timezone.utc)

# Check if dismissal has expired
if current_time >= dismissed_until_datetime:

Check warning on line 5993 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L5993

Added line #L5993 was not covered by tests
# Log before making the change
logger.info(

Check warning on line 5995 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L5995

Added line #L5995 was not covered by tests
"Updating expired dismissal for alert",
extra={
"tenant_id": tenant_id,
"fingerprint": enrichment.alert_fingerprint,
"dismissed_until": dismissed_until_str,
"expired_by_seconds": (current_time - dismissed_until_datetime).total_seconds(),
"current_time": current_time.isoformat()
}
)

# Update the enrichment to set dismissed=false
new_enrichments = enrichment.enrichments.copy()
old_dismissed = new_enrichments.get("dismissed")
new_enrichments["dismissed"] = False

Check warning on line 6009 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6007-L6009

Added lines #L6007 - L6009 were not covered by tests

# Update in database
stmt = (

Check warning on line 6012 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6012

Added line #L6012 was not covered by tests
update(AlertEnrichment)
.where(AlertEnrichment.id == enrichment.id)
.values(enrichments=new_enrichments)
)
session.execute(stmt)
updated_count += 1

Check warning on line 6018 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6017-L6018

Added lines #L6017 - L6018 were not covered by tests

logger.info(

Check warning on line 6020 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6020

Added line #L6020 was not covered by tests
"Successfully updated expired dismissal",
extra={
"tenant_id": tenant_id,
"fingerprint": enrichment.alert_fingerprint,
"old_dismissed": old_dismissed,
"new_dismissed": False,
"dismissed_until": dismissed_until_str
}
)
else:
# Log that dismissal is still active
time_remaining = (dismissed_until_datetime - current_time).total_seconds()
logger.debug(

Check warning on line 6033 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6032-L6033

Added lines #L6032 - L6033 were not covered by tests
"Dismissal still active for alert",
extra={
"tenant_id": tenant_id,
"fingerprint": enrichment.alert_fingerprint,
"dismissed_until": dismissed_until_str,
"time_remaining_seconds": time_remaining
}
)

except (ValueError, KeyError) as e:
logger.warning(

Check warning on line 6044 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6043-L6044

Added lines #L6043 - L6044 were not covered by tests
f"Failed to parse dismissedUntil for alert {enrichment.alert_fingerprint}: {e}",
extra={
"tenant_id": tenant_id,
"fingerprint": enrichment.alert_fingerprint,
"dismissed_until": enrichment.enrichments.get("dismissedUntil"),
"error": str(e)
}
)
continue

Check warning on line 6053 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6053

Added line #L6053 was not covered by tests

if updated_count > 0:
session.commit()
logger.info(

Check warning on line 6057 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6056-L6057

Added lines #L6056 - L6057 were not covered by tests
"Cleanup completed successfully",
extra={
"tenant_id": tenant_id,
"updated_count": updated_count,
"total_checked": len(expired_enrichments)
}
)
else:
logger.debug(
"No expired dismissals found to clean up",
extra={
"tenant_id": tenant_id,
"total_checked": len(expired_enrichments)
}
)

except Exception as e:
logger.exception(

Check warning on line 6075 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6074-L6075

Added lines #L6074 - L6075 were not covered by tests
f"Failed to cleanup expired dismissals for tenant {tenant_id}: {e}",
extra={"tenant_id": tenant_id, "error": str(e)}
)
session.rollback()
raise

Check warning on line 6080 in keep/api/core/db.py

View check run for this annotation

Codecov / codecov/patch

keep/api/core/db.py#L6079-L6080

Added lines #L6079 - L6080 were not covered by tests
1 change: 1 addition & 0 deletions keep/searchengine/searchengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def search_alerts_by_cel(
list[AlertDto]: The list of alerts that match the query
"""
self.logger.info("Searching alerts by CEL")

db_alerts, _ = query_last_alerts(
tenant_id=self.tenant_id,
query=QueryDto(
Expand Down
Loading
Loading