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:
Mihai Doarna
2025-10-23 11:39:38 +03:00
committed by GitHub
parent 24d3c88c09
commit 3076f7a9b9
12 changed files with 592 additions and 4 deletions
+1
View File
@@ -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)
+16
View File
@@ -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)
@@ -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 "grafana"."team_member"
SET permission = 'Admin',
updated = '2023-01-01 12:00:00'
WHERE uid = 'team-member-1'
@@ -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 }}
+6
View File
@@ -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:
+49 -1
View File
@@ -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) {