feat: implement Phase 4 enhancements
Some checks failed
CI / lint-and-test (push) Has been cancelled
Some checks failed
CI / lint-and-test (push) Has been cancelled
- Migrate frontend to Alpine.js for reactive state management
- Add source health dashboard in UI and /api/source-health endpoint
- Add event tagging (PATCH /api/events/{id}/tags) and commenting (POST /api/events/{id}/comments)
- Add CSV/JSON export from the UI
- Add rule-based alerting engine (rules.py) with CRUD endpoints (/api/rules)
- Add SIEM export via webhook (siem.py)
- Add AOC audit trail middleware logging all mutations to aoc_audit collection
- Update config with SIEM_ENABLED, SIEM_WEBHOOK_URL, ALERTS_ENABLED
- Add tests for rules engine, tags, comments, and source health
This commit is contained in:
42
backend/routes/rules.py
Normal file
42
backend/routes/rules.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from auth import require_auth
|
||||
from bson import ObjectId
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from models.api import AlertRuleResponse
|
||||
from rules import rules_collection
|
||||
|
||||
router = APIRouter(dependencies=[Depends(require_auth)])
|
||||
|
||||
|
||||
def _serialize(doc: dict) -> dict:
|
||||
doc["id"] = str(doc.pop("_id"))
|
||||
return doc
|
||||
|
||||
|
||||
@router.get("/rules", response_model=list[AlertRuleResponse])
|
||||
def list_rules():
|
||||
return [_serialize(doc) for doc in rules_collection.find()]
|
||||
|
||||
|
||||
@router.post("/rules", response_model=AlertRuleResponse)
|
||||
def create_rule(rule: AlertRuleResponse):
|
||||
payload = rule.model_dump(exclude={"id"})
|
||||
result = rules_collection.insert_one(payload)
|
||||
payload["id"] = str(result.inserted_id)
|
||||
return payload
|
||||
|
||||
|
||||
@router.put("/rules/{rule_id}", response_model=AlertRuleResponse)
|
||||
def update_rule(rule_id: str, rule: AlertRuleResponse):
|
||||
payload = rule.model_dump(exclude={"id"})
|
||||
result = rules_collection.update_one({"_id": ObjectId(rule_id)}, {"$set": payload})
|
||||
if result.matched_count == 0:
|
||||
raise HTTPException(status_code=404, detail="Rule not found")
|
||||
return {**payload, "id": rule_id}
|
||||
|
||||
|
||||
@router.delete("/rules/{rule_id}")
|
||||
def delete_rule(rule_id: str):
|
||||
result = rules_collection.delete_one({"_id": ObjectId(rule_id)})
|
||||
if result.deleted_count == 0:
|
||||
raise HTTPException(status_code=404, detail="Rule not found")
|
||||
return {"deleted": True}
|
||||
Reference in New Issue
Block a user