Add TLS reports capabilities

This commit is contained in:
2026-06-23 11:49:58 -03:00
parent 5c1dc95c36
commit f4ae9f8532
20 changed files with 1158 additions and 75 deletions
+21 -4
View File
@@ -15,7 +15,7 @@ from app.models import Alert
logger = logging.getLogger(__name__)
SYSTEM_PROMPT = (
"You are an expert email authentication and DMARC operations analyst. You explain deterministic DMARC telemetry "
"You are an expert email authentication, DMARC, and SMTP TLS reporting operations analyst. You explain deterministic telemetry "
"to a business owner/admin. You must not invent facts. You must distinguish confirmed facts from likely "
"interpretations. You must never claim an account is compromised solely from DMARC aggregate failures. You must "
"provide practical next steps. Output only valid JSON matching the requested schema."
@@ -32,6 +32,15 @@ ALERT_PROMPT = (
"object with these keys: summary, risk, recommended_action, confidence."
)
TLS_ALERT_PROMPT = (
"Explain this SMTP TLS aggregate report alert to a business owner/admin. Be precise, do not invent facts, and base "
"the explanation only on the supplied deterministic TLSRPT facts. Explain that TLSRPT covers delivery-session TLS "
"success or failure against policies such as MTA-STS, not DMARC authentication. Mention affected MX hosts, failure "
"counts/rates, and result types when supplied. Recommend concrete checks such as certificate hostname coverage, "
"certificate chain validity, MTA-STS policy contents, MX hostnames, and mail server TLS configuration. Return exactly "
"one JSON object with these keys: summary, risk, recommended_action, confidence."
)
POSTURE_DIGEST_PROMPT = (
"Write a current DMARC posture report for the admin using all supplied deterministic telemetry and all open alerts. "
"Base the report on unresolved/open risk, not only one report day. Mention exact counts/rates, important failing or "
@@ -148,6 +157,13 @@ def normalize_summary_output(output: dict[str, Any], payload: dict[str, Any]) ->
def fallback_alert_explanation(alert: Alert | Any) -> AlertExplanation:
if str(getattr(alert, "type", "")).startswith("tls_"):
return AlertExplanation(
summary=getattr(alert, "summary", "A deterministic SMTP TLS reporting alert was created."),
risk="Review the TLSRPT facts. TLS aggregate reports describe SMTP TLS delivery-session failures and do not by themselves prove message loss or account compromise.",
recommended_action="Check the affected MX hostnames, certificate chain and hostname coverage, MTA-STS policy, and mail server TLS configuration before changing policy.",
confidence="fallback",
)
return AlertExplanation(
summary=getattr(alert, "summary", "DMARC Sentinel created a deterministic alert."),
risk="Review the deterministic facts. DMARC aggregate data alone does not prove mailbox compromise.",
@@ -195,19 +211,20 @@ class LLMClient:
raise RuntimeError(f"LLM call failed: {last_error}")
def explain_alert(self, alert: Alert) -> AlertExplanation:
is_tls = str(alert.type).startswith("tls_")
payload = {
"task": "explain_dmarc_alert",
"task": "explain_tlsrpt_alert" if is_tls else "explain_dmarc_alert",
"domain": alert.domain,
"severity": alert.severity,
"alert_type": alert.type,
"facts": json.loads(alert.details_json or "{}"),
"required_json_schema": {
"summary": "string, one concise sentence based only on the supplied facts",
"risk": "string, business/operational risk without claiming compromise from aggregate data alone",
"risk": "string, business/operational risk without claiming unsupported compromise or data loss",
"recommended_action": "string, concrete next step for the admin",
"confidence": "low|medium|high",
},
"instruction": self._prompt(self.settings.llm.alert_prompt_path, ALERT_PROMPT),
"instruction": TLS_ALERT_PROMPT if is_tls else self._prompt(self.settings.llm.alert_prompt_path, ALERT_PROMPT),
}
last_error: Exception | None = None
for _ in range(2):