Skip to content

Commit dd964f1

Browse files
committed
feat: create new endpoint to retrieve summary of different alerts
Closes: #1200
1 parent 58132ba commit dd964f1

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
lines changed

src/codegate/api/v1.py

+27
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,33 @@ async def get_workspace_alerts(workspace_name: str) -> List[Optional[v1_models.A
397397
raise HTTPException(status_code=500, detail="Internal server error")
398398

399399

400+
@v1.get(
401+
"/workspaces/{workspace_name}/alerts-summary",
402+
tags=["Workspaces"],
403+
generate_unique_id_function=uniq_name,
404+
)
405+
async def get_workspace_alerts_summary(workspace_name: str) -> v1_models.AlertSummary:
406+
"""Get alert summary for a workspace."""
407+
try:
408+
ws = await wscrud.get_workspace_by_name(workspace_name)
409+
except crud.WorkspaceDoesNotExistError:
410+
raise HTTPException(status_code=404, detail="Workspace does not exist")
411+
except Exception:
412+
logger.exception("Error while getting workspace")
413+
raise HTTPException(status_code=500, detail="Internal server error")
414+
415+
try:
416+
summary = await dbreader.get_alerts_summary_by_workspace(ws.id)
417+
return v1_models.AlertSummary(
418+
malicious_packages=summary["codegate_context_retriever_count"],
419+
pii=summary["codegate_pii_count"],
420+
secrets=summary["codegate_secrets_count"],
421+
)
422+
except Exception:
423+
logger.exception("Error while getting alerts summary")
424+
raise HTTPException(status_code=500, detail="Internal server error")
425+
426+
400427
@v1.get(
401428
"/workspaces/{workspace_name}/messages",
402429
tags=["Workspaces"],

src/codegate/api/v1_models.py

+10
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ def from_db_model(db_model: db_models.Alert) -> "Alert":
190190
timestamp: datetime.datetime
191191

192192

193+
class AlertSummary(pydantic.BaseModel):
194+
"""
195+
Represents a set of summary alerts
196+
"""
197+
198+
malicious_packages: int
199+
pii: int
200+
secrets: int
201+
202+
193203
class PartialQuestionAnswer(pydantic.BaseModel):
194204
"""
195205
Represents a partial conversation.

src/codegate/db/connection.py

+33-4
Original file line numberDiff line numberDiff line change
@@ -677,10 +677,10 @@ async def get_prompts_with_output_alerts_usage_by_workspace_id(
677677
# If trigger category is None we want to get all alerts
678678
trigger_category = trigger_category if trigger_category else "%"
679679
conditions = {"workspace_id": workspace_id, "trigger_category": trigger_category}
680-
rows: List[IntermediatePromptWithOutputUsageAlerts] = (
681-
await self._exec_select_conditions_to_pydantic(
682-
IntermediatePromptWithOutputUsageAlerts, sql, conditions, should_raise=True
683-
)
680+
rows: List[
681+
IntermediatePromptWithOutputUsageAlerts
682+
] = await self._exec_select_conditions_to_pydantic(
683+
IntermediatePromptWithOutputUsageAlerts, sql, conditions, should_raise=True
684684
)
685685
prompts_dict: Dict[str, GetPromptWithOutputsRow] = {}
686686
for row in rows:
@@ -746,6 +746,35 @@ async def get_alerts_by_workspace(
746746
)
747747
return prompts
748748

749+
async def get_alerts_summary_by_workspace(self, workspace_id: str) -> dict:
750+
"""Get aggregated alert summary counts for a given workspace_id."""
751+
sql = text(
752+
"""
753+
SELECT
754+
COUNT(*) AS total_alerts,
755+
SUM(CASE WHEN a.trigger_type = 'codegate-secrets' THEN 1 ELSE 0 END) AS codegate_secrets_count,
756+
SUM(CASE WHEN a.trigger_type = 'codegate-context-retriever' THEN 1 ELSE 0 END) AS codegate_context_retriever_count,
757+
SUM(CASE WHEN a.trigger_type = 'codegate-pii' THEN 1 ELSE 0 END) AS codegate_pii_count
758+
FROM alerts a
759+
INNER JOIN prompts p ON p.id = a.prompt_id
760+
WHERE p.workspace_id = :workspace_id
761+
"""
762+
)
763+
conditions = {"workspace_id": workspace_id}
764+
765+
async with self._async_db_engine.begin() as conn:
766+
result = await conn.execute(sql, conditions)
767+
row = result.fetchone()
768+
769+
# Return a dictionary with counts (handling None values safely)
770+
return {
771+
"codegate_secrets_count": row.codegate_secrets_count or 0 if row else 0,
772+
"codegate_context_retriever_count": (
773+
row.codegate_context_retriever_count or 0 if row else 0
774+
),
775+
"codegate_pii_count": row.codegate_pii_count or 0 if row else 0,
776+
}
777+
749778
async def get_workspaces(self) -> List[WorkspaceWithSessionInfo]:
750779
sql = text(
751780
"""

0 commit comments

Comments
 (0)