Folders: Add validation that folder is not a parent of itself (#101569)

pull/101589/head
Stephanie Hingtgen 10 months ago committed by GitHub
parent e933f7cf01
commit 7c35d741ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      pkg/registry/apis/folders/register.go
  2. 38
      pkg/registry/apis/folders/register_test.go
  3. 4
      pkg/services/folder/folderimpl/sqlstore.go
  4. 12
      pkg/services/folder/folderimpl/sqlstore_test.go
  5. 2
      pkg/services/folder/model.go

@ -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"

Loading…
Cancel
Save