From 0a41c706aaf43a4a3ec113089c1a28353addd5f1 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 18 May 2026 10:57:48 +0800 Subject: [PATCH] Use ctx.States() for alert cards in HTML report Build alert cards from rule states when available; fall back to raw-data analysis (resolve failures, CNAME violations, unreachable targets) when states are absent. --- checker/report.go | 117 ++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 45 deletions(-) diff --git a/checker/report.go b/checker/report.go index 8cdb3c2..5d44efb 100644 --- a/checker/report.go +++ b/checker/report.go @@ -256,52 +256,79 @@ func (p *srvProvider) GetHTMLReport(ctx sdk.ReportContext) (string, error) { rd.Records = append(rd.Records, rec) } - if len(resolveFails) > 0 { - rd.Alerts = append(rd.Alerts, reportAlert{ - Severity: "crit", - Title: fmt.Sprintf("DNS resolution failed for %d SRV target(s)", len(resolveFails)), - Body: template.HTML(fmt.Sprintf( - "%s
Clients will not be able to reach the service. Fix: either publish A/AAAA records for the target(s), or remove the broken SRV record.", - strings.Join(resolveFails, "
"))), - }) - } - if len(cnames) > 0 { - rd.Alerts = append(rd.Alerts, reportAlert{ - Severity: "warn", - Title: "SRV target is a CNAME (RFC 2782 violation)", - Body: template.HTML(fmt.Sprintf( - "Target(s): %s
RFC 2782 requires SRV targets to resolve directly to A/AAAA. "+ - "Some clients will refuse to follow the CNAME. Fix: point the SRV record to a hostname with A/AAAA records, "+ - "or replace the CNAME with an ALIAS/ANAME at the DNS provider.", - ""+strings.Join(cnames, ", ")+"")), - }) - } - if len(tcpDown) > 0 { - var items []string - for _, f := range tcpDown { - items = append(items, fmt.Sprintf("%s (%s): %s", - template.HTMLEscapeString(f.address), - template.HTMLEscapeString(f.owner), - template.HTMLEscapeString(f.err))) + // Build alerts from rule states when available; fall back to raw-data + // analysis when the host hasn't threaded rule output through yet. + states := ctx.States() + if len(states) > 0 { + for _, st := range states { + sev := "" + switch st.Status { + case sdk.StatusCrit, sdk.StatusError: + sev = "crit" + case sdk.StatusWarn: + sev = "warn" + case sdk.StatusInfo: + sev = "info" + default: + continue + } + alert := reportAlert{ + Severity: sev, + Title: st.Message, + } + if fix, ok := st.Meta["fix"].(string); ok && fix != "" { + alert.Body = template.HTML(template.HTMLEscapeString(fix)) + } + rd.Alerts = append(rd.Alerts, alert) + } + } else { + if len(resolveFails) > 0 { + rd.Alerts = append(rd.Alerts, reportAlert{ + Severity: "crit", + Title: fmt.Sprintf("DNS resolution failed for %d SRV target(s)", len(resolveFails)), + Body: template.HTML(fmt.Sprintf( + "%s
Clients will not be able to reach the service. Fix: either publish A/AAAA records for the target(s), or remove the broken SRV record.", + strings.Join(resolveFails, "
"))), + }) + } + if len(cnames) > 0 { + rd.Alerts = append(rd.Alerts, reportAlert{ + Severity: "warn", + Title: "SRV target is a CNAME (RFC 2782 violation)", + Body: template.HTML(fmt.Sprintf( + "Target(s): %s
RFC 2782 requires SRV targets to resolve directly to A/AAAA. "+ + "Some clients will refuse to follow the CNAME. Fix: point the SRV record to a hostname with A/AAAA records, "+ + "or replace the CNAME with an ALIAS/ANAME at the DNS provider.", + ""+strings.Join(cnames, ", ")+"")), + }) + } + if len(tcpDown) > 0 { + var items []string + for _, f := range tcpDown { + items = append(items, fmt.Sprintf("%s (%s): %s", + template.HTMLEscapeString(f.address), + template.HTMLEscapeString(f.owner), + template.HTMLEscapeString(f.err))) + } + rd.Alerts = append(rd.Alerts, reportAlert{ + Severity: "crit", + Title: fmt.Sprintf("%d target(s) unreachable on their advertised TCP port", len(tcpDown)), + Body: template.HTML(strings.Join(items, "
") + + "
Check: (1) the server is running and bound to the right port; " + + "(2) firewall/security-group allows inbound TCP to that port; " + + "(3) the SRV record is not pointing at an old IP."), + }) + } + if len(nulls) > 0 && len(nulls) == len(d.Records) { + rd.Alerts = append(rd.Alerts, reportAlert{ + Severity: "warn", + Title: "All SRV records use the null target (\".\"): service is explicitly disabled", + Body: template.HTML( + "RFC 2782 defines a single SRV record with target \".\" to signal that the service is " + + "intentionally not available. If this is what you want, the configuration is correct. " + + "If you expected clients to reach this service, replace the null target with a real hostname."), + }) } - rd.Alerts = append(rd.Alerts, reportAlert{ - Severity: "crit", - Title: fmt.Sprintf("%d target(s) unreachable on their advertised TCP port", len(tcpDown)), - Body: template.HTML(strings.Join(items, "
") + - "
Check: (1) the server is running and bound to the right port; " + - "(2) firewall/security-group allows inbound TCP to that port; " + - "(3) the SRV record is not pointing at an old IP."), - }) - } - if len(nulls) > 0 && len(nulls) == len(d.Records) { - rd.Alerts = append(rd.Alerts, reportAlert{ - Severity: "warn", - Title: "All SRV records use the null target (\".\"): service is explicitly disabled", - Body: template.HTML( - "RFC 2782 defines a single SRV record with target \".\" to signal that the service is " + - "intentionally not available. If this is what you want, the configuration is correct. " + - "If you expected clients to reach this service, replace the null target with a real hostname."), - }) } var buf strings.Builder