Validation: Move validation into apimachinery package (#111736)
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/validation"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
)
|
||||
|
||||
@@ -17,17 +18,17 @@ func verifyRequestKey(key *resourcepb.ResourceKey) *resourcepb.ErrorResult {
|
||||
if key.Resource == "" {
|
||||
return NewBadRequestError("request key is missing resource")
|
||||
}
|
||||
if err := validateName(key.Name); err != nil {
|
||||
return NewBadRequestError(fmt.Sprintf("name '%s' is invalid: '%s'", key.Name, err))
|
||||
if err := validation.IsValidNamespace(key.Namespace); err != nil {
|
||||
return NewBadRequestError(err[0])
|
||||
}
|
||||
if err := validateNamespace(key.Namespace); err != nil {
|
||||
return NewBadRequestError(fmt.Sprintf("namespace '%s' is invalid: '%s'", key.Namespace, err))
|
||||
if err := validation.IsValidGroup(key.Group); err != nil {
|
||||
return NewBadRequestError(err[0])
|
||||
}
|
||||
if err := validateGroup(key.Group); err != nil {
|
||||
return NewBadRequestError(fmt.Sprintf("group '%s' is invalid: '%s'", key.Group, err))
|
||||
if err := validation.IsValidateResource(key.Resource); err != nil {
|
||||
return NewBadRequestError(err[0])
|
||||
}
|
||||
if err := validateResource(key.Resource); err != nil {
|
||||
return NewBadRequestError(fmt.Sprintf("resource '%s' is invalid: '%s'", key.Resource, err))
|
||||
if err := validation.IsValidGrafanaName(key.Name); err != nil {
|
||||
return NewBadRequestError(err[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func TestVerifyRequestKey(t *testing.T) {
|
||||
invalidNamespace := "(((((default"
|
||||
invalidName := " " // only spaces
|
||||
|
||||
namespaceTooLong := strings.Repeat("a", MaxNameLength+1)
|
||||
namespaceTooLong := strings.Repeat("a", 61)
|
||||
nameTooLong := strings.Repeat("a", 300)
|
||||
|
||||
tests := []struct {
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/grafana/dskit/ring"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/validation"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
"github.com/grafana/grafana/pkg/util/scheduler"
|
||||
@@ -523,8 +524,8 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *resour
|
||||
return nil, NewBadRequestError(
|
||||
fmt.Sprintf("key/name do not match (key: %s, name: %s)", key.Name, obj.GetName()))
|
||||
}
|
||||
if err := validateName(obj.GetName()); err != nil {
|
||||
return nil, err
|
||||
if errs := validation.IsValidGrafanaName(obj.GetName()); err != nil {
|
||||
return nil, NewBadRequestError(errs[0])
|
||||
}
|
||||
|
||||
// For folder moves, we need to check permissions on both folders
|
||||
|
||||
@@ -365,7 +365,7 @@ func TestSimpleServer(t *testing.T) {
|
||||
|
||||
invalidQualifiedNames := []string{
|
||||
"", // empty
|
||||
strings.Repeat("1", MaxNameLength+1), // too long
|
||||
strings.Repeat("1", 260), // too long
|
||||
" ", // only spaces
|
||||
"f8cc010c.ee72.4681;89d2+d46e1bd47d33", // invalid chars
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
)
|
||||
|
||||
const MaxNameLength = 253
|
||||
const MaxNamespaceLength = 40
|
||||
const MaxGroupLength = 60
|
||||
const MaxResourceLength = 40
|
||||
|
||||
var validNameCharPattern = `a-zA-Z0-9:\-\_\.`
|
||||
var validNamePattern = regexp.MustCompile(`^[` + validNameCharPattern + `]*$`).MatchString
|
||||
|
||||
func validateName(name string) *resourcepb.ErrorResult {
|
||||
if len(name) == 0 {
|
||||
return NewBadRequestError("name is too short")
|
||||
}
|
||||
if len(name) > MaxNameLength {
|
||||
return NewBadRequestError("name is too long")
|
||||
}
|
||||
if !validNamePattern(name) {
|
||||
return NewBadRequestError("name includes invalid characters")
|
||||
}
|
||||
// In standard k8s, it must not start with a number
|
||||
// however that would force us to update many many many existing resources
|
||||
// so we will be slightly more lenient than standard k8s
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateNamespace(value string) *resourcepb.ErrorResult {
|
||||
if len(value) == 0 {
|
||||
// empty namespace is allowed (means cluster-scoped)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(value) > MaxNamespaceLength {
|
||||
return NewBadRequestError("value is too long")
|
||||
}
|
||||
|
||||
err := validation.IsQualifiedName(value)
|
||||
if len(err) > 0 {
|
||||
return NewBadRequestError(fmt.Sprintf("name is not a valid qualified name: %+v", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateGroup(value string) *resourcepb.ErrorResult {
|
||||
if len(value) == 0 {
|
||||
return NewBadRequestError("value is too short")
|
||||
}
|
||||
|
||||
if len(value) > MaxGroupLength {
|
||||
return NewBadRequestError("value is too long")
|
||||
}
|
||||
|
||||
err := validation.IsQualifiedName(value)
|
||||
if len(err) > 0 {
|
||||
return NewBadRequestError(fmt.Sprintf("name is not a valid qualified name: %+v", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateResource(value string) *resourcepb.ErrorResult {
|
||||
if len(value) == 0 {
|
||||
return NewBadRequestError("value is too short")
|
||||
}
|
||||
|
||||
if len(value) > MaxResourceLength {
|
||||
return NewBadRequestError("value is too long")
|
||||
}
|
||||
|
||||
err := validation.IsQualifiedName(value)
|
||||
if len(err) > 0 {
|
||||
return NewBadRequestError(fmt.Sprintf("name is not a valid qualified name: %+v", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNameValidation(t *testing.T) {
|
||||
require.NotNil(t, validateName("")) // too short
|
||||
require.NotNil(t, validateName(strings.Repeat("0", 254))) // too long (max 253)
|
||||
|
||||
// OK
|
||||
require.Nil(t, validateName("a"))
|
||||
require.Nil(t, validateName("hello-world"))
|
||||
require.Nil(t, validateName("hello.world"))
|
||||
require.Nil(t, validateName("hello_world"))
|
||||
require.Nil(t, validateName("hello:world"))
|
||||
|
||||
// Bad characters
|
||||
require.NotNil(t, validateName("hello world"))
|
||||
require.NotNil(t, validateName("hello!"))
|
||||
require.NotNil(t, validateName("hello~"))
|
||||
require.NotNil(t, validateName("hello "))
|
||||
require.NotNil(t, validateName("hello*"))
|
||||
require.NotNil(t, validateName("hello+"))
|
||||
require.NotNil(t, validateName("hello="))
|
||||
require.NotNil(t, validateName("hello%"))
|
||||
}
|
||||
Reference in New Issue
Block a user