diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation.go index 3dbf3b26c0f..60e0de8ac90 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation.go @@ -325,19 +325,17 @@ func unescapeSingleQuote(s string) (string, error) { // ValidFieldPath validates that jsonPath is a valid JSON Path containing only field and map accessors // that are valid for the given schema, and returns a field.Path representation of the validated jsonPath or an error. func ValidFieldPath(jsonPath string, schema *schema.Structural) (validFieldPath *field.Path, err error) { - appendToPath := func(name string) error { - if schema.AdditionalProperties != nil { + appendToPath := func(name string, isNamed bool) error { + if !isNamed { validFieldPath = validFieldPath.Key(name) schema = schema.AdditionalProperties.Structural - } else if schema.Properties != nil { + } else { validFieldPath = validFieldPath.Child(name) val, ok := schema.Properties[name] if !ok { return fmt.Errorf("does not refer to a valid field") } schema = &val - } else { - return fmt.Errorf("does not refer to a valid field") } return nil } @@ -382,6 +380,7 @@ func ValidFieldPath(jsonPath string, schema *schema.Structural) (validFieldPath }) var tok string + var isNamed bool for scanner.Scan() { tok = scanner.Text() switch tok { @@ -397,7 +396,15 @@ func ValidFieldPath(jsonPath string, schema *schema.Structural) (validFieldPath if err != nil { return nil, fmt.Errorf("invalid string literal: %v", err) } - if err := appendToPath(unescaped); err != nil { + + if schema.Properties != nil { + isNamed = true + } else if schema.AdditionalProperties != nil { + isNamed = false + } else { + return nil, fmt.Errorf("does not refer to a valid field") + } + if err := appendToPath(unescaped, isNamed); err != nil { return nil, err } if !scanner.Scan() { @@ -412,7 +419,14 @@ func ValidFieldPath(jsonPath string, schema *schema.Structural) (validFieldPath return nil, fmt.Errorf("unexpected end of JSON path") } tok = scanner.Text() - if err := appendToPath(tok); err != nil { + if schema.Properties != nil { + isNamed = true + } else if schema.AdditionalProperties != nil { + isNamed = false + } else { + return nil, fmt.Errorf("does not refer to a valid field") + } + if err := appendToPath(tok, isNamed); err != nil { return nil, err } default: diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go index 57117b9a9dd..2ea8d38dbcf 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go @@ -2706,6 +2706,11 @@ func TestValidateFieldPath(t *testing.T) { Type: "number", }, }, + "'foo'bar": { + Generic: schema.Generic{ + Type: "number", + }, + }, "a": { Generic: schema.Generic{ Type: "object", @@ -2799,6 +2804,20 @@ func TestValidateFieldPath(t *testing.T) { schema: &sts, validFieldPath: path.Child("a"), }, + { + name: "Valid 'foo'bar", + fieldPath: "['\\'foo\\'bar']", + pathOfFieldPath: path, + schema: &sts, + validFieldPath: path.Child("'foo'bar"), + }, + { + name: "Invalid 'foo'bar", + fieldPath: ".\\'foo\\'bar", + pathOfFieldPath: path, + schema: &sts, + errDetail: "does not refer to a valid field", + }, { name: "Invalid with whitespace", fieldPath: ". a", @@ -2987,7 +3006,7 @@ func TestValidateFieldPath(t *testing.T) { t.Errorf("expected error to contain: %v, but get: %v", tc.errDetail, err) } if tc.validFieldPath != nil && tc.validFieldPath.String() != path.Child(validField.String()).String() { - t.Errorf("expected %v, got %v", tc.validFieldPath, validField) + t.Errorf("expected %v, got %v", tc.validFieldPath, path.Child(validField.String())) } }) }