32 lines
1.7 KiB
Python
32 lines
1.7 KiB
Python
"""Local alert triage: prints redacted counts; exits 1 when attention is required."""
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from .db import connect
|
|
from .scanning import ClamAV
|
|
|
|
def scanner_status():
|
|
try:
|
|
version=ClamAV().version()
|
|
signature_text=version.split('/',2)[2]
|
|
signature_at=datetime.strptime(signature_text,'%a %b %d %H:%M:%S %Y').replace(tzinfo=timezone.utc)
|
|
age_hours=max(0,(datetime.now(timezone.utc)-signature_at).total_seconds()/3600)
|
|
return {'available':True,'version':version,'signature_age_hours':round(age_hours,1),
|
|
'signatures_stale':age_hours>24*7}
|
|
except Exception:
|
|
return {'available':False,'version':None,'signature_age_hours':None,'signatures_stale':True}
|
|
|
|
def status():
|
|
with connect() as c:
|
|
rows=c.execute("""SELECT event,count(*) AS count FROM dtf_local.security_events
|
|
WHERE created_at>now()-interval '24 hours' GROUP BY event ORDER BY event""").fetchall()
|
|
blocked=c.execute("SELECT scan_state,count(*) AS count FROM dtf_local.uploads WHERE purged_at IS NULL AND scan_state IN ('error','rejected') GROUP BY scan_state").fetchall()
|
|
counts={r['event']:r['count'] for r in rows}
|
|
scanner=scanner_status()
|
|
attention=bool(blocked or not scanner['available'] or scanner['signatures_stale'] or
|
|
counts.get('rate_limit',0) or counts.get('scanner_worker_error',0) or
|
|
counts.get('operator_login_failed',0)+counts.get('customer_login_failed',0)>=10)
|
|
return {'attention_required':attention,'scanner':scanner,'last_24h':counts,'blocked_artwork':blocked}
|
|
|
|
if __name__=='__main__':
|
|
result=status();print(json.dumps(result,indent=2));raise SystemExit(1 if result['attention_required'] else 0)
|