from __future__ import annotations from app.schemas.analyze import AnalyzeItem from app.services.analyze.base import AnalyzerContribution, AnalyzeContext from app.services.domain_health import get_health_checker class BasicRiskAnalyzer: key = "basic_risk" ttl_seconds = 60 * 10 # 10m (HTTP/SSL/DNS can change quickly) async def analyze(self, ctx: AnalyzeContext) -> list[AnalyzerContribution]: if ctx.fast: return [ AnalyzerContribution( quadrant="risk", items=[ AnalyzeItem( key="risk_skipped_fast_mode", label="Risk Signals", value=None, status="na", source="internal", details={"reason": "Fast mode enabled: skip HTTP/SSL checks."}, ) ], ) ] health = ctx.health if health is None: health = await get_health_checker().check_domain(ctx.domain) # health object has attributes; keep access defensive score = int(getattr(health, "score", 0) or 0) status = getattr(getattr(health, "status", None), "value", None) or str(getattr(health, "status", "unknown")) signals = getattr(health, "signals", []) or [] http = getattr(health, "http", None) ssl = getattr(health, "ssl", None) dns = getattr(health, "dns", None) http_status_code = getattr(http, "status_code", None) if http else None http_reachable = bool(getattr(http, "is_reachable", False)) if http else False http_parked = bool(getattr(http, "is_parked", False)) if http else False redirect_url = getattr(http, "redirect_url", None) if http else None parking_signals = getattr(http, "parking_signals", []) if http else [] http_error = getattr(http, "error", None) if http else None ssl_has = bool(getattr(ssl, "has_ssl", False)) if ssl else False ssl_valid = bool(getattr(ssl, "is_valid", False)) if ssl else False ssl_days = getattr(ssl, "days_until_expiry", None) if ssl else None ssl_issuer = getattr(ssl, "issuer", None) if ssl else None ssl_error = getattr(ssl, "error", None) if ssl else None dns_has_ns = bool(getattr(dns, "has_nameservers", False)) if dns else False dns_has_a = bool(getattr(dns, "has_a_record", False)) if dns else False dns_parking_ns = bool(getattr(dns, "is_parking_ns", False)) if dns else False items = [ AnalyzeItem( key="health_score", label="Health Score", value=score, status="pass" if score >= 80 else "warn" if score >= 50 else "fail", source="internal", details={"status": status, "signals": signals}, ), AnalyzeItem( key="dns_infra", label="DNS Infra", value={"has_ns": dns_has_ns, "has_a": dns_has_a}, status="pass" if (dns_has_ns and dns_has_a and not dns_parking_ns) else "warn", source="dns", details={"parking_ns": dns_parking_ns}, ), AnalyzeItem( key="http", label="HTTP", value=http_status_code, status="pass" if http_reachable and (http_status_code or 0) < 400 else "warn", source="http", details={ "reachable": http_reachable, "is_parked": http_parked, "redirect_url": redirect_url, "parking_signals": parking_signals, "error": http_error, }, ), AnalyzeItem( key="ssl", label="SSL", value=ssl_days if ssl_has else None, status="pass" if ssl_has and ssl_valid else "warn", source="ssl", details={"has_certificate": ssl_has, "is_valid": ssl_valid, "issuer": ssl_issuer, "error": ssl_error}, ), ] return [AnalyzerContribution(quadrant="risk", items=items)]