diff --git a/internal/config/validation_gateway.go b/internal/config/validation_gateway.go index 7570517f..fe66067a 100644 --- a/internal/config/validation_gateway.go +++ b/internal/config/validation_gateway.go @@ -104,18 +104,7 @@ func validateGatewayConfig(gateway *StdinGatewayConfig) error { } func validateAgentIDs(agentIDs []string, defined bool, fieldName string) error { - if !defined { - return nil - } - if len(agentIDs) == 0 { - return fmt.Errorf("%s must be a non-empty array when present", fieldName) - } - for i, agentID := range agentIDs { - if strings.TrimSpace(agentID) == "" { - return fmt.Errorf("%s[%d] must be a non-empty string", fieldName, i) - } - } - return nil + return validateNonEmptyStringSlice(agentIDs, defined, fieldName, "") } func validateGatewayPayloadSizeThreshold(value int, fieldName, jsonPath string) error { @@ -136,18 +125,7 @@ func validateContainerRuntimeCommandNotBlank(command, fieldName, jsonPath string // validateTrustedBots checks that the trusted_bots/trustedBots list conforms to spec §4.1.3.4: // when present, it must be a non-empty array of non-empty strings. func validateTrustedBots(bots []string) error { - if bots == nil { - return nil - } - if len(bots) == 0 { - return fmt.Errorf("trusted_bots must be a non-empty array when present (spec §4.1.3.4)") - } - for i, bot := range bots { - if strings.TrimSpace(bot) == "" { - return fmt.Errorf("trusted_bots[%d] must be a non-empty string", i) - } - } - return nil + return validateNonEmptyStringSlice(bots, bots != nil, "trusted_bots", " (spec §4.1.3.4)") } // validateTOMLStdioContainerization validates that TOML stdio servers use the selected container runtime command. diff --git a/internal/config/validation_rules.go b/internal/config/validation_rules.go index d0affa34..458fe5fa 100644 --- a/internal/config/validation_rules.go +++ b/internal/config/validation_rules.go @@ -32,6 +32,26 @@ func PortRange(port int, jsonPath string) *ValidationError { return nil } +// validateNonEmptyStringSlice validates that, when defined is true, values is a non-empty +// slice containing only non-empty (non-whitespace) strings. When defined is false, the field +// is treated as absent and validation passes trivially. fieldName is used for both the +// top-level error and per-element errors; specSuffix (e.g. " (spec §4.1.3.4)") is appended +// verbatim after "when present" in the top-level error, or may be empty. +func validateNonEmptyStringSlice(values []string, defined bool, fieldName, specSuffix string) error { + if !defined { + return nil + } + if len(values) == 0 { + return fmt.Errorf("%s must be a non-empty array when present%s", fieldName, specSuffix) + } + for i, v := range values { + if strings.TrimSpace(v) == "" { + return fmt.Errorf("%s[%d] must be a non-empty string", fieldName, i) + } + } + return nil +} + func validatePositiveIntegerRule(value int, fieldName, jsonPath, logLabel, failureLabel, suggestion string) *ValidationError { logValidation.Printf("Validating %s: field=%s, value=%d, jsonPath=%s", logLabel, fieldName, value, jsonPath) if value < 1 {