From 81ca1810f12eee12c35f04163a73b08527e677a4 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 19 May 2026 21:51:12 +0800 Subject: [PATCH] Move per-rule user options onto their owning rules Each of the seven user options was read by exactly one rule, so expose them via CheckRuleWithOptions instead of the checker-wide UserOpts list. This keeps each rule's configuration colocated with its evaluation logic. --- checker/definition.go | 48 ------------------------------------ checker/rules_enumeration.go | 21 ++++++++++++++++ checker/rules_keys.go | 24 ++++++++++++++++++ checker/rules_signatures.go | 19 ++++++++++++++ checker/rules_ttl.go | 12 +++++++++ 5 files changed, 76 insertions(+), 48 deletions(-) diff --git a/checker/definition.go b/checker/definition.go index 1433538..76e7366 100644 --- a/checker/definition.go +++ b/checker/definition.go @@ -26,54 +26,6 @@ func Definition() *sdk.CheckerDefinition { Description: "Recursive resolver used to discover the apex name servers and to look up the parent DS. Defaults to /etc/resolv.conf.", }, }, - UserOpts: []sdk.CheckerOptionDocumentation{ - { - Id: "nsec3IterationsMax", - Type: "uint", - Label: "Maximum NSEC3 iterations", - Description: "RFC 9276 §3.1 sets the recommended ceiling at 0. Increase only if your signer cannot publish 0 yet.", - Default: defaultNSEC3IterationsMax, - }, - { - Id: "nsec3IterationsSeverity", - Type: "choice", - Label: "Severity when NSEC3 iterations exceed the ceiling", - Choices: []string{"warn", "crit"}, - Default: defaultNSEC3IterationsSeverityWarn, - Description: "Use 'crit' to enforce RFC 9276 strictly.", - }, - { - Id: "signatureFreshness", - Type: "uint", - Label: "RRSIG freshness WARN threshold (days)", - Description: "Warn when the closest RRSIG expires in fewer than this many days.", - Default: defaultSignatureFreshnessDays, - }, - { - Id: "signatureFreshnessCrit", - Type: "uint", - Label: "RRSIG freshness CRIT threshold (days)", - Default: defaultSignatureFreshnessCrit, - }, - { - Id: "minRSAKeySize", - Type: "uint", - Label: "Minimum RSA modulus size (bits)", - Default: defaultMinRSAKeySize, - }, - { - Id: "requireSEP", - Type: "bool", - Label: "Require a KSK (DNSKEY with SEP bit)", - Default: defaultRequireSEP, - }, - { - Id: "dnskeyTTLMin", - Type: "uint", - Label: "Minimum DNSKEY TTL (seconds)", - Default: defaultDNSKEYTTLMinSec, - }, - }, DomainOpts: []sdk.CheckerOptionDocumentation{ { Id: "domain_name", diff --git a/checker/rules_enumeration.go b/checker/rules_enumeration.go index 0adc1ad..ffad328 100644 --- a/checker/rules_enumeration.go +++ b/checker/rules_enumeration.go @@ -102,6 +102,27 @@ func (nsec3IterationsRule) Name() string { return "dnssec_nsec3_iterations" } func (nsec3IterationsRule) Description() string { return "Verifies that NSEC3PARAM.Iterations is at most nsec3IterationsMax (default 0, per RFC 9276 §3.1)." } +func (nsec3IterationsRule) Options() sdk.CheckerOptionsDocumentation { + return sdk.CheckerOptionsDocumentation{ + UserOpts: []sdk.CheckerOptionDocumentation{ + { + Id: "nsec3IterationsMax", + Type: "uint", + Label: "Maximum NSEC3 iterations", + Description: "RFC 9276 §3.1 sets the recommended ceiling at 0. Increase only if your signer cannot publish 0 yet.", + Default: defaultNSEC3IterationsMax, + }, + { + Id: "nsec3IterationsSeverity", + Type: "choice", + Label: "Severity when NSEC3 iterations exceed the ceiling", + Choices: []string{"warn", "crit"}, + Default: defaultNSEC3IterationsSeverityWarn, + Description: "Use 'crit' to enforce RFC 9276 strictly.", + }, + }, + } +} func (nsec3IterationsRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadDNSSEC(ctx, obs) diff --git a/checker/rules_keys.go b/checker/rules_keys.go index 69360bc..a3908ba 100644 --- a/checker/rules_keys.go +++ b/checker/rules_keys.go @@ -139,6 +139,18 @@ func (rsaKeySizeRule) Name() string { return "dnssec_rsa_keysize" } func (rsaKeySizeRule) Description() string { return "Verifies RSA DNSKEYs reach a minimum modulus size (default 2048 bits)." } +func (rsaKeySizeRule) Options() sdk.CheckerOptionsDocumentation { + return sdk.CheckerOptionsDocumentation{ + UserOpts: []sdk.CheckerOptionDocumentation{ + { + Id: "minRSAKeySize", + Type: "uint", + Label: "Minimum RSA modulus size (bits)", + Default: defaultMinRSAKeySize, + }, + }, + } +} func (rsaKeySizeRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadDNSSEC(ctx, obs) @@ -194,6 +206,18 @@ func (kskPresentRule) Name() string { return "dnssec_ksk_present" } func (kskPresentRule) Description() string { return "Verifies at least one DNSKEY has the SEP bit (KSK)." } +func (kskPresentRule) Options() sdk.CheckerOptionsDocumentation { + return sdk.CheckerOptionsDocumentation{ + UserOpts: []sdk.CheckerOptionDocumentation{ + { + Id: "requireSEP", + Type: "bool", + Label: "Require a KSK (DNSKEY with SEP bit)", + Default: defaultRequireSEP, + }, + }, + } +} func (kskPresentRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadDNSSEC(ctx, obs) diff --git a/checker/rules_signatures.go b/checker/rules_signatures.go index 4057d9b..f73c318 100644 --- a/checker/rules_signatures.go +++ b/checker/rules_signatures.go @@ -114,6 +114,25 @@ func (rrsigFreshnessRule) Name() string { return "dnssec_rrsig_freshness" } func (rrsigFreshnessRule) Description() string { return "Warns when RRSIGs are close to expiring; preemptive alert for stuck signers." } +func (rrsigFreshnessRule) Options() sdk.CheckerOptionsDocumentation { + return sdk.CheckerOptionsDocumentation{ + UserOpts: []sdk.CheckerOptionDocumentation{ + { + Id: "signatureFreshness", + Type: "uint", + Label: "RRSIG freshness WARN threshold (days)", + Description: "Warn when the closest RRSIG expires in fewer than this many days.", + Default: defaultSignatureFreshnessDays, + }, + { + Id: "signatureFreshnessCrit", + Type: "uint", + Label: "RRSIG freshness CRIT threshold (days)", + Default: defaultSignatureFreshnessCrit, + }, + }, + } +} func (rrsigFreshnessRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadDNSSEC(ctx, obs) diff --git a/checker/rules_ttl.go b/checker/rules_ttl.go index 53e5ff9..81fea51 100644 --- a/checker/rules_ttl.go +++ b/checker/rules_ttl.go @@ -13,6 +13,18 @@ func (dnskeyTTLMinRule) Name() string { return "dnssec_dnskey_ttl_min" } func (dnskeyTTLMinRule) Description() string { return "Warns when the DNSKEY TTL is too short to be useful for caching." } +func (dnskeyTTLMinRule) Options() sdk.CheckerOptionsDocumentation { + return sdk.CheckerOptionsDocumentation{ + UserOpts: []sdk.CheckerOptionDocumentation{ + { + Id: "dnskeyTTLMin", + Type: "uint", + Label: "Minimum DNSKEY TTL (seconds)", + Default: defaultDNSKEYTTLMinSec, + }, + }, + } +} func (dnskeyTTLMinRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState { data, errState := loadDNSSEC(ctx, obs)