Files
grafana/pkg/registry/apis/iam/serviceaccount/validate_test.go
MisiandGabriel MABILLE 29551a6edf IAM: Implement Delete in Service Account API (#110584)
* wip

* IAM: Create Service Account

* Add dual writer

* Update openapi_test.go

* Add integration tests

* Add sql tests

* Add Role to SA spec, add validation, add DBTime, add tests

* Format, update test

* Fixes

* Add check for External

* wip

* Fix merge

* wip

* Use plugin name instead of title for ext svc account login

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* Remove OrgID from DeleteUserCommand

* Use the new authorizer

* Fix tests

* cleanup

* Move test to enterprise

* Revert unnecessary change

* Address feedback

* Revert "Address feedback"

This reverts commit 8ab9559076.

---------

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
2025-09-16 15:39:01 +02:00

196 lines
5.3 KiB
Go

package serviceaccount
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/authlib/types"
iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/services/serviceaccounts"
)
func TestValidateOnCreate(t *testing.T) {
tests := []struct {
name string
serviceAccount *iamv0alpha1.ServiceAccount
requester *identity.StaticRequester
expectError bool
errorContains string
}{
{
name: "valid service account with user requester",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: "Test Service Account",
Role: iamv0alpha1.ServiceAccountOrgRoleViewer,
},
},
requester: &identity.StaticRequester{
Type: types.TypeUser,
OrgRole: identity.RoleAdmin,
},
expectError: false,
},
{
name: "empty title",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: "",
Role: iamv0alpha1.ServiceAccountOrgRoleViewer,
},
},
requester: &identity.StaticRequester{
Type: types.TypeUser,
OrgRole: identity.RoleAdmin,
},
expectError: true,
errorContains: "service account must have a title",
},
{
name: "invalid role",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: "Test Service Account",
Role: "InvalidRole",
},
},
requester: &identity.StaticRequester{
Type: types.TypeUser,
OrgRole: identity.RoleAdmin,
},
expectError: true,
errorContains: "invalid role",
},
{
name: "role higher than requester's role",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: "Test Service Account",
Role: iamv0alpha1.ServiceAccountOrgRoleAdmin,
},
},
requester: &identity.StaticRequester{
Type: types.TypeUser,
OrgRole: identity.RoleViewer,
},
expectError: true,
errorContains: "cannot assign a role higher than user's role",
},
{
name: "external service account - valid",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: serviceaccounts.ExtSvcPrefix + "test-plugin",
Role: iamv0alpha1.ServiceAccountOrgRoleNone,
Plugin: "test-plugin",
},
},
requester: &identity.StaticRequester{
Type: types.TypeAccessPolicy,
OrgRole: identity.RoleAdmin,
},
expectError: false,
},
{
name: "external service account - invalid title prefix",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: "invalid-prefix-test",
Role: iamv0alpha1.ServiceAccountOrgRoleNone,
Plugin: "test",
},
},
requester: &identity.StaticRequester{
Type: types.TypeAccessPolicy,
OrgRole: identity.RoleAdmin,
},
expectError: true,
errorContains: "title of external service accounts must start with " + serviceaccounts.ExtSvcPrefix,
},
{
name: "external service account - invalid title suffix",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: serviceaccounts.ExtSvcPrefix + "wrong-suffix",
Role: iamv0alpha1.ServiceAccountOrgRoleNone,
Plugin: "test",
},
},
requester: &identity.StaticRequester{
Type: types.TypeAccessPolicy,
OrgRole: identity.RoleAdmin,
},
expectError: true,
errorContains: "title of external service accounts must end with test",
},
{
name: "external service account - non-access-policy requester",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: serviceaccounts.ExtSvcPrefix + "test-test",
Role: iamv0alpha1.ServiceAccountOrgRoleNone,
Plugin: "test",
},
},
requester: &identity.StaticRequester{
Type: types.TypeUser,
OrgRole: identity.RoleAdmin,
},
expectError: true,
errorContains: "only service identities can create external service accounts",
},
{
name: "external service account - role not None",
serviceAccount: &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: serviceaccounts.ExtSvcPrefix + "test-test",
Role: iamv0alpha1.ServiceAccountOrgRoleViewer,
Plugin: "test",
},
},
requester: &identity.StaticRequester{
Type: types.TypeAccessPolicy,
OrgRole: identity.RoleAdmin,
},
expectError: true,
errorContains: "external service accounts must have role None",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := identity.WithRequester(
context.Background(),
tt.requester,
)
err := ValidateOnCreate(ctx, tt.serviceAccount)
if tt.expectError {
require.Error(t, err)
if tt.errorContains != "" {
require.Contains(t, err.Error(), tt.errorContains)
}
} else {
require.NoError(t, err)
}
})
}
}
func TestValidateOnCreate_NoRequester(t *testing.T) {
serviceAccount := &iamv0alpha1.ServiceAccount{
Spec: iamv0alpha1.ServiceAccountSpec{
Title: "Test Service Account",
Role: iamv0alpha1.ServiceAccountOrgRoleViewer,
},
}
err := ValidateOnCreate(context.Background(), serviceAccount)
require.Error(t, err)
require.Contains(t, err.Error(), "no identity found")
}