Folders: Add validation that folder is not a parent of itself (#101569)
This commit is contained in:
@@ -297,6 +297,10 @@ func (b *FolderAPIBuilder) validateOnCreate(ctx context.Context, id string, obj
|
||||
return dashboards.ErrFolderTitleEmpty
|
||||
}
|
||||
|
||||
if f.Name == getParent(obj) {
|
||||
return folder.ErrFolderCannotBeParentOfItself
|
||||
}
|
||||
|
||||
_, err := b.checkFolderMaxDepth(ctx, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
@@ -26,13 +27,22 @@ func TestFolderAPIBuilder_Validate_Create(t *testing.T) {
|
||||
name string
|
||||
}
|
||||
|
||||
circularObj := &v0alpha1.Folder{
|
||||
initialMaxDepth := folderValidationRules.maxDepth
|
||||
folderValidationRules.maxDepth = 2
|
||||
defer func() { folderValidationRules.maxDepth = initialMaxDepth }()
|
||||
deepFolder := &v0alpha1.Folder{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "foo",
|
||||
},
|
||||
}
|
||||
circularObj.Name = "valid-name"
|
||||
circularObj.Annotations = map[string]string{"grafana.app/folder": "valid-name"}
|
||||
deepFolder.Name = "valid-parent"
|
||||
deepFolder.Annotations = map[string]string{"grafana.app/folder": "valid-grandparent"}
|
||||
parentFolder := &v0alpha1.Folder{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "foo-grandparent",
|
||||
},
|
||||
}
|
||||
deepFolder.Name = "valid-grandparent"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -71,12 +81,15 @@ func TestFolderAPIBuilder_Validate_Create(t *testing.T) {
|
||||
Title: "foo",
|
||||
},
|
||||
},
|
||||
annotations: map[string]string{"grafana.app/folder": "valid-name"},
|
||||
annotations: map[string]string{"grafana.app/folder": "valid-parent"},
|
||||
name: "valid-name",
|
||||
},
|
||||
setupFn: func(m *mock.Mock) {
|
||||
m.On("Get", mock.Anything, "valid-name", mock.Anything).Return(
|
||||
circularObj,
|
||||
m.On("Get", mock.Anything, "valid-parent", mock.Anything).Return(
|
||||
deepFolder,
|
||||
nil)
|
||||
m.On("Get", mock.Anything, "valid-grandparent", mock.Anything).Return(
|
||||
parentFolder,
|
||||
nil)
|
||||
},
|
||||
err: folder.ErrMaximumDepthReached,
|
||||
@@ -93,6 +106,19 @@ func TestFolderAPIBuilder_Validate_Create(t *testing.T) {
|
||||
},
|
||||
err: dashboards.ErrFolderTitleEmpty,
|
||||
},
|
||||
{
|
||||
name: "should return error if folder is a parent of itself",
|
||||
input: input{
|
||||
annotations: map[string]string{utils.AnnoKeyFolder: "myself"},
|
||||
obj: &v0alpha1.Folder{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "title",
|
||||
},
|
||||
},
|
||||
name: "myself",
|
||||
},
|
||||
err: folder.ErrFolderCannotBeParentOfItself,
|
||||
},
|
||||
}
|
||||
|
||||
s := (grafanarest.Storage)(nil)
|
||||
|
||||
@@ -39,6 +39,10 @@ func (ss *FolderStoreImpl) Create(ctx context.Context, cmd folder.CreateFolderCo
|
||||
return nil, folder.ErrBadRequest.Errorf("missing UID")
|
||||
}
|
||||
|
||||
if cmd.UID == cmd.ParentUID {
|
||||
return nil, folder.ErrFolderCannotBeParentOfItself
|
||||
}
|
||||
|
||||
var foldr *folder.Folder
|
||||
/*
|
||||
version := 1
|
||||
|
||||
@@ -60,6 +60,18 @@ func TestIntegrationCreate(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("creating a folder with itself as a parent should fail", func(t *testing.T) {
|
||||
uid := util.GenerateShortUID()
|
||||
_, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
|
||||
Title: folderTitle,
|
||||
OrgID: orgID,
|
||||
ParentUID: uid,
|
||||
Description: folderDsc,
|
||||
UID: uid,
|
||||
})
|
||||
require.ErrorIs(t, err, folder.ErrFolderCannotBeParentOfItself)
|
||||
})
|
||||
|
||||
t.Run("creating a folder without providing a parent should default to the empty parent folder", func(t *testing.T) {
|
||||
uid := util.GenerateShortUID()
|
||||
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package folder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -20,6 +21,7 @@ var ErrInternal = errutil.Internal("folder.internal")
|
||||
var ErrCircularReference = errutil.BadRequest("folder.circular-reference", errutil.WithPublicMessage("Circular reference detected"))
|
||||
var ErrTargetRegistrySrvConflict = errutil.Internal("folder.target-registry-srv-conflict")
|
||||
var ErrFolderNotEmpty = errutil.BadRequest("folder.not-empty", errutil.WithPublicMessage("Folder cannot be deleted: folder is not empty"))
|
||||
var ErrFolderCannotBeParentOfItself = errors.New("folder cannot be parent of itself")
|
||||
|
||||
const (
|
||||
GeneralFolderUID = "general"
|
||||
|
||||
Reference in New Issue
Block a user