feat(security): add config validation for safety-critical parameters
Add Validate() method to Config that checks temperature range [0,2], max_tokens > 0, max_tool_iterations > 0, gateway port 1-65535, and non-negative security policy values. Called automatically by LoadConfig.
This commit is contained in:
parent
4dbf3e5fcb
commit
12ba462ae5
2 changed files with 157 additions and 0 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue