Backend numeric bounds validation
apps/backend/internal/plugins/config.goEnforces minimum and maximum for number and integer fields and rejects NaN and Inf.
func checkNumericBounds(name string, value any, prop map[string]any, typeName string) error {
if typeName != "number" && typeName != "integer" {
return nil
}
valueNumber, ok := numericValue(value)
if !ok || math.IsNaN(valueNumber) || math.IsInf(valueNumber, 0) {
return fmt.Errorf("%w: field %q must be finite", ErrConfigInvalid, name)
}
if minimum, ok := numericSchemaBound(prop["minimum"]); ok && valueNumber < minimum {
return fmt.Errorf("%w: field %q must be at least %v", ErrConfigInvalid, name, minimum)
}
if maximum, ok := numericSchemaBound(prop["maximum"]); ok && valueNumber > maximum {
return fmt.Errorf("%w: field %q must be at most %v", ErrConfigInvalid, name, maximum)
}
return nil
}
func numericSchemaBound(value any) (float64, bool) {
bound, ok := numericValue(value)
return bound, ok && !math.IsNaN(bound) && !math.IsInf(bound, 0)
}func numericValue(v any) (float64, bool) {
switch n := v.(type) {
case float64:
return n, true
case float32:
return float64(n), true
case int:
return float64(n), true
case int8:
return float64(n), true
case int16:
return float64(n), true
case int32:
return float64(n), true
case int64:
return float64(n), true
case uint:
return float64(n), true
case uint8:
return float64(n), true
case uint16:
return float64(n), true
case uint32:
return float64(n), true
case uint64:
return float64(n), true
default:
return 0, false
}
}func checkPropertyValue(name string, value any, prop map[string]any) error {
typeName, hasType := prop["type"].(string)
if hasType {
if !valueMatchesType(value, typeName) {
return fmt.Errorf("%w: field %q must be a %s", ErrConfigInvalid, name, typeName)
}
if err := checkNumericBounds(name, value, prop, typeName); err != nil {
return err
}
}
if enum, ok := prop["enum"].([]any); ok && len(enum) > 0 {
for _, allowed := range enum {
if enumValueMatches(value, allowed) {
return nil
}
}
return fmt.Errorf("%w: field %q must be one of the declared enum values", ErrConfigInvalid, name)
}
return nil
}