add ui
This commit is contained in:
92
src/fgai/monitor.py
Normal file
92
src/fgai/monitor.py
Normal file
@@ -0,0 +1,92 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from .anomaly import anomaly_summary, detect_source_anomalies
|
||||
from .logs import local_in_failures, read_events, summarize_events, top_field_values
|
||||
from .mitigation import parse_allowlist, suggest_block_candidates
|
||||
from .policies import audit_policies, read_policies
|
||||
|
||||
|
||||
def build_status(
|
||||
log_path: str,
|
||||
*,
|
||||
policy_path: str | None = None,
|
||||
min_block_events: int = 3,
|
||||
min_block_score: int = 7,
|
||||
anomaly_limit: int = 20,
|
||||
) -> dict[str, object]:
|
||||
events = read_events(log_path) if Path(log_path).exists() else []
|
||||
anomalies = detect_source_anomalies(events, limit=anomaly_limit)
|
||||
block_candidates = suggest_block_candidates(
|
||||
events,
|
||||
min_events=min_block_events,
|
||||
min_score=min_block_score,
|
||||
allowlist=parse_allowlist(),
|
||||
)
|
||||
|
||||
policy_findings: list[dict[str, str | None]] = []
|
||||
policy_error: str | None = None
|
||||
if policy_path and Path(policy_path).exists():
|
||||
try:
|
||||
policy_findings = [finding.__dict__ for finding in audit_policies(read_policies(policy_path))]
|
||||
except Exception as exc:
|
||||
policy_error = str(exc)
|
||||
|
||||
return {
|
||||
"generated_at": int(time.time()),
|
||||
"log_path": log_path,
|
||||
"policy_path": policy_path,
|
||||
"summary": summarize_events(events),
|
||||
"anomaly_summary": anomaly_summary(anomalies),
|
||||
"diagnostics": {
|
||||
"top_source_ips": top_field_values(events, "srcip", limit=10),
|
||||
"top_services": top_field_values(events, "service", limit=10),
|
||||
"top_actions": top_field_values(events, "action", limit=10),
|
||||
"top_subtypes": top_field_values(events, "subtype", limit=10),
|
||||
"local_in_failures": local_in_failures(events, limit=10),
|
||||
},
|
||||
"anomalies": [
|
||||
{
|
||||
"subject": finding.subject,
|
||||
"score": finding.score,
|
||||
"severity": finding.severity,
|
||||
"confidence": finding.confidence,
|
||||
"reasons": finding.reasons,
|
||||
"evidence": finding.evidence,
|
||||
}
|
||||
for finding in anomalies
|
||||
],
|
||||
"block_candidates": [
|
||||
{"src_ip": candidate.src_ip, "score": candidate.score, "reasons": candidate.reasons}
|
||||
for candidate in block_candidates
|
||||
],
|
||||
"policy_findings": policy_findings,
|
||||
"policy_error": policy_error,
|
||||
}
|
||||
|
||||
|
||||
def write_status(status: dict[str, object], output: str) -> None:
|
||||
output_path = Path(output)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp_path = output_path.with_suffix(f"{output_path.suffix}.tmp")
|
||||
tmp_path.write_text(json.dumps(status, indent=2, sort_keys=True), encoding="utf-8")
|
||||
tmp_path.replace(output_path)
|
||||
|
||||
|
||||
def monitor_loop(
|
||||
log_path: str,
|
||||
output: str,
|
||||
*,
|
||||
policy_path: str | None = None,
|
||||
interval: int = 10,
|
||||
anomaly_limit: int = 20,
|
||||
) -> None:
|
||||
print(f"Monitoring {log_path}")
|
||||
print(f"Writing status to {output}")
|
||||
while True:
|
||||
status = build_status(log_path, policy_path=policy_path, anomaly_limit=anomaly_limit)
|
||||
write_status(status, output)
|
||||
time.sleep(interval)
|
||||
Reference in New Issue
Block a user