From 5e9d7f7f2fa51b18d1641ae931325c25095c5335 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 12:56:30 +0000 Subject: [PATCH] refactor(config): extract shared non-empty string slice validator Consolidates validateAgentIDs and validateTrustedBots onto a single validateNonEmptyStringSlice helper in validation_rules.go, removing duplicated 'non-empty array of non-empty strings' logic identified in issue #12143. ValidateStringArrayField in guard_policy_validation.go was left unchanged since it operates on []interface{} (not []string) and its distinct error-message wording is pinned by existing tests. Closes #12143 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- internal/config/validation_gateway.go | 26 ++------------------------ internal/config/validation_rules.go | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/internal/config/validation_gateway.go b/internal/config/validation_gateway.go index 7570517f6..fe66067ae 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 d0affa348..458fe5fa2 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 {