mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-05 00:54:01 -04:00
[management] Prevent deletion of groups linked to flow groups (#5439)
This commit is contained in:
@@ -425,6 +425,11 @@ func (am *DefaultAccountManager) DeleteGroups(ctx context.Context, accountID, us
|
|||||||
var groupIDsToDelete []string
|
var groupIDsToDelete []string
|
||||||
var deletedGroups []*types.Group
|
var deletedGroups []*types.Group
|
||||||
|
|
||||||
|
extraSettings, err := am.settingsManager.GetExtraSettings(ctx, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = am.Store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
err = am.Store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
||||||
for _, groupID := range groupIDs {
|
for _, groupID := range groupIDs {
|
||||||
group, err := transaction.GetGroupByID(ctx, store.LockingStrengthNone, accountID, groupID)
|
group, err := transaction.GetGroupByID(ctx, store.LockingStrengthNone, accountID, groupID)
|
||||||
@@ -433,7 +438,7 @@ func (am *DefaultAccountManager) DeleteGroups(ctx context.Context, accountID, us
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateDeleteGroup(ctx, transaction, group, userID); err != nil {
|
if err = validateDeleteGroup(ctx, transaction, group, userID, extraSettings.FlowGroups); err != nil {
|
||||||
allErrors = errors.Join(allErrors, err)
|
allErrors = errors.Join(allErrors, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -621,7 +626,7 @@ func validateNewGroup(ctx context.Context, transaction store.Store, accountID st
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateDeleteGroup(ctx context.Context, transaction store.Store, group *types.Group, userID string) error {
|
func validateDeleteGroup(ctx context.Context, transaction store.Store, group *types.Group, userID string, flowGroups []string) error {
|
||||||
// disable a deleting integration group if the initiator is not an admin service user
|
// disable a deleting integration group if the initiator is not an admin service user
|
||||||
if group.Issued == types.GroupIssuedIntegration {
|
if group.Issued == types.GroupIssuedIntegration {
|
||||||
executingUser, err := transaction.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
executingUser, err := transaction.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
||||||
@@ -641,6 +646,10 @@ func validateDeleteGroup(ctx context.Context, transaction store.Store, group *ty
|
|||||||
return &GroupLinkError{"network resource", group.Resources[0].ID}
|
return &GroupLinkError{"network resource", group.Resources[0].ID}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if slices.Contains(flowGroups, group.ID) {
|
||||||
|
return &GroupLinkError{"settings", "traffic event logging"}
|
||||||
|
}
|
||||||
|
|
||||||
if isLinked, linkedRoute := isGroupLinkedToRoute(ctx, transaction, group.AccountID, group.ID); isLinked {
|
if isLinked, linkedRoute := isGroupLinkedToRoute(ctx, transaction, group.AccountID, group.ID); isLinked {
|
||||||
return &GroupLinkError{"route", string(linkedRoute.NetID)}
|
return &GroupLinkError{"route", string(linkedRoute.NetID)}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -26,6 +27,7 @@ import (
|
|||||||
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
||||||
peer2 "github.com/netbirdio/netbird/management/server/peer"
|
peer2 "github.com/netbirdio/netbird/management/server/peer"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"github.com/netbirdio/netbird/management/server/permissions"
|
||||||
|
"github.com/netbirdio/netbird/management/server/settings"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
"github.com/netbirdio/netbird/route"
|
"github.com/netbirdio/netbird/route"
|
||||||
@@ -284,6 +286,67 @@ func TestDefaultAccountManager_DeleteGroups(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultAccountManager_DeleteGroupLinkedToFlowGroup(t *testing.T) {
|
||||||
|
am, _, err := createManager(t)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
settingsMock := settings.NewMockManager(ctrl)
|
||||||
|
settingsMock.EXPECT().
|
||||||
|
GetExtraSettings(gomock.Any(), gomock.Any()).
|
||||||
|
Return(&types.ExtraSettings{FlowGroups: []string{"grp-for-flow"}}, nil).
|
||||||
|
AnyTimes()
|
||||||
|
settingsMock.EXPECT().
|
||||||
|
UpdateExtraSettings(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
|
Return(false, nil).
|
||||||
|
AnyTimes()
|
||||||
|
am.settingsManager = settingsMock
|
||||||
|
|
||||||
|
_, account, err := initTestGroupAccount(am)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
grp := &types.Group{
|
||||||
|
ID: "grp-for-flow",
|
||||||
|
AccountID: account.Id,
|
||||||
|
Name: "Group for flow",
|
||||||
|
Issued: types.GroupIssuedAPI,
|
||||||
|
Peers: make([]string, 0),
|
||||||
|
}
|
||||||
|
require.NoError(t, am.CreateGroup(context.Background(), account.Id, groupAdminUserID, grp))
|
||||||
|
|
||||||
|
err = am.DeleteGroup(context.Background(), account.Id, groupAdminUserID, "grp-for-flow")
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
var gErr *GroupLinkError
|
||||||
|
require.ErrorAs(t, err, &gErr)
|
||||||
|
assert.Equal(t, "settings", gErr.Resource)
|
||||||
|
assert.Equal(t, "traffic event logging", gErr.Name)
|
||||||
|
|
||||||
|
group, err := am.GetGroup(context.Background(), account.Id, "grp-for-flow", groupAdminUserID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, group)
|
||||||
|
|
||||||
|
regularGrp := &types.Group{
|
||||||
|
ID: "grp-regular",
|
||||||
|
AccountID: account.Id,
|
||||||
|
Name: "Regular group",
|
||||||
|
Issued: types.GroupIssuedAPI,
|
||||||
|
Peers: make([]string, 0),
|
||||||
|
}
|
||||||
|
err = am.CreateGroup(context.Background(), account.Id, groupAdminUserID, regularGrp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = am.DeleteGroups(context.Background(), account.Id, groupAdminUserID, []string{"grp-for-flow", "grp-regular"})
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
group, err = am.GetGroup(context.Background(), account.Id, "grp-for-flow", groupAdminUserID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, group)
|
||||||
|
|
||||||
|
_, err = am.GetGroup(context.Background(), account.Id, "grp-regular", groupAdminUserID)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *types.Account, error) {
|
func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *types.Account, error) {
|
||||||
accountID := "testingAcc"
|
accountID := "testingAcc"
|
||||||
domain := "example.com"
|
domain := "example.com"
|
||||||
|
|||||||
Reference in New Issue
Block a user