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.
This commit is contained in:
nemunaire 2026-05-18 10:57:48 +08:00
commit 0a41c706aa

View file

@ -256,52 +256,79 @@ func (p *srvProvider) GetHTMLReport(ctx sdk.ReportContext) (string, error) {
rd.Records = append(rd.Records, rec) rd.Records = append(rd.Records, rec)
} }
if len(resolveFails) > 0 { // Build alerts from rule states when available; fall back to raw-data
rd.Alerts = append(rd.Alerts, reportAlert{ // analysis when the host hasn't threaded rule output through yet.
Severity: "crit", states := ctx.States()
Title: fmt.Sprintf("DNS resolution failed for %d SRV target(s)", len(resolveFails)), if len(states) > 0 {
Body: template.HTML(fmt.Sprintf( for _, st := range states {
"%s<br>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.", sev := ""
strings.Join(resolveFails, "<br>"))), switch st.Status {
}) case sdk.StatusCrit, sdk.StatusError:
} sev = "crit"
if len(cnames) > 0 { case sdk.StatusWarn:
rd.Alerts = append(rd.Alerts, reportAlert{ sev = "warn"
Severity: "warn", case sdk.StatusInfo:
Title: "SRV target is a CNAME (RFC 2782 violation)", sev = "info"
Body: template.HTML(fmt.Sprintf( default:
"Target(s): %s<br>RFC 2782 requires SRV targets to resolve directly to A/AAAA. "+ continue
"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.", alert := reportAlert{
"<code>"+strings.Join(cnames, "</code>, <code>")+"</code>")), Severity: sev,
}) Title: st.Message,
} }
if len(tcpDown) > 0 { if fix, ok := st.Meta["fix"].(string); ok && fix != "" {
var items []string alert.Body = template.HTML(template.HTMLEscapeString(fix))
for _, f := range tcpDown { }
items = append(items, fmt.Sprintf("<code>%s</code> (%s): %s", rd.Alerts = append(rd.Alerts, alert)
template.HTMLEscapeString(f.address), }
template.HTMLEscapeString(f.owner), } else {
template.HTMLEscapeString(f.err))) 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<br>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, "<br>"))),
})
}
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<br>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.",
"<code>"+strings.Join(cnames, "</code>, <code>")+"</code>")),
})
}
if len(tcpDown) > 0 {
var items []string
for _, f := range tcpDown {
items = append(items, fmt.Sprintf("<code>%s</code> (%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, "<br>") +
"<br>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 <code>\".\"</code> 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, "<br>") +
"<br>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 <code>\".\"</code> 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 var buf strings.Builder