IAM: Implement the update method for team bindings (#112788)
* implement the update method for team bindings * fix lint error * add integration tests * add integration test for non existing team binding * try to fix lint error
This commit is contained in:
@@ -37,6 +37,7 @@ type LegacyIdentityStore interface {
|
||||
CreateTeamMember(ctx context.Context, ns claims.NamespaceInfo, cmd CreateTeamMemberCommand) (*CreateTeamMemberResult, error)
|
||||
ListTeamBindings(ctx context.Context, ns claims.NamespaceInfo, query ListTeamBindingsQuery) (*ListTeamBindingsResult, error)
|
||||
ListTeamMembers(ctx context.Context, ns claims.NamespaceInfo, query ListTeamMembersQuery) (*ListTeamMembersResult, error)
|
||||
UpdateTeamMember(ctx context.Context, ns claims.NamespaceInfo, cmd UpdateTeamMemberCommand) (*UpdateTeamMemberResult, error)
|
||||
}
|
||||
|
||||
var _ LegacyIdentityStore = (*legacySQLStore)(nil)
|
||||
|
||||
@@ -85,6 +85,12 @@ func TestIdentityQueries(t *testing.T) {
|
||||
return &v
|
||||
}
|
||||
|
||||
updateTeamMember := func(cmd *UpdateTeamMemberCommand) sqltemplate.SQLTemplate {
|
||||
v := newUpdateTeamMember(nodb, cmd)
|
||||
v.SQLTemplate = mocks.NewTestingSQLTemplate()
|
||||
return &v
|
||||
}
|
||||
|
||||
listTeamMembers := func(q *ListTeamMembersQuery) sqltemplate.SQLTemplate {
|
||||
v := newListTeamMembers(nodb, q)
|
||||
v.SQLTemplate = mocks.NewTestingSQLTemplate()
|
||||
@@ -260,6 +266,16 @@ func TestIdentityQueries(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
sqlUpdateTeamMemberQuery: {
|
||||
{
|
||||
Name: "update_team_member_basic",
|
||||
Data: updateTeamMember(&UpdateTeamMemberCommand{
|
||||
UID: "team-member-1",
|
||||
Permission: team.PermissionTypeAdmin,
|
||||
Updated: legacysql.NewDBTime(time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)),
|
||||
}),
|
||||
},
|
||||
},
|
||||
sqlQueryTeamMembersTemplate: {
|
||||
{
|
||||
Name: "team_1_members_page_1",
|
||||
|
||||
@@ -301,6 +301,73 @@ func (s *legacySQLStore) ListTeamMembers(ctx context.Context, ns claims.Namespac
|
||||
return res, err
|
||||
}
|
||||
|
||||
type UpdateTeamMemberCommand struct {
|
||||
UID string
|
||||
Permission team.PermissionType
|
||||
Updated legacysql.DBTime
|
||||
}
|
||||
|
||||
type UpdateTeamMemberResult struct {
|
||||
UID string
|
||||
Permission team.PermissionType
|
||||
Updated legacysql.DBTime
|
||||
}
|
||||
|
||||
var sqlUpdateTeamMemberQuery = mustTemplate("update_team_member_query.sql")
|
||||
|
||||
func newUpdateTeamMember(sql *legacysql.LegacyDatabaseHelper, cmd *UpdateTeamMemberCommand) updateTeamMemberQuery {
|
||||
return updateTeamMemberQuery{
|
||||
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
|
||||
TeamMemberTable: sql.Table("team_member"),
|
||||
Command: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
type updateTeamMemberQuery struct {
|
||||
sqltemplate.SQLTemplate
|
||||
TeamMemberTable string
|
||||
Command *UpdateTeamMemberCommand
|
||||
}
|
||||
|
||||
func (r updateTeamMemberQuery) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *legacySQLStore) UpdateTeamMember(ctx context.Context, ns claims.NamespaceInfo, cmd UpdateTeamMemberCommand) (*UpdateTeamMemberResult, error) {
|
||||
now := time.Now().UTC()
|
||||
cmd.Updated = legacysql.NewDBTime(now)
|
||||
|
||||
sql, err := s.sql(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := newUpdateTeamMember(sql, &cmd)
|
||||
|
||||
var result UpdateTeamMemberResult
|
||||
err = sql.DB.GetSqlxSession().WithTransaction(ctx, func(st *session.SessionTx) error {
|
||||
teamMemberQuery, err := sqltemplate.Execute(sqlUpdateTeamMemberQuery, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute team member template %q: %w", sqlUpdateTeamMemberQuery.Name(), err)
|
||||
}
|
||||
|
||||
_, err = st.Exec(ctx, teamMemberQuery, req.GetArgs()...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update team member: %w", err)
|
||||
}
|
||||
|
||||
result = UpdateTeamMemberResult(cmd)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func scanMember(rows *sql.Rows) (TeamMember, error) {
|
||||
m := TeamMember{}
|
||||
err := rows.Scan(&m.ID, &m.UID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Name, &m.Email, &m.Username, &m.External, &m.Created, &m.Updated, &m.Permission)
|
||||
|
||||
Vendored
Executable
+4
@@ -0,0 +1,4 @@
|
||||
UPDATE `grafana`.`team_member`
|
||||
SET permission = 'Admin',
|
||||
updated = '2023-01-01 12:00:00'
|
||||
WHERE uid = 'team-member-1'
|
||||
Vendored
Executable
+4
@@ -0,0 +1,4 @@
|
||||
UPDATE "grafana"."team_member"
|
||||
SET permission = 'Admin',
|
||||
updated = '2023-01-01 12:00:00'
|
||||
WHERE uid = 'team-member-1'
|
||||
Vendored
Executable
+4
@@ -0,0 +1,4 @@
|
||||
UPDATE "grafana"."team_member"
|
||||
SET permission = 'Admin',
|
||||
updated = '2023-01-01 12:00:00'
|
||||
WHERE uid = 'team-member-1'
|
||||
@@ -0,0 +1,4 @@
|
||||
UPDATE {{ .Ident .TeamMemberTable }}
|
||||
SET permission = {{ .Arg .Command.Permission }},
|
||||
updated = {{ .Arg .Command.Updated }}
|
||||
WHERE uid = {{ .Arg .Command.UID }}
|
||||
@@ -407,6 +407,12 @@ func (b *IdentityAccessManagementAPIBuilder) Validate(ctx context.Context, a adm
|
||||
return fmt.Errorf("expected old object to be a Team, got %T", oldTeamObj)
|
||||
}
|
||||
return team.ValidateOnUpdate(ctx, typedObj, oldTeamObj)
|
||||
case *iamv0.TeamBinding:
|
||||
oldTeamBindingObj, ok := a.GetOldObject().(*iamv0.TeamBinding)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected old object to be a TeamBinding, got %T", oldTeamBindingObj)
|
||||
}
|
||||
return teambinding.ValidateOnUpdate(ctx, typedObj, oldTeamBindingObj)
|
||||
}
|
||||
return nil
|
||||
case admission.Delete:
|
||||
|
||||
@@ -73,7 +73,55 @@ func (l *LegacyBindingStore) ConvertToTable(ctx context.Context, object runtime.
|
||||
}
|
||||
|
||||
func (l *LegacyBindingStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||
return nil, false, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "update")
|
||||
if !l.enableAuthnMutation {
|
||||
return nil, false, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "update")
|
||||
}
|
||||
|
||||
ns, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
oldObj, err := l.Get(ctx, name, nil)
|
||||
if err != nil {
|
||||
return oldObj, false, err
|
||||
}
|
||||
|
||||
obj, err := objInfo.UpdatedObject(ctx, oldObj)
|
||||
if err != nil {
|
||||
return oldObj, false, err
|
||||
}
|
||||
|
||||
teamBindingObj, ok := obj.(*iamv0alpha1.TeamBinding)
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("expected TeamBinding object, got %T", obj)
|
||||
}
|
||||
|
||||
if updateValidation != nil {
|
||||
if err := updateValidation(ctx, obj, oldObj); err != nil {
|
||||
return oldObj, false, err
|
||||
}
|
||||
}
|
||||
|
||||
var permission team.PermissionType
|
||||
switch teamBindingObj.Spec.Permission {
|
||||
case iamv0alpha1.TeamBindingTeamPermissionAdmin:
|
||||
permission = team.PermissionTypeAdmin
|
||||
case iamv0alpha1.TeamBindingTeamPermissionMember:
|
||||
permission = team.PermissionTypeMember
|
||||
}
|
||||
|
||||
updateCmd := legacy.UpdateTeamMemberCommand{
|
||||
UID: teamBindingObj.Name,
|
||||
Permission: permission,
|
||||
}
|
||||
|
||||
_, err = l.store.UpdateTeamMember(ctx, ns, updateCmd)
|
||||
if err != nil {
|
||||
return oldObj, false, err
|
||||
}
|
||||
|
||||
return teamBindingObj, false, nil
|
||||
}
|
||||
|
||||
func (l *LegacyBindingStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
|
||||
|
||||
@@ -29,3 +29,28 @@ func ValidateOnCreate(ctx context.Context, obj *iamv0alpha1.TeamBinding) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateOnUpdate(ctx context.Context, obj, old *iamv0alpha1.TeamBinding) error {
|
||||
_, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return apierrors.NewUnauthorized("no identity found")
|
||||
}
|
||||
|
||||
if obj.Spec.TeamRef.Name != old.Spec.TeamRef.Name {
|
||||
return apierrors.NewBadRequest("teamRef is immutable")
|
||||
}
|
||||
|
||||
if obj.Spec.Subject.Name != old.Spec.Subject.Name {
|
||||
return apierrors.NewBadRequest("subject is immutable")
|
||||
}
|
||||
|
||||
if obj.Spec.External != old.Spec.External {
|
||||
return apierrors.NewBadRequest("external is immutable")
|
||||
}
|
||||
|
||||
if obj.Spec.Permission != iamv0alpha1.TeamBindingTeamPermissionAdmin && obj.Spec.Permission != iamv0alpha1.TeamBindingTeamPermissionMember {
|
||||
return apierrors.NewBadRequest("invalid permission")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -121,3 +121,242 @@ func TestValidateOnCreate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateOnUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
requester *identity.StaticRequester
|
||||
old *iamv0alpha1.TeamBinding
|
||||
obj *iamv0alpha1.TeamBinding
|
||||
want error
|
||||
}{
|
||||
{
|
||||
name: "valid update - permission change",
|
||||
requester: &identity.StaticRequester{
|
||||
Type: types.TypeUser,
|
||||
OrgRole: identity.RoleAdmin,
|
||||
},
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionMember,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "valid update - no changes",
|
||||
requester: &identity.StaticRequester{
|
||||
Type: types.TypeUser,
|
||||
OrgRole: identity.RoleAdmin,
|
||||
},
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "invalid update - teamRef change",
|
||||
requester: &identity.StaticRequester{
|
||||
Type: types.TypeUser,
|
||||
OrgRole: identity.RoleAdmin,
|
||||
},
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team-updated",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
want: apierrors.NewBadRequest("teamRef is immutable"),
|
||||
},
|
||||
{
|
||||
name: "invalid update - subject change",
|
||||
requester: &identity.StaticRequester{
|
||||
Type: types.TypeUser,
|
||||
OrgRole: identity.RoleAdmin,
|
||||
},
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user-updated",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
want: apierrors.NewBadRequest("subject is immutable"),
|
||||
},
|
||||
{
|
||||
name: "invalid update - external change",
|
||||
requester: &identity.StaticRequester{
|
||||
Type: types.TypeUser,
|
||||
OrgRole: identity.RoleAdmin,
|
||||
},
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: true,
|
||||
},
|
||||
},
|
||||
want: apierrors.NewBadRequest("external is immutable"),
|
||||
},
|
||||
{
|
||||
name: "invalid update - invalid permission",
|
||||
requester: &identity.StaticRequester{
|
||||
Type: types.TypeUser,
|
||||
OrgRole: identity.RoleAdmin,
|
||||
},
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: "invalid",
|
||||
},
|
||||
},
|
||||
want: apierrors.NewBadRequest("invalid permission"),
|
||||
},
|
||||
{
|
||||
name: "invalid update - no requester in context",
|
||||
requester: nil,
|
||||
old: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
obj: &iamv0alpha1.TeamBinding{
|
||||
Spec: iamv0alpha1.TeamBindingSpec{
|
||||
Subject: iamv0alpha1.TeamBindingspecSubject{
|
||||
Name: "test-user",
|
||||
},
|
||||
TeamRef: iamv0alpha1.TeamBindingTeamRef{
|
||||
Name: "test-team",
|
||||
},
|
||||
Permission: iamv0alpha1.TeamBindingTeamPermissionAdmin,
|
||||
External: false,
|
||||
},
|
||||
},
|
||||
want: apierrors.NewUnauthorized("no identity found"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ctx := identity.WithRequester(context.Background(), test.requester)
|
||||
err := ValidateOnUpdate(ctx, test.obj, test.old)
|
||||
assert.Equal(t, test.want, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func TestIntegrationTeamBindings(t *testing.T) {
|
||||
}
|
||||
|
||||
func doTeamBindingCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHelper, team *unstructured.Unstructured, user *unstructured.Unstructured) {
|
||||
t.Run("should create/get team binding using the new APIs", func(t *testing.T) {
|
||||
t.Run("should create/update/get team binding using the new APIs", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
@@ -110,9 +110,33 @@ func doTeamBindingCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHel
|
||||
require.Equal(t, team.GetName(), fetchedSpec["teamRef"].(map[string]interface{})["name"])
|
||||
require.Equal(t, "admin", fetchedSpec["permission"])
|
||||
require.Equal(t, false, fetchedSpec["external"])
|
||||
|
||||
require.Equal(t, createdUID, fetched.GetName())
|
||||
require.Equal(t, "default", fetched.GetNamespace())
|
||||
|
||||
// Update the team binding
|
||||
toUpdate := toCreate.DeepCopy()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["permission"] = "member"
|
||||
updated, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updated)
|
||||
|
||||
updatedSpec := updated.Object["spec"].(map[string]interface{})
|
||||
require.Equal(t, createdUID, updated.GetName())
|
||||
require.Equal(t, user.GetName(), updatedSpec["subject"].(map[string]interface{})["name"])
|
||||
require.Equal(t, team.GetName(), updatedSpec["teamRef"].(map[string]interface{})["name"])
|
||||
require.Equal(t, "member", updatedSpec["permission"])
|
||||
require.Equal(t, false, updatedSpec["external"])
|
||||
|
||||
// Get the team binding
|
||||
fetched, err = teamBindingClient.Resource.Get(ctx, createdUID, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, fetched)
|
||||
|
||||
fetchedSpec = fetched.Object["spec"].(map[string]interface{})
|
||||
require.Equal(t, user.GetName(), fetchedSpec["subject"].(map[string]interface{})["name"])
|
||||
require.Equal(t, team.GetName(), fetchedSpec["teamRef"].(map[string]interface{})["name"])
|
||||
require.Equal(t, "member", fetchedSpec["permission"])
|
||||
require.Equal(t, false, fetchedSpec["external"])
|
||||
require.Equal(t, createdUID, fetched.GetName())
|
||||
})
|
||||
|
||||
t.Run("should not be able to create team binding when using a user with insufficient permissions", func(t *testing.T) {
|
||||
@@ -201,6 +225,152 @@ func doTeamBindingCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHel
|
||||
require.Equal(t, int32(400), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "invalid permission")
|
||||
})
|
||||
|
||||
t.Run("should not be able to update team binding with insufficient permissions", func(t *testing.T) {
|
||||
for _, u := range []apis.User{
|
||||
helper.Org1.Editor,
|
||||
helper.Org1.Viewer,
|
||||
} {
|
||||
t.Run(fmt.Sprintf("with basic role_%s", u.Identity.GetOrgRole()), func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: u,
|
||||
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
|
||||
GVR: gvrTeamBindings,
|
||||
})
|
||||
|
||||
toUpdate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toUpdate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["permission"] = "member"
|
||||
_, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(403), statusErr.ErrStatus.Code)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should not be able to update team binding if the team binding does not exist", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
|
||||
GVR: gvrTeamBindings,
|
||||
})
|
||||
|
||||
toUpdate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toUpdate.Object["metadata"].(map[string]interface{})["name"] = "invalid-team-binding-name"
|
||||
toUpdate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
_, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(404), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "not found")
|
||||
})
|
||||
|
||||
t.Run("should not be able to update team binding with teamRef change", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
|
||||
GVR: gvrTeamBindings,
|
||||
})
|
||||
|
||||
// Create the team binding if it doesn't already exist
|
||||
toCreate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toCreate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toCreate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
_, _ = teamBindingClient.Resource.Create(ctx, toCreate, metav1.CreateOptions{})
|
||||
|
||||
toUpdate := toCreate.DeepCopy()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = "test-team-2"
|
||||
_, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(400), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "teamRef is immutable")
|
||||
})
|
||||
|
||||
t.Run("should not be able to update team binding with subject change", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
|
||||
GVR: gvrTeamBindings,
|
||||
})
|
||||
|
||||
// Create the team binding if it doesn't already exist
|
||||
toCreate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toCreate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toCreate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
_, _ = teamBindingClient.Resource.Create(ctx, toCreate, metav1.CreateOptions{})
|
||||
|
||||
toUpdate := toCreate.DeepCopy()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = "test-user-2"
|
||||
|
||||
_, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(400), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "subject is immutable")
|
||||
})
|
||||
|
||||
t.Run("should not be able to update team binding with external change", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
|
||||
GVR: gvrTeamBindings,
|
||||
})
|
||||
|
||||
// Create the team binding if it doesn't already exist
|
||||
toCreate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toCreate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toCreate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
_, _ = teamBindingClient.Resource.Create(ctx, toCreate, metav1.CreateOptions{})
|
||||
|
||||
toUpdate := toCreate.DeepCopy()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["external"] = true
|
||||
_, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(400), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "external is immutable")
|
||||
})
|
||||
|
||||
t.Run("should not be able to update team binding with invalid permission", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
|
||||
GVR: gvrTeamBindings,
|
||||
})
|
||||
|
||||
// Create the team binding if it doesn't already exist
|
||||
toCreate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toCreate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toCreate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
_, _ = teamBindingClient.Resource.Create(ctx, toCreate, metav1.CreateOptions{})
|
||||
|
||||
toUpdate := helper.LoadYAMLOrJSONFile("testdata/teambinding-test-create-v0.yaml")
|
||||
toUpdate.Object["spec"].(map[string]interface{})["subject"].(map[string]interface{})["name"] = user.GetName()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["teamRef"].(map[string]interface{})["name"] = team.GetName()
|
||||
toUpdate.Object["spec"].(map[string]interface{})["permission"] = "invalid"
|
||||
_, err := teamBindingClient.Resource.Update(ctx, toUpdate, metav1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(400), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "invalid permission")
|
||||
})
|
||||
}
|
||||
|
||||
func doTeamBindingCRUDTestsUsingTheLegacyAPIs(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWriterMode) {
|
||||
|
||||
Reference in New Issue
Block a user