Use ctx.States() for headline and diagnoses in HTML report

Drive listed-count and action-required cards from rule states when
available; fall back to raw observation data when states are absent.
This commit is contained in:
nemunaire 2026-05-17 23:56:28 +08:00
commit 6719e21b51

View file

@ -21,16 +21,17 @@ func (p *blacklistProvider) GetHTMLReport(ctx sdk.ReportContext) (string, error)
return "", fmt.Errorf("decode blacklist data: %w", err)
}
states := ctx.States()
view := reportView{
Domain: data.Domain,
RegisteredDomain: data.RegisteredDomain,
CollectedAt: data.CollectedAt.Format("2006-01-02 15:04 MST"),
TotalHits: data.TotalHits(),
Diagnoses: diagnose(&data),
Diagnoses: diagnoseFromStates(states, &data),
Sections: buildSections(&data),
CSS: template.CSS(reportCSS),
}
view.Headline, view.HeadlineClass = headline(view.TotalHits)
view.Headline, view.HeadlineClass = headlineFromStates(states, view.TotalHits)
var b bytes.Buffer
if err := reportTemplate.Execute(&b, view); err != nil {
@ -129,6 +130,54 @@ func diagnose(d *BlacklistData) []Diagnosis {
return out
}
func headlineFromStates(states []sdk.CheckState, fallbackHits int) (string, string) {
if len(states) == 0 {
return headline(fallbackHits)
}
listed := 0
for _, st := range states {
if st.Code == "source_listed" {
listed++
}
}
return headline(listed)
}
func diagnoseFromStates(states []sdk.CheckState, d *BlacklistData) []Diagnosis {
if len(states) == 0 {
return diagnose(d)
}
var out []Diagnosis
for _, st := range states {
if st.Status != sdk.StatusCrit && st.Status != sdk.StatusWarn {
continue
}
switch st.Code {
case "source_listed":
diag := Diagnosis{
Severity: SeverityCrit,
Title: "Listed in " + st.Subject,
Detail: st.Message,
}
if v, ok := st.Meta["lookup_url"].(string); ok {
diag.LookupURL = v
}
if v, ok := st.Meta["removal_url"].(string); ok {
diag.RemovalURL = v
}
out = append(out, diag)
case "source_error", "source_resolver_blocked":
out = append(out, Diagnosis{
Severity: SeverityWarn,
Title: "Could not query " + st.Subject,
Detail: st.Message,
})
}
}
sort.SliceStable(out, func(i, j int) bool { return sevRank(out[i].Severity) < sevRank(out[j].Severity) })
return out
}
func sevRank(s string) int {
switch s {
case SeverityCrit: