mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
[Folder] Add general UID validation (#95549)
* Add general UID validation * [REVIEW] group all folder validation rules into struct * Fix test
This commit is contained in:
parent
3e1046ee2e
commit
55afbdc6be
@ -36,6 +36,14 @@ var resourceInfo = v0alpha1.FolderResourceInfo
|
||||
var errNoUser = errors.New("valid user is required")
|
||||
var errNoResource = errors.New("resource name is required")
|
||||
|
||||
var folderValidationRules = struct {
|
||||
maxDepth int
|
||||
invalidNames []string
|
||||
}{
|
||||
maxDepth: 4,
|
||||
invalidNames: []string{"general"},
|
||||
}
|
||||
|
||||
// This is used just so wire has something unique to return
|
||||
type FolderAPIBuilder struct {
|
||||
gv schema.GroupVersion
|
||||
@ -183,10 +191,6 @@ func (b *FolderAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
})
|
||||
}
|
||||
|
||||
func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorizerParams, error) {
|
||||
verb := attr.GetVerb()
|
||||
name := attr.GetName()
|
||||
@ -220,3 +224,38 @@ func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorize
|
||||
}
|
||||
return &authorizerParams{evaluator: eval, user: user}, nil
|
||||
}
|
||||
|
||||
func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
|
||||
// name cannot be called "general"
|
||||
id := a.GetName()
|
||||
for _, invalidName := range folderValidationRules.invalidNames {
|
||||
if id == invalidName {
|
||||
return dashboards.ErrFolderInvalidUID
|
||||
}
|
||||
}
|
||||
|
||||
obj := a.GetObject()
|
||||
|
||||
for i := 0; i <= folderValidationRules.maxDepth+1; i++ {
|
||||
parent := getParent(obj)
|
||||
if parent == "" {
|
||||
break
|
||||
}
|
||||
if i == folderValidationRules.maxDepth+1 {
|
||||
return folder.ErrMaximumDepthReached
|
||||
}
|
||||
|
||||
// TODO: investigate the best way to get a folder by name, considering validate is called before the storage layer
|
||||
// parent, err := getFolderByNameSomehow()
|
||||
// obj = parent
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getParent(o runtime.Object) string {
|
||||
meta, err := utils.MetaAccessor(o)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return meta.GetFolder()
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
@ -13,6 +14,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
@ -114,3 +117,58 @@ func TestFolderAPIBuilder_getAuthorizerFunc(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFolderAPIBuilder_Validate(t *testing.T) {
|
||||
type input struct {
|
||||
obj *unstructured.Unstructured
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
input input
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "should return error when nameis invalid",
|
||||
input: input{
|
||||
obj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"meta": map[string]interface{}{"name": folderValidationRules.invalidNames[0]},
|
||||
},
|
||||
},
|
||||
name: folderValidationRules.invalidNames[0],
|
||||
},
|
||||
err: dashboards.ErrFolderInvalidUID,
|
||||
},
|
||||
}
|
||||
|
||||
b := &FolderAPIBuilder{
|
||||
gv: resourceInfo.GroupVersion(),
|
||||
features: nil,
|
||||
namespacer: func(_ int64) string { return "123" },
|
||||
folderSvc: foldertest.NewFakeService(),
|
||||
accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders"), zanzana.NewNoopClient()),
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := b.Validate(context.Background(), admission.NewAttributesRecord(
|
||||
tt.input.obj,
|
||||
nil,
|
||||
v0alpha1.SchemeGroupVersion.WithKind("folder"),
|
||||
"stacks-123",
|
||||
tt.input.name,
|
||||
v0alpha1.SchemeGroupVersion.WithResource("folders"),
|
||||
"",
|
||||
"create",
|
||||
nil,
|
||||
true,
|
||||
&user.SignedInUser{},
|
||||
), nil)
|
||||
|
||||
if tt.err != nil {
|
||||
require.ErrorIs(t, err, tt.err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user