From 1588131e90fae3a24862d0dab26a8aa91576b4ab Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 21 May 2026 18:17:57 +0800 Subject: [PATCH 1/4] Override is no more needed --- checker/definition.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/checker/definition.go b/checker/definition.go index 50d9612..f6223fa 100644 --- a/checker/definition.go +++ b/checker/definition.go @@ -35,19 +35,6 @@ func Definition() *sdk.CheckerDefinition { }, }, UserOpts: []sdk.CheckerOptionDocumentation{ - { - Id: "happydeliver_url", - Type: "string", - Label: "happyDeliver instance URL (override)", - Description: "Override the operator-provided happyDeliver URL.", - }, - { - Id: "happydeliver_token", - Type: "string", - Label: "happyDeliver API token (override)", - Description: "Override the operator-provided happyDeliver token.", - Secret: true, - }, { Id: "smtp_host", Type: "string", From 10a65aed02e11375610d957d6dcbfe5fd82eef8d Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 21 May 2026 18:35:42 +0800 Subject: [PATCH 2/4] Move from_address to domain options with no-reply default --- checker/collect.go | 6 +++++- checker/definition.go | 13 ++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/checker/collect.go b/checker/collect.go index d675434..8ec5c38 100644 --- a/checker/collect.go +++ b/checker/collect.go @@ -158,7 +158,11 @@ func loadConfig(opts sdk.CheckerOptions) (*runConfig, error) { return nil, fmt.Errorf("smtp_host is required") } if cfg.FromAddress == "" { - return nil, fmt.Errorf("from_address is required") + domain := strings.TrimSpace(stringOpt(opts, "domain_name")) + if domain == "" { + return nil, fmt.Errorf("from_address is required when domain_name is not set") + } + cfg.FromAddress = "no-reply@" + strings.TrimSuffix(domain, ".") } parsedFrom, err := mail.ParseAddress(cfg.FromAddress) if err != nil { diff --git a/checker/definition.go b/checker/definition.go index f6223fa..787ff00 100644 --- a/checker/definition.go +++ b/checker/definition.go @@ -71,13 +71,6 @@ func Definition() *sdk.CheckerDefinition { Choices: []string{"starttls", "tls", "none"}, Default: "starttls", }, - { - Id: "from_address", - Type: "string", - Label: "From address", - Description: "Address used in the From header of the test email. Must be in the tested domain.", - Required: true, - }, { Id: "subject_override", Type: "string", @@ -119,6 +112,12 @@ func Definition() *sdk.CheckerDefinition { Label: "Domain name", AutoFill: sdk.AutoFillDomainName, }, + { + Id: "from_address", + Type: "string", + Label: "From address", + Description: "Address used in the From header of the test email. Must be in the tested domain. Defaults to no-reply@.", + }, }, }, Rules: []sdk.CheckRule{ From 7fe4e4b3a4dcb9b0df84368429e61de5b9ae1e1c Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 21 May 2026 18:52:19 +0800 Subject: [PATCH 3/4] Fix TestDefinitionShape to assert ApplyToService The checker no longer applies to whole domains (see 62af174 "Apply only on opt-in services"); align the test with that availability. --- checker/provider_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checker/provider_test.go b/checker/provider_test.go index f2d9629..e57c4e7 100644 --- a/checker/provider_test.go +++ b/checker/provider_test.go @@ -86,8 +86,8 @@ func TestDefinitionShape(t *testing.T) { if def.ID != "happydeliver" { t.Errorf("ID = %q", def.ID) } - if !def.Availability.ApplyToDomain { - t.Error("should apply to domain") + if !def.Availability.ApplyToService { + t.Error("should apply to service") } if !def.HasMetrics { t.Error("HasMetrics should be true") From ae8efc2f64e4bdc8c9cb98e261e60f5c08f4488a Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 21 May 2026 18:52:32 +0800 Subject: [PATCH 4/4] Validate from_address option via net/mail at the host Reject malformed addresses up-front instead of letting them surface as a runtime SMTP failure during Collect. --- checker/provider.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/checker/provider.go b/checker/provider.go index 2cf6a50..d66de34 100644 --- a/checker/provider.go +++ b/checker/provider.go @@ -2,6 +2,9 @@ package checker import ( "encoding/json" + "fmt" + "net/mail" + "strings" "time" sdk "git.happydns.org/checker-sdk-go/checker" @@ -21,6 +24,27 @@ func (p *happyDeliverProvider) Definition() *sdk.CheckerDefinition { return Definition() } +// ValidateOptions runs on the host before Collect so bad options are rejected +// up-front rather than surfacing as a runtime SMTP failure. +func (p *happyDeliverProvider) ValidateOptions(opts sdk.CheckerOptions) error { + raw, ok := opts["from_address"] + if !ok { + return nil + } + s, ok := raw.(string) + if !ok { + return fmt.Errorf("from_address must be a string") + } + s = strings.TrimSpace(s) + if s == "" { + return nil + } + if _, err := mail.ParseAddress(s); err != nil { + return fmt.Errorf("invalid from_address: %w", err) + } + return nil +} + func (p *happyDeliverProvider) ExtractMetrics(ctx sdk.ReportContext, collectedAt time.Time) ([]sdk.CheckMetric, error) { var data HappyDeliverData if err := json.Unmarshal(ctx.Data(), &data); err != nil {