Skip to content

Commit 01242f2

Browse files
authored
[CLD-3125] remove explicit scope (#361)
1 parent 72cd259 commit 01242f2

5 files changed

Lines changed: 649 additions & 599 deletions

File tree

app/role.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package app
33
import (
44
"context"
55
"fmt"
6+
"slices"
67
"strings"
78

89
"github.com/temporalio/tcld/protogen/api/auth/v1"
@@ -21,6 +22,7 @@ func getAccountActionGroups() []string {
2122
rv = append(rv, n)
2223
}
2324
}
25+
slices.Sort(rv)
2426
return rv
2527
}
2628

@@ -31,6 +33,7 @@ func getNamespaceActionGroups() []string {
3133
rv = append(rv, n)
3234
}
3335
}
36+
slices.Sort(rv)
3437
return rv
3538
}
3639

app/serviceaccount.go

Lines changed: 64 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,8 @@ const (
1313
serviceAccountIDFlagName = "service-account-id"
1414
serviceAccountNameFlagName = "name"
1515
serviceAccountDescriptionFlagName = "description"
16-
serviceAccountScopeTypeFlagName = "scope-type"
17-
serviceAccountScopeIDFlagName = "scope-id"
1816
)
1917

20-
var (
21-
scopeTypes = map[string]auth.ServiceAccountScopeType{
22-
"namespace": auth.SERVICE_ACCOUNT_SCOPE_TYPE_NAMESPACE,
23-
}
24-
)
25-
26-
func getScopeTypes() []string {
27-
var types []string
28-
for st := range scopeTypes {
29-
types = append(types, st)
30-
}
31-
return types
32-
}
33-
3418
var (
3519
serviceAccountIDFlag = &cli.StringFlag{
3620
Name: serviceAccountIDFlagName,
@@ -226,73 +210,40 @@ func NewServiceAccountCommand(getServiceAccountClientFn GetServiceAccountClientF
226210
serviceAccountNameFlag,
227211
RequestIDFlag,
228212
&cli.StringFlag{
229-
Name: accountRoleFlagName,
230-
Usage: fmt.Sprintf("The account role to set on the service account; valid types are: %v", accountActionGroups),
231-
Aliases: []string{"ar"},
213+
Name: accountRoleFlagName,
214+
Usage: fmt.Sprintf("The account role to set on the service account; valid types are: %v", accountActionGroups),
215+
Required: true,
216+
Aliases: []string{"ar"},
232217
},
233218
&cli.StringSliceFlag{
234219
Name: namespacePermissionFlagName,
235-
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"namespace=permission\"; valid types are: %v", namespaceActionGroups),
220+
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"<namespace>=<permission>\"; valid types are: %v", namespaceActionGroups),
236221
Aliases: []string{"np"},
237222
},
238-
&cli.StringFlag{
239-
Name: serviceAccountScopeTypeFlagName,
240-
Usage: fmt.Sprintf("The service account scope type; valid types are: %v", getScopeTypes()),
241-
Aliases: []string{"st"},
242-
},
243-
&cli.StringFlag{
244-
Name: serviceAccountScopeIDFlagName,
245-
Usage: "The entity ID that the service account is scoped to (e.g. namespace ID if creating a namespace scoped service account)",
246-
Aliases: []string{"sid"},
247-
},
248223
},
249224
Action: func(ctx *cli.Context) error {
250225
if len(ctx.String(serviceAccountNameFlagName)) == 0 {
251226
return fmt.Errorf("service account name must be provided with '--%s'", serviceAccountNameFlagName)
252227
}
253228

254-
scopeType := ctx.String(serviceAccountScopeTypeFlagName)
255-
scopeID := ctx.String(serviceAccountScopeIDFlagName)
256-
if (len(scopeType) > 0) != (len(scopeID) > 0) {
257-
return fmt.Errorf("both scope type and scope ID must be provided")
229+
if len(ctx.String(accountRoleFlagName)) == 0 {
230+
return fmt.Errorf("account role must be specified; valid types are %v", accountActionGroups)
258231
}
259232

260-
var scope *auth.ServiceAccountScope
261-
if len(scopeType) > 0 {
262-
t, ok := scopeTypes[scopeType]
263-
if !ok {
264-
return fmt.Errorf("invalid scope type: %s", scopeType)
265-
}
266-
scope = &auth.ServiceAccountScope{
267-
Type: t,
268-
Id: scopeID,
269-
}
270-
}
271-
272-
var access *auth.AccountAccess
273-
if scope == nil {
274-
if len(ctx.String(accountRoleFlagName)) == 0 {
275-
return fmt.Errorf("account role must be specified; valid types are %v", accountActionGroups)
276-
}
277-
ag, err := toAccountActionGroup(ctx.String(accountRoleFlagName))
278-
if err != nil {
279-
return fmt.Errorf("failed to parse account role: %w", err)
280-
}
281-
access = &auth.AccountAccess{
282-
Role: ag,
283-
}
284-
} else if scope.Type == auth.SERVICE_ACCOUNT_SCOPE_TYPE_NAMESPACE && len(ctx.String(accountRoleFlagName)) > 0 {
285-
return fmt.Errorf("namespace scoped service accounts may not have an account role")
233+
ag, err := toAccountActionGroup(ctx.String(accountRoleFlagName))
234+
if err != nil {
235+
return fmt.Errorf("failed to parse account role: %w", err)
286236
}
287237

288238
spec := &auth.ServiceAccountSpec{
289239
Name: ctx.String(serviceAccountNameFlagName),
290240
Access: &auth.Access{
291-
AccountAccess: access,
241+
AccountAccess: &auth.AccountAccess{
242+
Role: ag,
243+
},
292244
NamespaceAccesses: map[string]*auth.NamespaceAccess{},
293245
},
294246
Description: ctx.String(serviceAccountDescriptionFlagName),
295-
Scope: scope,
296247
}
297248

298249
isAccountAdmin := ctx.String(accountRoleFlagName) == auth.AccountActionGroup_name[int32(auth.ACCOUNT_ACTION_GROUP_ADMIN)]
@@ -329,6 +280,57 @@ func NewServiceAccountCommand(getServiceAccountClientFn GetServiceAccountClientF
329280
return c.createServiceAccount(ctx, spec, ctx.String(RequestIDFlagName))
330281
},
331282
},
283+
{
284+
Name: "create-scoped",
285+
Usage: "Create a scoped service account (service account restricted to a single namespace)",
286+
Aliases: []string{"cs"},
287+
Flags: []cli.Flag{
288+
serviceAccountDescriptionFlag,
289+
serviceAccountNameFlag,
290+
RequestIDFlag,
291+
&cli.StringFlag{
292+
Name: namespacePermissionFlagName,
293+
Usage: fmt.Sprintf("Value must be \"<namespace>=<permission>\"; valid types are: %v", namespaceActionGroups),
294+
Aliases: []string{"np"},
295+
},
296+
},
297+
Action: func(ctx *cli.Context) error {
298+
if len(ctx.String(serviceAccountNameFlagName)) == 0 {
299+
return fmt.Errorf("service account name must be provided with '--%s'", serviceAccountNameFlagName)
300+
}
301+
302+
scopedNamespace := ctx.String(namespacePermissionFlagName)
303+
if len(scopedNamespace) == 0 {
304+
return fmt.Errorf("namespace permission must be specified")
305+
}
306+
307+
spec := &auth.ServiceAccountSpec{
308+
Name: ctx.String(serviceAccountNameFlagName),
309+
Access: &auth.Access{
310+
NamespaceAccesses: map[string]*auth.NamespaceAccess{},
311+
},
312+
Description: ctx.String(serviceAccountDescriptionFlagName),
313+
}
314+
315+
nsMap, err := toNamespacePermissionsMap([]string{scopedNamespace})
316+
if err != nil {
317+
return fmt.Errorf("failed to read namespace permissions: %w", err)
318+
}
319+
320+
for ns, perm := range nsMap {
321+
nsActionGroup, err := toNamespaceActionGroup(perm)
322+
if err != nil {
323+
return fmt.Errorf("failed to parse %q namespace permission: %w", ns, err)
324+
}
325+
326+
spec.Access.NamespaceAccesses[ns] = &auth.NamespaceAccess{
327+
Permission: nsActionGroup,
328+
}
329+
}
330+
331+
return c.createServiceAccount(ctx, spec, ctx.String(RequestIDFlagName))
332+
},
333+
},
332334
{
333335
Name: "list",
334336
Usage: "List service accounts",

app/serviceaccount_test.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,6 @@ func (s *ServiceAccountTestSuite) TestList() {
105105
func (s *ServiceAccountTestSuite) TestCreateServiceAccount() {
106106
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(nil, errors.New("create service account error")).Times(1)
107107
s.EqualError(s.RunCmd("service-account", "create", "--description", "test description", "--name", "test name", "--account-role", "Read"), "unable to create service account: create service account error")
108-
s.EqualError(s.RunCmd("service-account", "create", "--name", "test name", "--scope-type", "namespace"), "both scope type and scope ID must be provided")
109-
s.EqualError(s.RunCmd("service-account", "create", "--name", "test name", "--scope-id", "test.ns"), "both scope type and scope ID must be provided")
110-
s.EqualError(s.RunCmd("service-account", "create", "--name", "test name", "--scope-type", "invalid", "--scope-id", "test.ns"), "invalid scope type: invalid")
111-
s.EqualError(s.RunCmd("service-account", "create", "--name", "test name", "--scope-type", "namespace", "--scope-id", "test.ns", "--account-role", "Read"), "namespace scoped service accounts may not have an account role")
112-
s.ErrorContains(s.RunCmd("service-account", "create", "--name", "test name"), "account role must be specified")
113-
114108
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(&authservice.CreateServiceAccountResponse{
115109
RequestStatus: &request.RequestStatus{
116110
State: request.STATE_FULFILLED,
@@ -131,6 +125,19 @@ func (s *ServiceAccountTestSuite) TestCreateServiceAccount() {
131125
s.NoError(s.RunCmd("service-account", "create", "--description", "test description", "--name", "test name", "--account-role", "Read", "--namespace-permission", "test-namespace=Read"))
132126
}
133127

128+
func (s *ServiceAccountTestSuite) TestCreateScopedServiceAccount() {
129+
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(nil, errors.New("create service account error")).Times(1)
130+
s.EqualError(s.RunCmd("service-account", "create-scoped", "--description", "test description", "--name", "test name", "--namespace-permission", "test-namespace=Read"), "unable to create service account: create service account error")
131+
s.EqualError(s.RunCmd("service-account", "create-scoped", "--description", "test description", "--name", "test name"), "namespace permission must be specified")
132+
133+
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(&authservice.CreateServiceAccountResponse{
134+
RequestStatus: &request.RequestStatus{
135+
State: request.STATE_FULFILLED,
136+
},
137+
}, nil).Times(1)
138+
s.NoError(s.RunCmd("service-account", "create-scoped", "--description", "test description", "--name", "test name", "--namespace-permission", "test-namespace=Admin"))
139+
}
140+
134141
func (s *ServiceAccountTestSuite) TestDeleteServiceAccount() {
135142
s.mockAuthService.EXPECT().GetServiceAccount(gomock.Any(), gomock.Any()).Return(nil, errors.New("get service account error")).Times(1)
136143
s.EqualError(s.RunCmd("service-account", "delete", "--service-account-id", "test-service-account-id"), "unable to get service account: get service account error")

0 commit comments

Comments
 (0)