|
|
@@ -971,26 +971,29 @@ func convertRule(l *slog.Logger, p any, table string, i int) (rule, error) {
|
|
|
var singleGroup string
|
|
|
if g, ok := m["group"]; ok && g != nil {
|
|
|
// Make sure group isn't an array
|
|
|
- if v, ok := g.([]any); ok {
|
|
|
+ v, isArray := g.([]any)
|
|
|
+ if isArray {
|
|
|
if len(v) > 1 {
|
|
|
return r, errors.New("group should contain a single value, an array with more than one entry was provided")
|
|
|
}
|
|
|
if len(v) == 0 {
|
|
|
return r, errors.New("group should contain a single value, an empty array was provided")
|
|
|
}
|
|
|
-
|
|
|
- l.Warn("group was an array with a single value, converting to simple value",
|
|
|
- "table", table,
|
|
|
- "rule", i,
|
|
|
- )
|
|
|
g = v[0]
|
|
|
}
|
|
|
|
|
|
var err error
|
|
|
- singleGroup, err = groupName(g)
|
|
|
+ singleGroup, err = groupName(l, g, table, i)
|
|
|
if err != nil {
|
|
|
return r, fmt.Errorf("group should contain a single value, %w", err)
|
|
|
}
|
|
|
+
|
|
|
+ if isArray {
|
|
|
+ l.Warn("group was an array with a single value, converting to simple value",
|
|
|
+ "table", table,
|
|
|
+ "rule", i,
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// A null value, `groups:` with nothing after it, is the same as no groups
|
|
|
@@ -1000,14 +1003,14 @@ func convertRule(l *slog.Logger, p any, table string, i int) (rule, error) {
|
|
|
v := reflect.ValueOf(rg)
|
|
|
r.Groups = make([]string, v.Len())
|
|
|
for gi := 0; gi < v.Len(); gi++ {
|
|
|
- name, err := groupName(v.Index(gi).Interface())
|
|
|
+ name, err := groupName(l, v.Index(gi).Interface(), table, i)
|
|
|
if err != nil {
|
|
|
return r, fmt.Errorf("groups entry #%d should contain a single value, %w", gi, err)
|
|
|
}
|
|
|
r.Groups[gi] = name
|
|
|
}
|
|
|
default:
|
|
|
- name, err := groupName(rg)
|
|
|
+ name, err := groupName(l, rg, table, i)
|
|
|
if err != nil {
|
|
|
return r, fmt.Errorf("groups should contain an array or a single value, %w", err)
|
|
|
}
|
|
|
@@ -1027,20 +1030,31 @@ func convertRule(l *slog.Logger, p any, table string, i int) (rule, error) {
|
|
|
return r, nil
|
|
|
}
|
|
|
|
|
|
-// groupName reads a group name from config. A scalar is read as a string, as the other rule fields are, so `1` is the
|
|
|
-// group "1". A null, array, or map would only become a name that matches nothing, like "<nil>" or "map[a:b]", so
|
|
|
-// those are rejected. A group really named one of those can be quoted.
|
|
|
-func groupName(v any) (string, error) {
|
|
|
+// groupName reads a group name from config. YAML has already parsed an unquoted value by the time we see it, so `007`
|
|
|
+// arrives as 7, `1.10` as 1.1, and a date as a time.Time, and the text that was written is gone. Strings are used as
|
|
|
+// is. Ints and bools are converted so `group: 7` keeps working, with a warning to quote them. Anything else would
|
|
|
+// become a name that may not match what was written, or matches nothing like "<nil>" or "map[a:b]", so it is rejected.
|
|
|
+func groupName(l *slog.Logger, v any, table string, i int) (string, error) {
|
|
|
if v == nil {
|
|
|
return "", errors.New("a null was provided")
|
|
|
}
|
|
|
switch reflect.TypeOf(v).Kind() {
|
|
|
+ case reflect.String:
|
|
|
+ return reflect.ValueOf(v).String(), nil
|
|
|
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
|
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Bool:
|
|
|
+ l.Warn("group was not a string and should be quoted to match as written",
|
|
|
+ "table", table,
|
|
|
+ "rule", i,
|
|
|
+ "group", v,
|
|
|
+ )
|
|
|
+ return fmt.Sprintf("%v", v), nil
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
return "", errors.New("an array was provided")
|
|
|
case reflect.Map:
|
|
|
return "", errors.New("a map was provided")
|
|
|
}
|
|
|
- return fmt.Sprintf("%v", v), nil
|
|
|
+ return "", fmt.Errorf("%v was read as a %T, quote it to use it as a group name", v, v)
|
|
|
}
|
|
|
|
|
|
// sanity returns an error if the rule would be evaluated in a way that would short-circuit a configured check on a wildcard value
|