Add TLS reports capabilities
This commit is contained in:
+21
-4
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user