Skip to content

Commit e825471

Browse files
authored
feat(cli): display instance admin status in organization describe (#2725)
Signed-off-by: Sylwester Piskozub <sylwesterpiskozub@gmail.com>
1 parent 3713950 commit e825471

8 files changed

Lines changed: 88 additions & 19 deletions

File tree

app/cli/cmd/organization_describe.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2023-2025 The Chainloop Authors.
2+
// Copyright 2023-2026 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ func newOrganizationDescribeCmd() *cobra.Command {
4646
func contextTableOutput(config *action.ConfigContextItem) error {
4747
gt := output.NewTableWriter()
4848
gt.SetTitle("Current Context")
49+
4950
gt.AppendRow(table.Row{"Logged in as", config.CurrentUser.PrintUserProfileWithEmail()})
5051
gt.AppendSeparator()
5152

app/cli/pkg/action/config_current_context.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2023 The Chainloop Authors.
2+
// Copyright 2023-2026 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -37,11 +37,12 @@ type ConfigContextItem struct {
3737
}
3838

3939
type UserItem struct {
40-
ID string `json:"id"`
41-
Email string `json:"email"`
42-
FirstName string `json:"firstName"`
43-
LastName string `json:"lastName"`
44-
CreatedAt *time.Time `json:"createdAt"`
40+
ID string `json:"id"`
41+
Email string `json:"email"`
42+
FirstName string `json:"firstName"`
43+
LastName string `json:"lastName"`
44+
CreatedAt *time.Time `json:"createdAt"`
45+
InstanceAdmin bool `json:"instanceAdmin,omitempty"`
4546
}
4647

4748
// PrintUserProfileWithEmail formats the user's profile with their email.
@@ -58,11 +59,19 @@ func (u *UserItem) PrintUserProfileWithEmail() string {
5859
name = u.LastName
5960
}
6061

62+
var result string
6163
// If we have a name, format with email, otherwise just return email
6264
if name != "" {
63-
return name + " <" + u.Email + ">"
65+
result = name + " <" + u.Email + ">"
66+
} else {
67+
result = u.Email
6468
}
65-
return u.Email
69+
70+
if u.InstanceAdmin {
71+
result += " (Instance admin)"
72+
}
73+
74+
return result
6675
}
6776

6877
func (action *ConfigCurrentContext) Run() (*ConfigContextItem, error) {
@@ -87,10 +96,11 @@ func pbUserItemToAction(in *pb.User) *UserItem {
8796
}
8897

8998
return &UserItem{
90-
ID: in.Id,
91-
Email: in.Email,
92-
FirstName: in.FirstName,
93-
LastName: in.LastName,
94-
CreatedAt: toTimePtr(in.CreatedAt.AsTime()),
99+
ID: in.Id,
100+
Email: in.Email,
101+
FirstName: in.FirstName,
102+
LastName: in.LastName,
103+
CreatedAt: toTimePtr(in.CreatedAt.AsTime()),
104+
InstanceAdmin: in.InstanceAdmin,
95105
}
96106
}

app/controlplane/api/controlplane/v1/response_messages.pb.go

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/controlplane/v1/response_messages.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ message User {
253253
google.protobuf.Timestamp updated_at = 6;
254254
string first_name = 4;
255255
string last_name = 5;
256+
bool instance_admin = 7;
256257
}
257258

258259
message OrgMembershipItem {

app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/gen/jsonschema/controlplane.v1.User.jsonschema.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/gen/jsonschema/controlplane.v1.User.schema.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/internal/service/context.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2024-2025 The Chainloop Authors.
2+
// Copyright 2024-2026 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -17,9 +17,11 @@ package service
1717

1818
import (
1919
"context"
20+
"slices"
2021

2122
pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1"
2223
"github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/entities"
24+
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/authz"
2325
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz"
2426
errors "github.com/go-kratos/kratos/v2/errors"
2527
"google.golang.org/protobuf/types/known/timestamppb"
@@ -67,7 +69,7 @@ func (s *ContextService) Current(ctx context.Context, _ *pb.ContextServiceCurren
6769
}
6870
} else if currentUser != nil {
6971
res.CurrentUser = &pb.User{
70-
Id: currentUser.ID, Email: currentUser.Email, FirstName: currentUser.FirstName, LastName: currentUser.LastName, CreatedAt: timestamppb.New(*currentUser.CreatedAt),
72+
Id: currentUser.ID, Email: currentUser.Email, FirstName: currentUser.FirstName, LastName: currentUser.LastName, CreatedAt: timestamppb.New(*currentUser.CreatedAt), InstanceAdmin: isInstanceAdmin(ctx),
7173
}
7274

7375
// For regular users, we need to load the membership manually
@@ -143,3 +145,15 @@ func bizPolicyViolationBlockingStrategyToPb(blockOnPolicyViolation bool) pb.OrgI
143145

144146
return pb.OrgItem_POLICY_VIOLATION_BLOCKING_STRATEGY_ADVISORY
145147
}
148+
149+
// isInstanceAdmin checks if the current user has instance admin role
150+
func isInstanceAdmin(ctx context.Context) bool {
151+
m := entities.CurrentMembership(ctx)
152+
if m == nil {
153+
return false
154+
}
155+
156+
return slices.ContainsFunc(m.Resources, func(r *entities.ResourceMembership) bool {
157+
return r.Role == authz.RoleInstanceAdmin && r.ResourceType == authz.ResourceTypeInstance
158+
})
159+
}

0 commit comments

Comments
 (0)