"""Local alert triage: prints redacted counts; exits 1 when attention is required.""" import json from datetime import datetime, timezone from app.core.db import connect from app.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)