diff --git a/pkg/config/config.go b/pkg/config/config.go index 035d6d37c..92f7930c1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -531,9 +531,55 @@ func LoadConfig(path string) (*Config, error) { return nil, err } + // Validate configuration values + if err := cfg.Validate(); err != nil { + return nil, err + } + return cfg, nil } +// Validate checks configuration values for correctness. +func (c *Config) Validate() error { + // Temperature: [0.0, 2.0] if set + if c.Agents.Defaults.Temperature != nil { + t := *c.Agents.Defaults.Temperature + if t < 0.0 || t > 2.0 { + return fmt.Errorf("agents.defaults.temperature must be between 0.0 and 2.0, got %v", t) + } + } + + // MaxTokens > 0 + if c.Agents.Defaults.MaxTokens <= 0 { + return fmt.Errorf("agents.defaults.max_tokens must be > 0, got %d", c.Agents.Defaults.MaxTokens) + } + + // MaxToolIterations > 0 + if c.Agents.Defaults.MaxToolIterations <= 0 { + return fmt.Errorf("agents.defaults.max_tool_iterations must be > 0, got %d", c.Agents.Defaults.MaxToolIterations) + } + + // Gateway port: 1-65535 + if c.Gateway.Port < 1 || c.Gateway.Port > 65535 { + return fmt.Errorf("gateway.port must be between 1 and 65535, got %d", c.Gateway.Port) + } + + // Security: non-negative values + if c.Tools.Security.DefaultMaxArgSize < 0 { + return fmt.Errorf("tools.security.default_max_arg_size must be >= 0, got %d", c.Tools.Security.DefaultMaxArgSize) + } + for name, policy := range c.Tools.Security.ToolPolicies { + if policy.MaxCallsPerMin < 0 { + return fmt.Errorf("tools.security.tool_policies[%s].max_calls_per_min must be >= 0, got %d", name, policy.MaxCallsPerMin) + } + if policy.MaxArgSize < 0 { + return fmt.Errorf("tools.security.tool_policies[%s].max_arg_size must be >= 0, got %d", name, policy.MaxArgSize) + } + } + + return nil +} + func SaveConfig(path string, cfg *Config) error { data, err := json.MarshalIndent(cfg, "", " ") if err != nil { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 0898217d6..1b3ac7cf7 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "runtime" + "strings" "testing" ) @@ -392,3 +393,113 @@ func TestLoadConfig_OpenAIWebSearchCanBeDisabled(t *testing.T) { t.Fatal("OpenAI codex web search should be false when disabled in config file") } } + +// --- Config Validate() tests --- + +func TestValidate_DefaultConfig(t *testing.T) { + cfg := DefaultConfig() + if err := cfg.Validate(); err != nil { + t.Fatalf("DefaultConfig should be valid, got: %v", err) + } +} + +func TestValidate_TemperatureTooHigh(t *testing.T) { + cfg := DefaultConfig() + temp := 3.0 + cfg.Agents.Defaults.Temperature = &temp + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for temperature > 2.0") + } + if !strings.Contains(err.Error(), "temperature") { + t.Errorf("Error should mention temperature, got: %v", err) + } +} + +func TestValidate_TemperatureNegative(t *testing.T) { + cfg := DefaultConfig() + temp := -0.1 + cfg.Agents.Defaults.Temperature = &temp + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for negative temperature") + } +} + +func TestValidate_TemperatureValid(t *testing.T) { + cfg := DefaultConfig() + temp := 0.7 + cfg.Agents.Defaults.Temperature = &temp + if err := cfg.Validate(); err != nil { + t.Fatalf("Temperature 0.7 should be valid, got: %v", err) + } +} + +func TestValidate_MaxTokensZero(t *testing.T) { + cfg := DefaultConfig() + cfg.Agents.Defaults.MaxTokens = 0 + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for MaxTokens = 0") + } + if !strings.Contains(err.Error(), "max_tokens") { + t.Errorf("Error should mention max_tokens, got: %v", err) + } +} + +func TestValidate_MaxTokensNegative(t *testing.T) { + cfg := DefaultConfig() + cfg.Agents.Defaults.MaxTokens = -1 + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for negative MaxTokens") + } +} + +func TestValidate_MaxToolIterationsZero(t *testing.T) { + cfg := DefaultConfig() + cfg.Agents.Defaults.MaxToolIterations = 0 + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for MaxToolIterations = 0") + } +} + +func TestValidate_GatewayPortInvalid(t *testing.T) { + cfg := DefaultConfig() + cfg.Gateway.Port = 0 + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for port = 0") + } + if !strings.Contains(err.Error(), "port") { + t.Errorf("Error should mention port, got: %v", err) + } +} + +func TestValidate_GatewayPortTooHigh(t *testing.T) { + cfg := DefaultConfig() + cfg.Gateway.Port = 70000 + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for port > 65535") + } +} + +func TestValidate_SecurityMaxArgSizeNegative(t *testing.T) { + cfg := DefaultConfig() + cfg.Tools.Security.DefaultMaxArgSize = -1 + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for negative DefaultMaxArgSize") + } +} + +func TestValidate_SecurityMaxCallsPerMinNegative(t *testing.T) { + cfg := DefaultConfig() + cfg.Tools.Security.ToolPolicies["exec"] = ToolPolicyConfig{MaxCallsPerMin: -1} + err := cfg.Validate() + if err == nil { + t.Fatal("Expected error for negative MaxCallsPerMin") + } +}