// SPDX-License-Identifier: MIT package checker import ( "context" "fmt" sdk "git.happydns.org/checker-sdk-go/checker" ) // overallStatusRule reports on the leaf zone's DNSViz status. A SECURE leaf // means the entire chain validates from the root; BOGUS means at least one // link of the chain is broken. type overallStatusRule struct{} func (r *overallStatusRule) Name() string { return "dnsviz_overall_status" } func (r *overallStatusRule) Description() string { return "Reports the DNSViz status of the queried domain (SECURE, INSECURE, BOGUS, INDETERMINATE)." } func (r *overallStatusRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadData(ctx, obs, "dnsviz_overall_status") if errState != nil { return errState } leaf := data.Domain + "." z, ok := data.Zones[leaf] if !ok { // Fall back to the most-specific zone DNSViz reported. zones := orderedZones(data) if len(zones) == 0 { return []sdk.CheckState{{ Status: sdk.StatusUnknown, Code: "dnsviz_overall_status", Message: "DNSViz returned no zones for this domain", }} } leaf = zones[0] z = data.Zones[leaf] } st := sdk.CheckState{ Code: "dnsviz_overall_status", Subject: leaf, Status: statusFromGrok(z.Status), Message: fmt.Sprintf("DNSViz status: %s", emptyAsUnknown(z.Status)), Meta: map[string]any{ "status": z.Status, "errors": len(z.Errors), "warnings": len(z.Warnings), }, } return []sdk.CheckState{st} } // perZoneStatusRule emits one CheckState per zone in the chain. This is what // powers the "every authoritative/parent in a dedicated block" requirement // of the report: each entry has Subject set to the zone name. type perZoneStatusRule struct{} func (r *perZoneStatusRule) Name() string { return "dnsviz_per_zone_status" } func (r *perZoneStatusRule) Description() string { return "Reports the DNSViz status of every zone in the chain (root, TLD, intermediates, leaf)." } func (r *perZoneStatusRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadData(ctx, obs, "dnsviz_per_zone_status") if errState != nil { return errState } zones := orderedZones(data) if len(zones) == 0 { return []sdk.CheckState{{ Status: sdk.StatusUnknown, Code: "dnsviz_per_zone_status", Message: "DNSViz returned no zones for this domain", }} } out := make([]sdk.CheckState, 0, len(zones)) for _, name := range zones { z := data.Zones[name] out = append(out, sdk.CheckState{ Code: "dnsviz_per_zone_status", Subject: name, Status: statusFromGrok(z.Status), Message: fmt.Sprintf("%s — errors=%d warnings=%d", emptyAsUnknown(z.Status), len(z.Errors), len(z.Warnings)), }) } return out } // zoneErrorsRule turns every DNSViz "error" entry into a Crit CheckState. // One state per (zone, finding) pair, so the UI can show a precise list. type zoneErrorsRule struct{} func (r *zoneErrorsRule) Name() string { return "dnsviz_zone_errors" } func (r *zoneErrorsRule) Description() string { return "Surfaces every error reported by DNSViz, scoped to the zone where it was found." } func (r *zoneErrorsRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadData(ctx, obs, "dnsviz_zone_errors") if errState != nil { return errState } var out []sdk.CheckState for _, name := range orderedZones(data) { for _, f := range data.Zones[name].Errors { out = append(out, sdk.CheckState{ Status: sdk.StatusCrit, Code: nonEmpty(f.Code, "dnsviz_zone_errors"), Subject: name, Message: f.Description, Meta: findingMeta(f), }) } } if len(out) == 0 { return []sdk.CheckState{{ Status: sdk.StatusOK, Code: "dnsviz_zone_errors", Message: "DNSViz reported no errors in any zone", }} } return out } // zoneWarningsRule mirrors zoneErrorsRule for warnings (StatusWarn). type zoneWarningsRule struct{} func (r *zoneWarningsRule) Name() string { return "dnsviz_zone_warnings" } func (r *zoneWarningsRule) Description() string { return "Surfaces every warning reported by DNSViz, scoped to the zone where it was found." } func (r *zoneWarningsRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadData(ctx, obs, "dnsviz_zone_warnings") if errState != nil { return errState } var out []sdk.CheckState for _, name := range orderedZones(data) { for _, f := range data.Zones[name].Warnings { out = append(out, sdk.CheckState{ Status: sdk.StatusWarn, Code: nonEmpty(f.Code, "dnsviz_zone_warnings"), Subject: name, Message: f.Description, Meta: findingMeta(f), }) } } if len(out) == 0 { return []sdk.CheckState{{ Status: sdk.StatusOK, Code: "dnsviz_zone_warnings", Message: "DNSViz reported no warnings in any zone", }} } return out } func emptyAsUnknown(s string) string { if s == "" { return "UNKNOWN" } return s } func nonEmpty(a, b string) string { if a != "" { return a } return b } func findingMeta(f Finding) map[string]any { m := map[string]any{} if f.Code != "" { m["code"] = f.Code } if len(f.Servers) > 0 { m["servers"] = f.Servers } if len(m) == 0 { return nil } return m }