109 lines
3 KiB
Go
109 lines
3 KiB
Go
package checker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
// issue is a rule-internal description of a failed test. Rules return a
|
|
// slice of issues from their check func; Evaluate converts them to
|
|
// sdk.CheckState.
|
|
type issue struct {
|
|
Severity sdk.Status // StatusInfo / StatusWarn / StatusCrit
|
|
Message string
|
|
Hint string // remediation hint; surfaced as Meta["hint"]
|
|
Subject string // optional; overrides default data.QueriedOwner
|
|
}
|
|
|
|
// ruleFunc consumes the facts + runtime options and returns zero or more
|
|
// issues. No issues means the test passed.
|
|
type ruleFunc func(d *EmailKeyData, opts sdk.CheckerOptions) []issue
|
|
|
|
// rule is a data-driven CheckRule. All per-test rules share this type;
|
|
// only name / description / applicable kinds / options / check differ.
|
|
type rule struct {
|
|
name string
|
|
description string
|
|
okMessage string // message for StatusOK returns
|
|
kinds []string // applicable kinds; empty = both
|
|
options sdk.CheckerOptionsDocumentation // per-rule options
|
|
check ruleFunc
|
|
}
|
|
|
|
func (r *rule) Name() string { return r.name }
|
|
func (r *rule) Description() string { return r.description }
|
|
func (r *rule) Options() sdk.CheckerOptionsDocumentation { return r.options }
|
|
|
|
func (r *rule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
var data EmailKeyData
|
|
if err := obs.Get(ctx, ObservationKey, &data); err != nil {
|
|
return []sdk.CheckState{{
|
|
Status: sdk.StatusError,
|
|
Message: fmt.Sprintf("Failed to read observation %q: %v", ObservationKey, err),
|
|
Code: "openpgpkey_observation_error",
|
|
}}
|
|
}
|
|
|
|
if len(r.kinds) > 0 && !containsString(r.kinds, data.Kind) {
|
|
return []sdk.CheckState{{
|
|
Status: sdk.StatusUnknown,
|
|
Message: fmt.Sprintf("Not applicable for %s records.", data.Kind),
|
|
Code: r.name,
|
|
Subject: data.QueriedOwner,
|
|
}}
|
|
}
|
|
|
|
issues := r.check(&data, opts)
|
|
if len(issues) == 0 {
|
|
msg := r.okMessage
|
|
if msg == "" {
|
|
msg = "Check passed."
|
|
}
|
|
return []sdk.CheckState{{
|
|
Status: sdk.StatusOK,
|
|
Message: msg,
|
|
Code: r.name,
|
|
Subject: data.QueriedOwner,
|
|
}}
|
|
}
|
|
|
|
states := make([]sdk.CheckState, 0, len(issues))
|
|
for _, iss := range issues {
|
|
subject := iss.Subject
|
|
if subject == "" {
|
|
subject = data.QueriedOwner
|
|
}
|
|
var meta map[string]any
|
|
if iss.Hint != "" {
|
|
meta = map[string]any{"hint": iss.Hint}
|
|
}
|
|
states = append(states, sdk.CheckState{
|
|
Status: iss.Severity,
|
|
Message: iss.Message,
|
|
Code: r.name,
|
|
Subject: subject,
|
|
Meta: meta,
|
|
})
|
|
}
|
|
return states
|
|
}
|
|
|
|
// Rules returns the full set of per-test rules for this checker.
|
|
func Rules() []sdk.CheckRule {
|
|
out := make([]sdk.CheckRule, len(allRules))
|
|
for i := range allRules {
|
|
out[i] = allRules[i]
|
|
}
|
|
return out
|
|
}
|
|
|
|
func containsString(hay []string, needle string) bool {
|
|
for _, v := range hay {
|
|
if v == needle {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|