diff --git a/api/client/accesslist/accesslist.go b/api/client/accesslist/accesslist.go index 620ff615233..5e04f863d88 100644 --- a/api/client/accesslist/accesslist.go +++ b/api/client/accesslist/accesslist.go @@ -38,6 +38,22 @@ func NewClient(grpcClient accesslistv1.AccessListServiceClient) *Client { } } +func fromAccessListProto(accessList *accesslistv1.AccessList) (*accesslist.AccessList, error) { + return conv.FromProto( + accessList, + conv.WithOwnersIneligibleStatusField(accessList.GetSpec().GetOwners()), + conv.WithOwnerDisplaysField(accessList.GetStatus()), + ) +} + +func fromMemberProto(member *accesslistv1.Member) (*accesslist.AccessListMember, error) { + return conv.FromMemberProto( + member, + conv.WithMemberIneligibleStatusField(member), + conv.WithMemberStatusField(member), + ) +} + // GetAccessLists returns a list of all access lists. func (c *Client) GetAccessLists(ctx context.Context) ([]*accesslist.AccessList, error) { resp, err := c.grpcClient.GetAccessLists(ctx, &accesslistv1.GetAccessListsRequest{}) @@ -48,9 +64,7 @@ func (c *Client) GetAccessLists(ctx context.Context) ([]*accesslist.AccessList, accessLists := make([]*accesslist.AccessList, len(resp.AccessLists)) for i, accessList := range resp.AccessLists { var err error - accessLists[i], err = conv.FromProto( - accessList, - conv.WithOwnersIneligibleStatusField(accessList.GetSpec().GetOwners())) + accessLists[i], err = fromAccessListProto(accessList) if err != nil { return nil, trace.Wrap(err) } @@ -76,7 +90,7 @@ func (c *Client) ListAccessLists(ctx context.Context, pageSize int, nextToken st accessLists := make([]*accesslist.AccessList, len(resp.AccessLists)) for i, accessList := range resp.AccessLists { var err error - accessLists[i], err = conv.FromProto(accessList, conv.WithOwnersIneligibleStatusField(accessList.GetSpec().GetOwners())) + accessLists[i], err = fromAccessListProto(accessList) if err != nil { return nil, "", trace.Wrap(err) } @@ -94,7 +108,7 @@ func (c *Client) ListAccessListsV2(ctx context.Context, req *accesslistv1.ListAc accessLists := make([]*accesslist.AccessList, len(resp.AccessLists)) for i, accessList := range resp.AccessLists { - accessLists[i], err = conv.FromProto(accessList, conv.WithOwnersIneligibleStatusField(accessList.GetSpec().GetOwners())) + accessLists[i], err = fromAccessListProto(accessList) if err != nil { return nil, "", trace.Wrap(err) } @@ -112,7 +126,7 @@ func (c *Client) GetAccessList(ctx context.Context, name string) (*accesslist.Ac return nil, trace.Wrap(err) } - accessList, err := conv.FromProto(resp, conv.WithOwnersIneligibleStatusField(resp.GetSpec().GetOwners())) + accessList, err := fromAccessListProto(resp) return accessList, trace.Wrap(err) } @@ -126,7 +140,7 @@ func (c *Client) GetAccessListsToReview(ctx context.Context) ([]*accesslist.Acce accessLists := make([]*accesslist.AccessList, len(resp.AccessLists)) for i, accessList := range resp.AccessLists { var err error - accessLists[i], err = conv.FromProto(accessList, conv.WithOwnersIneligibleStatusField(accessList.GetSpec().GetOwners())) + accessLists[i], err = fromAccessListProto(accessList) if err != nil { return nil, trace.Wrap(err) } @@ -156,7 +170,7 @@ func (c *Client) UpsertAccessList(ctx context.Context, accessList *accesslist.Ac if err != nil { return nil, trace.Wrap(err) } - responseAccessList, err := conv.FromProto(resp, conv.WithOwnersIneligibleStatusField(resp.GetSpec().GetOwners())) + responseAccessList, err := fromAccessListProto(resp) return responseAccessList, trace.Wrap(err) } @@ -168,7 +182,7 @@ func (c *Client) UpdateAccessList(ctx context.Context, accessList *accesslist.Ac if err != nil { return nil, trace.Wrap(err) } - responseAccessList, err := conv.FromProto(resp, conv.WithOwnersIneligibleStatusField(resp.GetSpec().GetOwners())) + responseAccessList, err := fromAccessListProto(resp) return responseAccessList, trace.Wrap(err) } @@ -206,7 +220,7 @@ func (c *Client) ListAccessListMembers(ctx context.Context, accessList string, p members = make([]*accesslist.AccessListMember, len(resp.Members)) for i, member := range resp.Members { var err error - members[i], err = conv.FromMemberProto(member, conv.WithMemberIneligibleStatusField(member)) + members[i], err = fromMemberProto(member) if err != nil { return nil, "", trace.Wrap(err) } @@ -228,7 +242,7 @@ func (c *Client) ListAllAccessListMembers(ctx context.Context, pageSize int, pag members = make([]*accesslist.AccessListMember, len(resp.Members)) for i, member := range resp.Members { var err error - members[i], err = conv.FromMemberProto(member, conv.WithMemberIneligibleStatusField(member)) + members[i], err = fromMemberProto(member) if err != nil { return nil, "", trace.Wrap(err) } @@ -247,7 +261,7 @@ func (c *Client) GetAccessListMember(ctx context.Context, accessList, memberName return nil, trace.Wrap(err) } - member, err := conv.FromMemberProto(resp, conv.WithMemberIneligibleStatusField(resp)) + member, err := fromMemberProto(resp) return member, trace.Wrap(err) } @@ -262,7 +276,7 @@ func (c *Client) GetStaticAccessListMember(ctx context.Context, accessList, memb return nil, trace.Wrap(err) } - member, err := conv.FromMemberProto(resp.Member, conv.WithMemberIneligibleStatusField(resp.Member)) + member, err := fromMemberProto(resp.Member) return member, trace.Wrap(err) } @@ -294,7 +308,7 @@ func (c *Client) UpsertAccessListMember(ctx context.Context, member *accesslist. if err != nil { return nil, trace.Wrap(err) } - responseMember, err := conv.FromMemberProto(resp, conv.WithMemberIneligibleStatusField(resp)) + responseMember, err := fromMemberProto(resp) return responseMember, trace.Wrap(err) } @@ -307,7 +321,7 @@ func (c *Client) UpsertStaticAccessListMember(ctx context.Context, member *acces if err != nil { return nil, trace.Wrap(err) } - m, err := conv.FromMemberProto(resp.Member, conv.WithMemberIneligibleStatusField(resp.Member)) + m, err := fromMemberProto(resp.Member) return m, trace.Wrap(err) } @@ -319,7 +333,7 @@ func (c *Client) UpdateAccessListMember(ctx context.Context, member *accesslist. if err != nil { return nil, trace.Wrap(err) } - responseMember, err := conv.FromMemberProto(resp, conv.WithMemberIneligibleStatusField(resp)) + responseMember, err := fromMemberProto(resp) return responseMember, trace.Wrap(err) } @@ -360,7 +374,7 @@ func (c *Client) UpsertAccessListWithMembers(ctx context.Context, list *accessli return nil, nil, trace.Wrap(err) } - accessList, err := conv.FromProto(resp.AccessList, conv.WithOwnersIneligibleStatusField(resp.AccessList.GetSpec().GetOwners())) + accessList, err := fromAccessListProto(resp.AccessList) if err != nil { return nil, nil, trace.Wrap(err) } @@ -368,7 +382,7 @@ func (c *Client) UpsertAccessListWithMembers(ctx context.Context, list *accessli updatedMembers := make([]*accesslist.AccessListMember, len(resp.Members)) for i, member := range resp.Members { var err error - updatedMembers[i], err = conv.FromMemberProto(member, conv.WithMemberIneligibleStatusField(member)) + updatedMembers[i], err = fromMemberProto(member) if err != nil { return nil, nil, trace.Wrap(err) } @@ -464,7 +478,7 @@ func (c *Client) GetSuggestedAccessLists(ctx context.Context, accessRequestID st accessLists := make([]*accesslist.AccessList, len(resp.AccessLists)) for i, accessList := range resp.AccessLists { var err error - accessLists[i], err = conv.FromProto(accessList) + accessLists[i], err = fromAccessListProto(accessList) if err != nil { return nil, trace.Wrap(err) } @@ -483,7 +497,7 @@ func (c *Client) ListUserAccessLists(ctx context.Context, req *accesslistv1.List accessLists := make([]*accesslist.AccessList, len(resp.AccessLists)) for i, accessList := range resp.AccessLists { - accessLists[i], err = conv.FromProto(accessList, conv.WithOwnersIneligibleStatusField(accessList.GetSpec().GetOwners())) + accessLists[i], err = fromAccessListProto(accessList) if err != nil { return nil, "", trace.Wrap(err) } diff --git a/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go b/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go index 00dd5421298..a423e6abf5b 100644 --- a/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go +++ b/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go @@ -1354,6 +1354,84 @@ func (b0 ScopedRoleGrant_builder) Build() *ScopedRoleGrant { return m0 } +// UserDisplay contains display values derived from a user. An empty message +// means the user has no primary/secondary distinct from the username; the +// absence of this message means the user was not found. +type UserDisplay struct { + state protoimpl.MessageState `protogen:"hybrid.v1"` + // primary is a human-readable display name when distinct from username. + Primary string `protobuf:"bytes,1,opt,name=primary,proto3" json:"primary,omitempty"` + // secondary is supporting display context when distinct from username. + Secondary string `protobuf:"bytes,2,opt,name=secondary,proto3" json:"secondary,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UserDisplay) Reset() { + *x = UserDisplay{} + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UserDisplay) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserDisplay) ProtoMessage() {} + +func (x *UserDisplay) ProtoReflect() protoreflect.Message { + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *UserDisplay) GetPrimary() string { + if x != nil { + return x.Primary + } + return "" +} + +func (x *UserDisplay) GetSecondary() string { + if x != nil { + return x.Secondary + } + return "" +} + +func (x *UserDisplay) SetPrimary(v string) { + x.Primary = v +} + +func (x *UserDisplay) SetSecondary(v string) { + x.Secondary = v +} + +type UserDisplay_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // primary is a human-readable display name when distinct from username. + Primary string + // secondary is supporting display context when distinct from username. + Secondary string +} + +func (b0 UserDisplay_builder) Build() *UserDisplay { + m0 := &UserDisplay{} + b, x := &b0, m0 + _, _ = b, x + x.Primary = b.Primary + x.Secondary = b.Secondary + return m0 +} + // Member describes a member of an Access List. type Member struct { state protoimpl.MessageState `protogen:"hybrid.v1"` @@ -1363,14 +1441,16 @@ type Member struct { Spec *MemberSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` // scope is the scope of the Access List member, it must be equal to the // scope of the parent Access List. - Scope string `protobuf:"bytes,3,opt,name=scope,proto3" json:"scope,omitempty"` + Scope string `protobuf:"bytes,3,opt,name=scope,proto3" json:"scope,omitempty"` + // status contains dynamically calculated fields. + Status *MemberStatus `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Member) Reset() { *x = Member{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1382,7 +1462,7 @@ func (x *Member) String() string { func (*Member) ProtoMessage() {} func (x *Member) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1414,6 +1494,13 @@ func (x *Member) GetScope() string { return "" } +func (x *Member) GetStatus() *MemberStatus { + if x != nil { + return x.Status + } + return nil +} + func (x *Member) SetHeader(v *v1.ResourceHeader) { x.Header = v } @@ -1426,6 +1513,10 @@ func (x *Member) SetScope(v string) { x.Scope = v } +func (x *Member) SetStatus(v *MemberStatus) { + x.Status = v +} + func (x *Member) HasHeader() bool { if x == nil { return false @@ -1440,6 +1531,13 @@ func (x *Member) HasSpec() bool { return x.Spec != nil } +func (x *Member) HasStatus() bool { + if x == nil { + return false + } + return x.Status != nil +} + func (x *Member) ClearHeader() { x.Header = nil } @@ -1448,6 +1546,10 @@ func (x *Member) ClearSpec() { x.Spec = nil } +func (x *Member) ClearStatus() { + x.Status = nil +} + type Member_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. @@ -1458,6 +1560,8 @@ type Member_builder struct { // scope is the scope of the Access List member, it must be equal to the // scope of the parent Access List. Scope string + // status contains dynamically calculated fields. + Status *MemberStatus } func (b0 Member_builder) Build() *Member { @@ -1467,6 +1571,105 @@ func (b0 Member_builder) Build() *Member { x.Header = b.Header x.Spec = b.Spec x.Scope = b.Scope + x.Status = b.Status + return m0 +} + +// MemberStatus contains dynamic fields calculated during retrieval. +type MemberStatus struct { + state protoimpl.MessageState `protogen:"hybrid.v1"` + // display contains display values for the member user. + Display *UserDisplay `protobuf:"bytes,1,opt,name=display,proto3" json:"display,omitempty"` + // added_by_display contains display values for the user that added the member. + AddedByDisplay *UserDisplay `protobuf:"bytes,2,opt,name=added_by_display,json=addedByDisplay,proto3" json:"added_by_display,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MemberStatus) Reset() { + *x = MemberStatus{} + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MemberStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MemberStatus) ProtoMessage() {} + +func (x *MemberStatus) ProtoReflect() protoreflect.Message { + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *MemberStatus) GetDisplay() *UserDisplay { + if x != nil { + return x.Display + } + return nil +} + +func (x *MemberStatus) GetAddedByDisplay() *UserDisplay { + if x != nil { + return x.AddedByDisplay + } + return nil +} + +func (x *MemberStatus) SetDisplay(v *UserDisplay) { + x.Display = v +} + +func (x *MemberStatus) SetAddedByDisplay(v *UserDisplay) { + x.AddedByDisplay = v +} + +func (x *MemberStatus) HasDisplay() bool { + if x == nil { + return false + } + return x.Display != nil +} + +func (x *MemberStatus) HasAddedByDisplay() bool { + if x == nil { + return false + } + return x.AddedByDisplay != nil +} + +func (x *MemberStatus) ClearDisplay() { + x.Display = nil +} + +func (x *MemberStatus) ClearAddedByDisplay() { + x.AddedByDisplay = nil +} + +type MemberStatus_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // display contains display values for the member user. + Display *UserDisplay + // added_by_display contains display values for the user that added the member. + AddedByDisplay *UserDisplay +} + +func (b0 MemberStatus_builder) Build() *MemberStatus { + m0 := &MemberStatus{} + b, x := &b0, m0 + _, _ = b, x + x.Display = b.Display + x.AddedByDisplay = b.AddedByDisplay return m0 } @@ -1500,7 +1703,7 @@ type MemberSpec struct { func (x *MemberSpec) Reset() { *x = MemberSpec{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1512,7 +1715,7 @@ func (x *MemberSpec) String() string { func (*MemberSpec) ProtoMessage() {} func (x *MemberSpec) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1690,7 +1893,7 @@ type Review struct { func (x *Review) Reset() { *x = Review{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1702,7 +1905,7 @@ func (x *Review) String() string { func (*Review) ProtoMessage() {} func (x *Review) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1812,7 +2015,7 @@ type ReviewSpec struct { func (x *ReviewSpec) Reset() { *x = ReviewSpec{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1824,7 +2027,7 @@ func (x *ReviewSpec) String() string { func (*ReviewSpec) ProtoMessage() {} func (x *ReviewSpec) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1965,7 +2168,7 @@ type ReviewChanges struct { func (x *ReviewChanges) Reset() { *x = ReviewChanges{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1977,7 +2180,7 @@ func (x *ReviewChanges) String() string { func (*ReviewChanges) ProtoMessage() {} func (x *ReviewChanges) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2098,7 +2301,7 @@ type CurrentUserAssignments struct { func (x *CurrentUserAssignments) Reset() { *x = CurrentUserAssignments{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2110,7 +2313,7 @@ func (x *CurrentUserAssignments) String() string { func (*CurrentUserAssignments) ProtoMessage() {} func (x *CurrentUserAssignments) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2174,7 +2377,7 @@ type UserAssignments struct { func (x *UserAssignments) Reset() { *x = UserAssignments{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2186,7 +2389,7 @@ func (x *UserAssignments) String() string { func (*UserAssignments) ProtoMessage() {} func (x *UserAssignments) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2258,13 +2461,15 @@ type AccessListStatus struct { // scoped_member_of describes scoped Access Lists where this Access List is an explicit member. // Each item is the scope-qualified name of the parent scoped Access List. ScopedMemberOf []string `protobuf:"bytes,8,rep,name=scoped_member_of,json=scopedMemberOf,proto3" json:"scoped_member_of,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // owner_displays contains display values for owners, keyed by owner username. + OwnerDisplays map[string]*UserDisplay `protobuf:"bytes,9,rep,name=owner_displays,json=ownerDisplays,proto3" json:"owner_displays,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccessListStatus) Reset() { *x = AccessListStatus{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2276,7 +2481,7 @@ func (x *AccessListStatus) String() string { func (*AccessListStatus) ProtoMessage() {} func (x *AccessListStatus) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2343,6 +2548,13 @@ func (x *AccessListStatus) GetScopedMemberOf() []string { return nil } +func (x *AccessListStatus) GetOwnerDisplays() map[string]*UserDisplay { + if x != nil { + return x.OwnerDisplays + } + return nil +} + func (x *AccessListStatus) SetMemberCount(v uint32) { x.MemberCount = &v } @@ -2375,6 +2587,10 @@ func (x *AccessListStatus) SetScopedMemberOf(v []string) { x.ScopedMemberOf = v } +func (x *AccessListStatus) SetOwnerDisplays(v map[string]*UserDisplay) { + x.OwnerDisplays = v +} + func (x *AccessListStatus) HasMemberCount() bool { if x == nil { return false @@ -2440,6 +2656,8 @@ type AccessListStatus_builder struct { // scoped_member_of describes scoped Access Lists where this Access List is an explicit member. // Each item is the scope-qualified name of the parent scoped Access List. ScopedMemberOf []string + // owner_displays contains display values for owners, keyed by owner username. + OwnerDisplays map[string]*UserDisplay } func (b0 AccessListStatus_builder) Build() *AccessListStatus { @@ -2454,6 +2672,7 @@ func (b0 AccessListStatus_builder) Build() *AccessListStatus { x.UserAssignments = b.UserAssignments x.ScopedOwnerOf = b.ScopedOwnerOf x.ScopedMemberOf = b.ScopedMemberOf + x.OwnerDisplays = b.OwnerDisplays return m0 } @@ -2508,11 +2727,18 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "\fscoped_roles\x18\x03 \x03(\v2'.teleport.accesslist.v1.ScopedRoleGrantR\vscopedRoles\";\n" + "\x0fScopedRoleGrant\x12\x12\n" + "\x04role\x18\x01 \x01(\tR\x04role\x12\x14\n" + - "\x05scope\x18\x02 \x01(\tR\x05scope\"\x92\x01\n" + + "\x05scope\x18\x02 \x01(\tR\x05scope\"E\n" + + "\vUserDisplay\x12\x18\n" + + "\aprimary\x18\x01 \x01(\tR\aprimary\x12\x1c\n" + + "\tsecondary\x18\x02 \x01(\tR\tsecondary\"\xd0\x01\n" + "\x06Member\x12:\n" + "\x06header\x18\x01 \x01(\v2\".teleport.header.v1.ResourceHeaderR\x06header\x126\n" + "\x04spec\x18\x02 \x01(\v2\".teleport.accesslist.v1.MemberSpecR\x04spec\x12\x14\n" + - "\x05scope\x18\x03 \x01(\tR\x05scope\"\x98\x03\n" + + "\x05scope\x18\x03 \x01(\tR\x05scope\x12<\n" + + "\x06status\x18\x04 \x01(\v2$.teleport.accesslist.v1.MemberStatusR\x06status\"\x9c\x01\n" + + "\fMemberStatus\x12=\n" + + "\adisplay\x18\x01 \x01(\v2#.teleport.accesslist.v1.UserDisplayR\adisplay\x12M\n" + + "\x10added_by_display\x18\x02 \x01(\v2#.teleport.accesslist.v1.UserDisplayR\x0eaddedByDisplay\"\x98\x03\n" + "\n" + "MemberSpec\x12\x1f\n" + "\vaccess_list\x18\x01 \x01(\tR\n" + @@ -2549,7 +2775,7 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "\x0fmembership_type\x18\x02 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\x0emembershipType\"\xcd\x01\n" + "\x0fUserAssignments\x12[\n" + "\x0eownership_type\x18\x01 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\rownershipType\x12]\n" + - "\x0fmembership_type\x18\x02 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\x0emembershipType\"\xda\x03\n" + + "\x0fmembership_type\x18\x02 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\x0emembershipType\"\xa5\x05\n" + "\x10AccessListStatus\x12&\n" + "\fmember_count\x18\x01 \x01(\rH\x00R\vmemberCount\x88\x01\x01\x12/\n" + "\x11member_list_count\x18\x02 \x01(\rH\x01R\x0fmemberListCount\x88\x01\x01\x12\x19\n" + @@ -2558,7 +2784,11 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "\x18current_user_assignments\x18\x05 \x01(\v2..teleport.accesslist.v1.CurrentUserAssignmentsR\x16currentUserAssignments\x12R\n" + "\x10user_assignments\x18\x06 \x01(\v2'.teleport.accesslist.v1.UserAssignmentsR\x0fuserAssignments\x12&\n" + "\x0fscoped_owner_of\x18\a \x03(\tR\rscopedOwnerOf\x12(\n" + - "\x10scoped_member_of\x18\b \x03(\tR\x0escopedMemberOfB\x0f\n" + + "\x10scoped_member_of\x18\b \x03(\tR\x0escopedMemberOf\x12b\n" + + "\x0eowner_displays\x18\t \x03(\v2;.teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntryR\rownerDisplays\x1ae\n" + + "\x12OwnerDisplaysEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x129\n" + + "\x05value\x18\x02 \x01(\v2#.teleport.accesslist.v1.UserDisplayR\x05value:\x028\x01B\x0f\n" + "\r_member_countB\x14\n" + "\x12_member_list_count*\xb6\x01\n" + "\x0fReviewFrequency\x12 \n" + @@ -2589,7 +2819,7 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "*ACCESS_LIST_USER_ASSIGNMENT_TYPE_INHERITED\x10\x02BXZVgithub.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1;accesslistv1b\x06proto3" var file_teleport_accesslist_v1_accesslist_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_teleport_accesslist_v1_accesslist_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_teleport_accesslist_v1_accesslist_proto_msgTypes = make([]protoimpl.MessageInfo, 20) var file_teleport_accesslist_v1_accesslist_proto_goTypes = []any{ (ReviewFrequency)(0), // 0: teleport.accesslist.v1.ReviewFrequency (ReviewDayOfMonth)(0), // 1: teleport.accesslist.v1.ReviewDayOfMonth @@ -2605,23 +2835,26 @@ var file_teleport_accesslist_v1_accesslist_proto_goTypes = []any{ (*AccessListRequires)(nil), // 11: teleport.accesslist.v1.AccessListRequires (*AccessListGrants)(nil), // 12: teleport.accesslist.v1.AccessListGrants (*ScopedRoleGrant)(nil), // 13: teleport.accesslist.v1.ScopedRoleGrant - (*Member)(nil), // 14: teleport.accesslist.v1.Member - (*MemberSpec)(nil), // 15: teleport.accesslist.v1.MemberSpec - (*Review)(nil), // 16: teleport.accesslist.v1.Review - (*ReviewSpec)(nil), // 17: teleport.accesslist.v1.ReviewSpec - (*ReviewChanges)(nil), // 18: teleport.accesslist.v1.ReviewChanges - (*CurrentUserAssignments)(nil), // 19: teleport.accesslist.v1.CurrentUserAssignments - (*UserAssignments)(nil), // 20: teleport.accesslist.v1.UserAssignments - (*AccessListStatus)(nil), // 21: teleport.accesslist.v1.AccessListStatus - (*v1.ResourceHeader)(nil), // 22: teleport.header.v1.ResourceHeader - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 24: google.protobuf.Duration - (*v11.Trait)(nil), // 25: teleport.trait.v1.Trait + (*UserDisplay)(nil), // 14: teleport.accesslist.v1.UserDisplay + (*Member)(nil), // 15: teleport.accesslist.v1.Member + (*MemberStatus)(nil), // 16: teleport.accesslist.v1.MemberStatus + (*MemberSpec)(nil), // 17: teleport.accesslist.v1.MemberSpec + (*Review)(nil), // 18: teleport.accesslist.v1.Review + (*ReviewSpec)(nil), // 19: teleport.accesslist.v1.ReviewSpec + (*ReviewChanges)(nil), // 20: teleport.accesslist.v1.ReviewChanges + (*CurrentUserAssignments)(nil), // 21: teleport.accesslist.v1.CurrentUserAssignments + (*UserAssignments)(nil), // 22: teleport.accesslist.v1.UserAssignments + (*AccessListStatus)(nil), // 23: teleport.accesslist.v1.AccessListStatus + nil, // 24: teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntry + (*v1.ResourceHeader)(nil), // 25: teleport.header.v1.ResourceHeader + (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 27: google.protobuf.Duration + (*v11.Trait)(nil), // 28: teleport.trait.v1.Trait } var file_teleport_accesslist_v1_accesslist_proto_depIdxs = []int32{ - 22, // 0: teleport.accesslist.v1.AccessList.header:type_name -> teleport.header.v1.ResourceHeader + 25, // 0: teleport.accesslist.v1.AccessList.header:type_name -> teleport.header.v1.ResourceHeader 6, // 1: teleport.accesslist.v1.AccessList.spec:type_name -> teleport.accesslist.v1.AccessListSpec - 21, // 2: teleport.accesslist.v1.AccessList.status:type_name -> teleport.accesslist.v1.AccessListStatus + 23, // 2: teleport.accesslist.v1.AccessList.status:type_name -> teleport.accesslist.v1.AccessListStatus 7, // 3: teleport.accesslist.v1.AccessListSpec.owners:type_name -> teleport.accesslist.v1.AccessListOwner 8, // 4: teleport.accesslist.v1.AccessListSpec.audit:type_name -> teleport.accesslist.v1.AccessListAudit 11, // 5: teleport.accesslist.v1.AccessListSpec.membership_requires:type_name -> teleport.accesslist.v1.AccessListRequires @@ -2630,39 +2863,44 @@ var file_teleport_accesslist_v1_accesslist_proto_depIdxs = []int32{ 12, // 8: teleport.accesslist.v1.AccessListSpec.owner_grants:type_name -> teleport.accesslist.v1.AccessListGrants 3, // 9: teleport.accesslist.v1.AccessListOwner.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus 2, // 10: teleport.accesslist.v1.AccessListOwner.membership_kind:type_name -> teleport.accesslist.v1.MembershipKind - 23, // 11: teleport.accesslist.v1.AccessListAudit.next_audit_date:type_name -> google.protobuf.Timestamp + 26, // 11: teleport.accesslist.v1.AccessListAudit.next_audit_date:type_name -> google.protobuf.Timestamp 9, // 12: teleport.accesslist.v1.AccessListAudit.recurrence:type_name -> teleport.accesslist.v1.Recurrence 10, // 13: teleport.accesslist.v1.AccessListAudit.notifications:type_name -> teleport.accesslist.v1.Notifications 0, // 14: teleport.accesslist.v1.Recurrence.frequency:type_name -> teleport.accesslist.v1.ReviewFrequency 1, // 15: teleport.accesslist.v1.Recurrence.day_of_month:type_name -> teleport.accesslist.v1.ReviewDayOfMonth - 24, // 16: teleport.accesslist.v1.Notifications.start:type_name -> google.protobuf.Duration - 25, // 17: teleport.accesslist.v1.AccessListRequires.traits:type_name -> teleport.trait.v1.Trait - 25, // 18: teleport.accesslist.v1.AccessListGrants.traits:type_name -> teleport.trait.v1.Trait + 27, // 16: teleport.accesslist.v1.Notifications.start:type_name -> google.protobuf.Duration + 28, // 17: teleport.accesslist.v1.AccessListRequires.traits:type_name -> teleport.trait.v1.Trait + 28, // 18: teleport.accesslist.v1.AccessListGrants.traits:type_name -> teleport.trait.v1.Trait 13, // 19: teleport.accesslist.v1.AccessListGrants.scoped_roles:type_name -> teleport.accesslist.v1.ScopedRoleGrant - 22, // 20: teleport.accesslist.v1.Member.header:type_name -> teleport.header.v1.ResourceHeader - 15, // 21: teleport.accesslist.v1.Member.spec:type_name -> teleport.accesslist.v1.MemberSpec - 23, // 22: teleport.accesslist.v1.MemberSpec.joined:type_name -> google.protobuf.Timestamp - 23, // 23: teleport.accesslist.v1.MemberSpec.expires:type_name -> google.protobuf.Timestamp - 3, // 24: teleport.accesslist.v1.MemberSpec.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus - 2, // 25: teleport.accesslist.v1.MemberSpec.membership_kind:type_name -> teleport.accesslist.v1.MembershipKind - 22, // 26: teleport.accesslist.v1.Review.header:type_name -> teleport.header.v1.ResourceHeader - 17, // 27: teleport.accesslist.v1.Review.spec:type_name -> teleport.accesslist.v1.ReviewSpec - 23, // 28: teleport.accesslist.v1.ReviewSpec.review_date:type_name -> google.protobuf.Timestamp - 18, // 29: teleport.accesslist.v1.ReviewSpec.changes:type_name -> teleport.accesslist.v1.ReviewChanges - 11, // 30: teleport.accesslist.v1.ReviewChanges.membership_requirements_changed:type_name -> teleport.accesslist.v1.AccessListRequires - 0, // 31: teleport.accesslist.v1.ReviewChanges.review_frequency_changed:type_name -> teleport.accesslist.v1.ReviewFrequency - 1, // 32: teleport.accesslist.v1.ReviewChanges.review_day_of_month_changed:type_name -> teleport.accesslist.v1.ReviewDayOfMonth - 4, // 33: teleport.accesslist.v1.CurrentUserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 4, // 34: teleport.accesslist.v1.CurrentUserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 4, // 35: teleport.accesslist.v1.UserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 4, // 36: teleport.accesslist.v1.UserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 19, // 37: teleport.accesslist.v1.AccessListStatus.current_user_assignments:type_name -> teleport.accesslist.v1.CurrentUserAssignments - 20, // 38: teleport.accesslist.v1.AccessListStatus.user_assignments:type_name -> teleport.accesslist.v1.UserAssignments - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 25, // 20: teleport.accesslist.v1.Member.header:type_name -> teleport.header.v1.ResourceHeader + 17, // 21: teleport.accesslist.v1.Member.spec:type_name -> teleport.accesslist.v1.MemberSpec + 16, // 22: teleport.accesslist.v1.Member.status:type_name -> teleport.accesslist.v1.MemberStatus + 14, // 23: teleport.accesslist.v1.MemberStatus.display:type_name -> teleport.accesslist.v1.UserDisplay + 14, // 24: teleport.accesslist.v1.MemberStatus.added_by_display:type_name -> teleport.accesslist.v1.UserDisplay + 26, // 25: teleport.accesslist.v1.MemberSpec.joined:type_name -> google.protobuf.Timestamp + 26, // 26: teleport.accesslist.v1.MemberSpec.expires:type_name -> google.protobuf.Timestamp + 3, // 27: teleport.accesslist.v1.MemberSpec.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus + 2, // 28: teleport.accesslist.v1.MemberSpec.membership_kind:type_name -> teleport.accesslist.v1.MembershipKind + 25, // 29: teleport.accesslist.v1.Review.header:type_name -> teleport.header.v1.ResourceHeader + 19, // 30: teleport.accesslist.v1.Review.spec:type_name -> teleport.accesslist.v1.ReviewSpec + 26, // 31: teleport.accesslist.v1.ReviewSpec.review_date:type_name -> google.protobuf.Timestamp + 20, // 32: teleport.accesslist.v1.ReviewSpec.changes:type_name -> teleport.accesslist.v1.ReviewChanges + 11, // 33: teleport.accesslist.v1.ReviewChanges.membership_requirements_changed:type_name -> teleport.accesslist.v1.AccessListRequires + 0, // 34: teleport.accesslist.v1.ReviewChanges.review_frequency_changed:type_name -> teleport.accesslist.v1.ReviewFrequency + 1, // 35: teleport.accesslist.v1.ReviewChanges.review_day_of_month_changed:type_name -> teleport.accesslist.v1.ReviewDayOfMonth + 4, // 36: teleport.accesslist.v1.CurrentUserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 4, // 37: teleport.accesslist.v1.CurrentUserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 4, // 38: teleport.accesslist.v1.UserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 4, // 39: teleport.accesslist.v1.UserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 21, // 40: teleport.accesslist.v1.AccessListStatus.current_user_assignments:type_name -> teleport.accesslist.v1.CurrentUserAssignments + 22, // 41: teleport.accesslist.v1.AccessListStatus.user_assignments:type_name -> teleport.accesslist.v1.UserAssignments + 24, // 42: teleport.accesslist.v1.AccessListStatus.owner_displays:type_name -> teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntry + 14, // 43: teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntry.value:type_name -> teleport.accesslist.v1.UserDisplay + 44, // [44:44] is the sub-list for method output_type + 44, // [44:44] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name } func init() { file_teleport_accesslist_v1_accesslist_proto_init() } @@ -2670,14 +2908,14 @@ func file_teleport_accesslist_v1_accesslist_proto_init() { if File_teleport_accesslist_v1_accesslist_proto != nil { return } - file_teleport_accesslist_v1_accesslist_proto_msgTypes[16].OneofWrappers = []any{} + file_teleport_accesslist_v1_accesslist_proto_msgTypes[18].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_accesslist_v1_accesslist_proto_rawDesc), len(file_teleport_accesslist_v1_accesslist_proto_rawDesc)), NumEnums: 5, - NumMessages: 17, + NumMessages: 20, NumExtensions: 0, NumServices: 0, }, diff --git a/api/gen/proto/go/teleport/accesslist/v1/accesslist_protoopaque.pb.go b/api/gen/proto/go/teleport/accesslist/v1/accesslist_protoopaque.pb.go index 57b2326435d..fcf8319f241 100644 --- a/api/gen/proto/go/teleport/accesslist/v1/accesslist_protoopaque.pb.go +++ b/api/gen/proto/go/teleport/accesslist/v1/accesslist_protoopaque.pb.go @@ -1312,19 +1312,96 @@ func (b0 ScopedRoleGrant_builder) Build() *ScopedRoleGrant { return m0 } +// UserDisplay contains display values derived from a user. An empty message +// means the user has no primary/secondary distinct from the username; the +// absence of this message means the user was not found. +type UserDisplay struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Primary string `protobuf:"bytes,1,opt,name=primary,proto3"` + xxx_hidden_Secondary string `protobuf:"bytes,2,opt,name=secondary,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UserDisplay) Reset() { + *x = UserDisplay{} + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UserDisplay) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserDisplay) ProtoMessage() {} + +func (x *UserDisplay) ProtoReflect() protoreflect.Message { + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *UserDisplay) GetPrimary() string { + if x != nil { + return x.xxx_hidden_Primary + } + return "" +} + +func (x *UserDisplay) GetSecondary() string { + if x != nil { + return x.xxx_hidden_Secondary + } + return "" +} + +func (x *UserDisplay) SetPrimary(v string) { + x.xxx_hidden_Primary = v +} + +func (x *UserDisplay) SetSecondary(v string) { + x.xxx_hidden_Secondary = v +} + +type UserDisplay_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // primary is a human-readable display name when distinct from username. + Primary string + // secondary is supporting display context when distinct from username. + Secondary string +} + +func (b0 UserDisplay_builder) Build() *UserDisplay { + m0 := &UserDisplay{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Primary = b.Primary + x.xxx_hidden_Secondary = b.Secondary + return m0 +} + // Member describes a member of an Access List. type Member struct { state protoimpl.MessageState `protogen:"opaque.v1"` xxx_hidden_Header *v1.ResourceHeader `protobuf:"bytes,1,opt,name=header,proto3"` xxx_hidden_Spec *MemberSpec `protobuf:"bytes,2,opt,name=spec,proto3"` xxx_hidden_Scope string `protobuf:"bytes,3,opt,name=scope,proto3"` + xxx_hidden_Status *MemberStatus `protobuf:"bytes,4,opt,name=status,proto3"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Member) Reset() { *x = Member{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1336,7 +1413,7 @@ func (x *Member) String() string { func (*Member) ProtoMessage() {} func (x *Member) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1368,6 +1445,13 @@ func (x *Member) GetScope() string { return "" } +func (x *Member) GetStatus() *MemberStatus { + if x != nil { + return x.xxx_hidden_Status + } + return nil +} + func (x *Member) SetHeader(v *v1.ResourceHeader) { x.xxx_hidden_Header = v } @@ -1380,6 +1464,10 @@ func (x *Member) SetScope(v string) { x.xxx_hidden_Scope = v } +func (x *Member) SetStatus(v *MemberStatus) { + x.xxx_hidden_Status = v +} + func (x *Member) HasHeader() bool { if x == nil { return false @@ -1394,6 +1482,13 @@ func (x *Member) HasSpec() bool { return x.xxx_hidden_Spec != nil } +func (x *Member) HasStatus() bool { + if x == nil { + return false + } + return x.xxx_hidden_Status != nil +} + func (x *Member) ClearHeader() { x.xxx_hidden_Header = nil } @@ -1402,6 +1497,10 @@ func (x *Member) ClearSpec() { x.xxx_hidden_Spec = nil } +func (x *Member) ClearStatus() { + x.xxx_hidden_Status = nil +} + type Member_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. @@ -1412,6 +1511,8 @@ type Member_builder struct { // scope is the scope of the Access List member, it must be equal to the // scope of the parent Access List. Scope string + // status contains dynamically calculated fields. + Status *MemberStatus } func (b0 Member_builder) Build() *Member { @@ -1421,6 +1522,103 @@ func (b0 Member_builder) Build() *Member { x.xxx_hidden_Header = b.Header x.xxx_hidden_Spec = b.Spec x.xxx_hidden_Scope = b.Scope + x.xxx_hidden_Status = b.Status + return m0 +} + +// MemberStatus contains dynamic fields calculated during retrieval. +type MemberStatus struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Display *UserDisplay `protobuf:"bytes,1,opt,name=display,proto3"` + xxx_hidden_AddedByDisplay *UserDisplay `protobuf:"bytes,2,opt,name=added_by_display,json=addedByDisplay,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MemberStatus) Reset() { + *x = MemberStatus{} + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MemberStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MemberStatus) ProtoMessage() {} + +func (x *MemberStatus) ProtoReflect() protoreflect.Message { + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *MemberStatus) GetDisplay() *UserDisplay { + if x != nil { + return x.xxx_hidden_Display + } + return nil +} + +func (x *MemberStatus) GetAddedByDisplay() *UserDisplay { + if x != nil { + return x.xxx_hidden_AddedByDisplay + } + return nil +} + +func (x *MemberStatus) SetDisplay(v *UserDisplay) { + x.xxx_hidden_Display = v +} + +func (x *MemberStatus) SetAddedByDisplay(v *UserDisplay) { + x.xxx_hidden_AddedByDisplay = v +} + +func (x *MemberStatus) HasDisplay() bool { + if x == nil { + return false + } + return x.xxx_hidden_Display != nil +} + +func (x *MemberStatus) HasAddedByDisplay() bool { + if x == nil { + return false + } + return x.xxx_hidden_AddedByDisplay != nil +} + +func (x *MemberStatus) ClearDisplay() { + x.xxx_hidden_Display = nil +} + +func (x *MemberStatus) ClearAddedByDisplay() { + x.xxx_hidden_AddedByDisplay = nil +} + +type MemberStatus_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // display contains display values for the member user. + Display *UserDisplay + // added_by_display contains display values for the user that added the member. + AddedByDisplay *UserDisplay +} + +func (b0 MemberStatus_builder) Build() *MemberStatus { + m0 := &MemberStatus{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Display = b.Display + x.xxx_hidden_AddedByDisplay = b.AddedByDisplay return m0 } @@ -1441,7 +1639,7 @@ type MemberSpec struct { func (x *MemberSpec) Reset() { *x = MemberSpec{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1453,7 +1651,7 @@ func (x *MemberSpec) String() string { func (*MemberSpec) ProtoMessage() {} func (x *MemberSpec) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1627,7 +1825,7 @@ type Review struct { func (x *Review) Reset() { *x = Review{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1639,7 +1837,7 @@ func (x *Review) String() string { func (*Review) ProtoMessage() {} func (x *Review) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1741,7 +1939,7 @@ type ReviewSpec struct { func (x *ReviewSpec) Reset() { *x = ReviewSpec{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1753,7 +1951,7 @@ func (x *ReviewSpec) String() string { func (*ReviewSpec) ProtoMessage() {} func (x *ReviewSpec) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[12] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1885,7 +2083,7 @@ type ReviewChanges struct { func (x *ReviewChanges) Reset() { *x = ReviewChanges{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1897,7 +2095,7 @@ func (x *ReviewChanges) String() string { func (*ReviewChanges) ProtoMessage() {} func (x *ReviewChanges) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[13] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2016,7 +2214,7 @@ type CurrentUserAssignments struct { func (x *CurrentUserAssignments) Reset() { *x = CurrentUserAssignments{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2028,7 +2226,7 @@ func (x *CurrentUserAssignments) String() string { func (*CurrentUserAssignments) ProtoMessage() {} func (x *CurrentUserAssignments) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[14] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2090,7 +2288,7 @@ type UserAssignments struct { func (x *UserAssignments) Reset() { *x = UserAssignments{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2102,7 +2300,7 @@ func (x *UserAssignments) String() string { func (*UserAssignments) ProtoMessage() {} func (x *UserAssignments) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[15] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2164,6 +2362,7 @@ type AccessListStatus struct { xxx_hidden_UserAssignments *UserAssignments `protobuf:"bytes,6,opt,name=user_assignments,json=userAssignments,proto3"` xxx_hidden_ScopedOwnerOf []string `protobuf:"bytes,7,rep,name=scoped_owner_of,json=scopedOwnerOf,proto3"` xxx_hidden_ScopedMemberOf []string `protobuf:"bytes,8,rep,name=scoped_member_of,json=scopedMemberOf,proto3"` + xxx_hidden_OwnerDisplays map[string]*UserDisplay `protobuf:"bytes,9,rep,name=owner_displays,json=ownerDisplays,proto3" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` XXX_raceDetectHookData protoimpl.RaceDetectHookData XXX_presence [1]uint32 unknownFields protoimpl.UnknownFields @@ -2172,7 +2371,7 @@ type AccessListStatus struct { func (x *AccessListStatus) Reset() { *x = AccessListStatus{} - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2184,7 +2383,7 @@ func (x *AccessListStatus) String() string { func (*AccessListStatus) ProtoMessage() {} func (x *AccessListStatus) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[16] + mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2251,14 +2450,21 @@ func (x *AccessListStatus) GetScopedMemberOf() []string { return nil } +func (x *AccessListStatus) GetOwnerDisplays() map[string]*UserDisplay { + if x != nil { + return x.xxx_hidden_OwnerDisplays + } + return nil +} + func (x *AccessListStatus) SetMemberCount(v uint32) { x.xxx_hidden_MemberCount = v - protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 8) + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 9) } func (x *AccessListStatus) SetMemberListCount(v uint32) { x.xxx_hidden_MemberListCount = v - protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 8) + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 9) } func (x *AccessListStatus) SetOwnerOf(v []string) { @@ -2285,6 +2491,10 @@ func (x *AccessListStatus) SetScopedMemberOf(v []string) { x.xxx_hidden_ScopedMemberOf = v } +func (x *AccessListStatus) SetOwnerDisplays(v map[string]*UserDisplay) { + x.xxx_hidden_OwnerDisplays = v +} + func (x *AccessListStatus) HasMemberCount() bool { if x == nil { return false @@ -2352,6 +2562,8 @@ type AccessListStatus_builder struct { // scoped_member_of describes scoped Access Lists where this Access List is an explicit member. // Each item is the scope-qualified name of the parent scoped Access List. ScopedMemberOf []string + // owner_displays contains display values for owners, keyed by owner username. + OwnerDisplays map[string]*UserDisplay } func (b0 AccessListStatus_builder) Build() *AccessListStatus { @@ -2359,11 +2571,11 @@ func (b0 AccessListStatus_builder) Build() *AccessListStatus { b, x := &b0, m0 _, _ = b, x if b.MemberCount != nil { - protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 8) + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 9) x.xxx_hidden_MemberCount = *b.MemberCount } if b.MemberListCount != nil { - protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 8) + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 9) x.xxx_hidden_MemberListCount = *b.MemberListCount } x.xxx_hidden_OwnerOf = b.OwnerOf @@ -2372,6 +2584,7 @@ func (b0 AccessListStatus_builder) Build() *AccessListStatus { x.xxx_hidden_UserAssignments = b.UserAssignments x.xxx_hidden_ScopedOwnerOf = b.ScopedOwnerOf x.xxx_hidden_ScopedMemberOf = b.ScopedMemberOf + x.xxx_hidden_OwnerDisplays = b.OwnerDisplays return m0 } @@ -2426,11 +2639,18 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "\fscoped_roles\x18\x03 \x03(\v2'.teleport.accesslist.v1.ScopedRoleGrantR\vscopedRoles\";\n" + "\x0fScopedRoleGrant\x12\x12\n" + "\x04role\x18\x01 \x01(\tR\x04role\x12\x14\n" + - "\x05scope\x18\x02 \x01(\tR\x05scope\"\x92\x01\n" + + "\x05scope\x18\x02 \x01(\tR\x05scope\"E\n" + + "\vUserDisplay\x12\x18\n" + + "\aprimary\x18\x01 \x01(\tR\aprimary\x12\x1c\n" + + "\tsecondary\x18\x02 \x01(\tR\tsecondary\"\xd0\x01\n" + "\x06Member\x12:\n" + "\x06header\x18\x01 \x01(\v2\".teleport.header.v1.ResourceHeaderR\x06header\x126\n" + "\x04spec\x18\x02 \x01(\v2\".teleport.accesslist.v1.MemberSpecR\x04spec\x12\x14\n" + - "\x05scope\x18\x03 \x01(\tR\x05scope\"\x98\x03\n" + + "\x05scope\x18\x03 \x01(\tR\x05scope\x12<\n" + + "\x06status\x18\x04 \x01(\v2$.teleport.accesslist.v1.MemberStatusR\x06status\"\x9c\x01\n" + + "\fMemberStatus\x12=\n" + + "\adisplay\x18\x01 \x01(\v2#.teleport.accesslist.v1.UserDisplayR\adisplay\x12M\n" + + "\x10added_by_display\x18\x02 \x01(\v2#.teleport.accesslist.v1.UserDisplayR\x0eaddedByDisplay\"\x98\x03\n" + "\n" + "MemberSpec\x12\x1f\n" + "\vaccess_list\x18\x01 \x01(\tR\n" + @@ -2467,7 +2687,7 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "\x0fmembership_type\x18\x02 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\x0emembershipType\"\xcd\x01\n" + "\x0fUserAssignments\x12[\n" + "\x0eownership_type\x18\x01 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\rownershipType\x12]\n" + - "\x0fmembership_type\x18\x02 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\x0emembershipType\"\xda\x03\n" + + "\x0fmembership_type\x18\x02 \x01(\x0e24.teleport.accesslist.v1.AccessListUserAssignmentTypeR\x0emembershipType\"\xa5\x05\n" + "\x10AccessListStatus\x12&\n" + "\fmember_count\x18\x01 \x01(\rH\x00R\vmemberCount\x88\x01\x01\x12/\n" + "\x11member_list_count\x18\x02 \x01(\rH\x01R\x0fmemberListCount\x88\x01\x01\x12\x19\n" + @@ -2476,7 +2696,11 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "\x18current_user_assignments\x18\x05 \x01(\v2..teleport.accesslist.v1.CurrentUserAssignmentsR\x16currentUserAssignments\x12R\n" + "\x10user_assignments\x18\x06 \x01(\v2'.teleport.accesslist.v1.UserAssignmentsR\x0fuserAssignments\x12&\n" + "\x0fscoped_owner_of\x18\a \x03(\tR\rscopedOwnerOf\x12(\n" + - "\x10scoped_member_of\x18\b \x03(\tR\x0escopedMemberOfB\x0f\n" + + "\x10scoped_member_of\x18\b \x03(\tR\x0escopedMemberOf\x12b\n" + + "\x0eowner_displays\x18\t \x03(\v2;.teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntryR\rownerDisplays\x1ae\n" + + "\x12OwnerDisplaysEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x129\n" + + "\x05value\x18\x02 \x01(\v2#.teleport.accesslist.v1.UserDisplayR\x05value:\x028\x01B\x0f\n" + "\r_member_countB\x14\n" + "\x12_member_list_count*\xb6\x01\n" + "\x0fReviewFrequency\x12 \n" + @@ -2507,7 +2731,7 @@ const file_teleport_accesslist_v1_accesslist_proto_rawDesc = "" + "*ACCESS_LIST_USER_ASSIGNMENT_TYPE_INHERITED\x10\x02BXZVgithub.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1;accesslistv1b\x06proto3" var file_teleport_accesslist_v1_accesslist_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_teleport_accesslist_v1_accesslist_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_teleport_accesslist_v1_accesslist_proto_msgTypes = make([]protoimpl.MessageInfo, 20) var file_teleport_accesslist_v1_accesslist_proto_goTypes = []any{ (ReviewFrequency)(0), // 0: teleport.accesslist.v1.ReviewFrequency (ReviewDayOfMonth)(0), // 1: teleport.accesslist.v1.ReviewDayOfMonth @@ -2523,23 +2747,26 @@ var file_teleport_accesslist_v1_accesslist_proto_goTypes = []any{ (*AccessListRequires)(nil), // 11: teleport.accesslist.v1.AccessListRequires (*AccessListGrants)(nil), // 12: teleport.accesslist.v1.AccessListGrants (*ScopedRoleGrant)(nil), // 13: teleport.accesslist.v1.ScopedRoleGrant - (*Member)(nil), // 14: teleport.accesslist.v1.Member - (*MemberSpec)(nil), // 15: teleport.accesslist.v1.MemberSpec - (*Review)(nil), // 16: teleport.accesslist.v1.Review - (*ReviewSpec)(nil), // 17: teleport.accesslist.v1.ReviewSpec - (*ReviewChanges)(nil), // 18: teleport.accesslist.v1.ReviewChanges - (*CurrentUserAssignments)(nil), // 19: teleport.accesslist.v1.CurrentUserAssignments - (*UserAssignments)(nil), // 20: teleport.accesslist.v1.UserAssignments - (*AccessListStatus)(nil), // 21: teleport.accesslist.v1.AccessListStatus - (*v1.ResourceHeader)(nil), // 22: teleport.header.v1.ResourceHeader - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 24: google.protobuf.Duration - (*v11.Trait)(nil), // 25: teleport.trait.v1.Trait + (*UserDisplay)(nil), // 14: teleport.accesslist.v1.UserDisplay + (*Member)(nil), // 15: teleport.accesslist.v1.Member + (*MemberStatus)(nil), // 16: teleport.accesslist.v1.MemberStatus + (*MemberSpec)(nil), // 17: teleport.accesslist.v1.MemberSpec + (*Review)(nil), // 18: teleport.accesslist.v1.Review + (*ReviewSpec)(nil), // 19: teleport.accesslist.v1.ReviewSpec + (*ReviewChanges)(nil), // 20: teleport.accesslist.v1.ReviewChanges + (*CurrentUserAssignments)(nil), // 21: teleport.accesslist.v1.CurrentUserAssignments + (*UserAssignments)(nil), // 22: teleport.accesslist.v1.UserAssignments + (*AccessListStatus)(nil), // 23: teleport.accesslist.v1.AccessListStatus + nil, // 24: teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntry + (*v1.ResourceHeader)(nil), // 25: teleport.header.v1.ResourceHeader + (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 27: google.protobuf.Duration + (*v11.Trait)(nil), // 28: teleport.trait.v1.Trait } var file_teleport_accesslist_v1_accesslist_proto_depIdxs = []int32{ - 22, // 0: teleport.accesslist.v1.AccessList.header:type_name -> teleport.header.v1.ResourceHeader + 25, // 0: teleport.accesslist.v1.AccessList.header:type_name -> teleport.header.v1.ResourceHeader 6, // 1: teleport.accesslist.v1.AccessList.spec:type_name -> teleport.accesslist.v1.AccessListSpec - 21, // 2: teleport.accesslist.v1.AccessList.status:type_name -> teleport.accesslist.v1.AccessListStatus + 23, // 2: teleport.accesslist.v1.AccessList.status:type_name -> teleport.accesslist.v1.AccessListStatus 7, // 3: teleport.accesslist.v1.AccessListSpec.owners:type_name -> teleport.accesslist.v1.AccessListOwner 8, // 4: teleport.accesslist.v1.AccessListSpec.audit:type_name -> teleport.accesslist.v1.AccessListAudit 11, // 5: teleport.accesslist.v1.AccessListSpec.membership_requires:type_name -> teleport.accesslist.v1.AccessListRequires @@ -2548,39 +2775,44 @@ var file_teleport_accesslist_v1_accesslist_proto_depIdxs = []int32{ 12, // 8: teleport.accesslist.v1.AccessListSpec.owner_grants:type_name -> teleport.accesslist.v1.AccessListGrants 3, // 9: teleport.accesslist.v1.AccessListOwner.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus 2, // 10: teleport.accesslist.v1.AccessListOwner.membership_kind:type_name -> teleport.accesslist.v1.MembershipKind - 23, // 11: teleport.accesslist.v1.AccessListAudit.next_audit_date:type_name -> google.protobuf.Timestamp + 26, // 11: teleport.accesslist.v1.AccessListAudit.next_audit_date:type_name -> google.protobuf.Timestamp 9, // 12: teleport.accesslist.v1.AccessListAudit.recurrence:type_name -> teleport.accesslist.v1.Recurrence 10, // 13: teleport.accesslist.v1.AccessListAudit.notifications:type_name -> teleport.accesslist.v1.Notifications 0, // 14: teleport.accesslist.v1.Recurrence.frequency:type_name -> teleport.accesslist.v1.ReviewFrequency 1, // 15: teleport.accesslist.v1.Recurrence.day_of_month:type_name -> teleport.accesslist.v1.ReviewDayOfMonth - 24, // 16: teleport.accesslist.v1.Notifications.start:type_name -> google.protobuf.Duration - 25, // 17: teleport.accesslist.v1.AccessListRequires.traits:type_name -> teleport.trait.v1.Trait - 25, // 18: teleport.accesslist.v1.AccessListGrants.traits:type_name -> teleport.trait.v1.Trait + 27, // 16: teleport.accesslist.v1.Notifications.start:type_name -> google.protobuf.Duration + 28, // 17: teleport.accesslist.v1.AccessListRequires.traits:type_name -> teleport.trait.v1.Trait + 28, // 18: teleport.accesslist.v1.AccessListGrants.traits:type_name -> teleport.trait.v1.Trait 13, // 19: teleport.accesslist.v1.AccessListGrants.scoped_roles:type_name -> teleport.accesslist.v1.ScopedRoleGrant - 22, // 20: teleport.accesslist.v1.Member.header:type_name -> teleport.header.v1.ResourceHeader - 15, // 21: teleport.accesslist.v1.Member.spec:type_name -> teleport.accesslist.v1.MemberSpec - 23, // 22: teleport.accesslist.v1.MemberSpec.joined:type_name -> google.protobuf.Timestamp - 23, // 23: teleport.accesslist.v1.MemberSpec.expires:type_name -> google.protobuf.Timestamp - 3, // 24: teleport.accesslist.v1.MemberSpec.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus - 2, // 25: teleport.accesslist.v1.MemberSpec.membership_kind:type_name -> teleport.accesslist.v1.MembershipKind - 22, // 26: teleport.accesslist.v1.Review.header:type_name -> teleport.header.v1.ResourceHeader - 17, // 27: teleport.accesslist.v1.Review.spec:type_name -> teleport.accesslist.v1.ReviewSpec - 23, // 28: teleport.accesslist.v1.ReviewSpec.review_date:type_name -> google.protobuf.Timestamp - 18, // 29: teleport.accesslist.v1.ReviewSpec.changes:type_name -> teleport.accesslist.v1.ReviewChanges - 11, // 30: teleport.accesslist.v1.ReviewChanges.membership_requirements_changed:type_name -> teleport.accesslist.v1.AccessListRequires - 0, // 31: teleport.accesslist.v1.ReviewChanges.review_frequency_changed:type_name -> teleport.accesslist.v1.ReviewFrequency - 1, // 32: teleport.accesslist.v1.ReviewChanges.review_day_of_month_changed:type_name -> teleport.accesslist.v1.ReviewDayOfMonth - 4, // 33: teleport.accesslist.v1.CurrentUserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 4, // 34: teleport.accesslist.v1.CurrentUserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 4, // 35: teleport.accesslist.v1.UserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 4, // 36: teleport.accesslist.v1.UserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType - 19, // 37: teleport.accesslist.v1.AccessListStatus.current_user_assignments:type_name -> teleport.accesslist.v1.CurrentUserAssignments - 20, // 38: teleport.accesslist.v1.AccessListStatus.user_assignments:type_name -> teleport.accesslist.v1.UserAssignments - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 25, // 20: teleport.accesslist.v1.Member.header:type_name -> teleport.header.v1.ResourceHeader + 17, // 21: teleport.accesslist.v1.Member.spec:type_name -> teleport.accesslist.v1.MemberSpec + 16, // 22: teleport.accesslist.v1.Member.status:type_name -> teleport.accesslist.v1.MemberStatus + 14, // 23: teleport.accesslist.v1.MemberStatus.display:type_name -> teleport.accesslist.v1.UserDisplay + 14, // 24: teleport.accesslist.v1.MemberStatus.added_by_display:type_name -> teleport.accesslist.v1.UserDisplay + 26, // 25: teleport.accesslist.v1.MemberSpec.joined:type_name -> google.protobuf.Timestamp + 26, // 26: teleport.accesslist.v1.MemberSpec.expires:type_name -> google.protobuf.Timestamp + 3, // 27: teleport.accesslist.v1.MemberSpec.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus + 2, // 28: teleport.accesslist.v1.MemberSpec.membership_kind:type_name -> teleport.accesslist.v1.MembershipKind + 25, // 29: teleport.accesslist.v1.Review.header:type_name -> teleport.header.v1.ResourceHeader + 19, // 30: teleport.accesslist.v1.Review.spec:type_name -> teleport.accesslist.v1.ReviewSpec + 26, // 31: teleport.accesslist.v1.ReviewSpec.review_date:type_name -> google.protobuf.Timestamp + 20, // 32: teleport.accesslist.v1.ReviewSpec.changes:type_name -> teleport.accesslist.v1.ReviewChanges + 11, // 33: teleport.accesslist.v1.ReviewChanges.membership_requirements_changed:type_name -> teleport.accesslist.v1.AccessListRequires + 0, // 34: teleport.accesslist.v1.ReviewChanges.review_frequency_changed:type_name -> teleport.accesslist.v1.ReviewFrequency + 1, // 35: teleport.accesslist.v1.ReviewChanges.review_day_of_month_changed:type_name -> teleport.accesslist.v1.ReviewDayOfMonth + 4, // 36: teleport.accesslist.v1.CurrentUserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 4, // 37: teleport.accesslist.v1.CurrentUserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 4, // 38: teleport.accesslist.v1.UserAssignments.ownership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 4, // 39: teleport.accesslist.v1.UserAssignments.membership_type:type_name -> teleport.accesslist.v1.AccessListUserAssignmentType + 21, // 40: teleport.accesslist.v1.AccessListStatus.current_user_assignments:type_name -> teleport.accesslist.v1.CurrentUserAssignments + 22, // 41: teleport.accesslist.v1.AccessListStatus.user_assignments:type_name -> teleport.accesslist.v1.UserAssignments + 24, // 42: teleport.accesslist.v1.AccessListStatus.owner_displays:type_name -> teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntry + 14, // 43: teleport.accesslist.v1.AccessListStatus.OwnerDisplaysEntry.value:type_name -> teleport.accesslist.v1.UserDisplay + 44, // [44:44] is the sub-list for method output_type + 44, // [44:44] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name } func init() { file_teleport_accesslist_v1_accesslist_proto_init() } @@ -2588,14 +2820,14 @@ func file_teleport_accesslist_v1_accesslist_proto_init() { if File_teleport_accesslist_v1_accesslist_proto != nil { return } - file_teleport_accesslist_v1_accesslist_proto_msgTypes[16].OneofWrappers = []any{} + file_teleport_accesslist_v1_accesslist_proto_msgTypes[18].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_accesslist_v1_accesslist_proto_rawDesc), len(file_teleport_accesslist_v1_accesslist_proto_rawDesc)), NumEnums: 5, - NumMessages: 17, + NumMessages: 20, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/teleport/accesslist/v1/accesslist.proto b/api/proto/teleport/accesslist/v1/accesslist.proto index 9b7ad8afe52..fc33ff922c0 100644 --- a/api/proto/teleport/accesslist/v1/accesslist.proto +++ b/api/proto/teleport/accesslist/v1/accesslist.proto @@ -187,6 +187,16 @@ message ScopedRoleGrant { string scope = 2; } +// UserDisplay contains display values derived from a user. An empty message +// means the user has no primary/secondary distinct from the username; the +// absence of this message means the user was not found. +message UserDisplay { + // primary is a human-readable display name when distinct from username. + string primary = 1; + // secondary is supporting display context when distinct from username. + string secondary = 2; +} + // Member describes a member of an Access List. message Member { // header is the header for the resource. @@ -198,6 +208,17 @@ message Member { // scope is the scope of the Access List member, it must be equal to the // scope of the parent Access List. string scope = 3; + + // status contains dynamically calculated fields. + MemberStatus status = 4; +} + +// MemberStatus contains dynamic fields calculated during retrieval. +message MemberStatus { + // display contains display values for the member user. + UserDisplay display = 1; + // added_by_display contains display values for the user that added the member. + UserDisplay added_by_display = 2; } // MemberSpec is the specification for an Access List member. @@ -372,4 +393,6 @@ message AccessListStatus { // scoped_member_of describes scoped Access Lists where this Access List is an explicit member. // Each item is the scope-qualified name of the parent scoped Access List. repeated string scoped_member_of = 8; + // owner_displays contains display values for owners, keyed by owner username. + map owner_displays = 9; } diff --git a/api/types/accesslist/accesslist.go b/api/types/accesslist/accesslist.go index 4391a1ac6b6..8c48e6d8499 100644 --- a/api/types/accesslist/accesslist.go +++ b/api/types/accesslist/accesslist.go @@ -357,6 +357,10 @@ type Status struct { // MemberOf is a list of Access List UUIDs where this access list is an explicit member. MemberOf []string `json:"member_of" yaml:"member_of"` + // OwnerDisplays contains display values for owners, keyed by owner username. + // It is ignored when marshaling so tctl users do not mistake these read-time + // values for fields they could update with resource YAML. + OwnerDisplays map[string]types.UserDisplay `json:"-" yaml:"-"` // ScopedOwnerOf is a list of scope-qualified names of scoped access lists // where this access list is an explicit owner. ScopedOwnerOf []string `json:"scoped_owner_of" yaml:"scoped_owner_of"` diff --git a/api/types/accesslist/accesslist_test.go b/api/types/accesslist/accesslist_test.go index c1b8e8e408c..d1aa0b35503 100644 --- a/api/types/accesslist/accesslist_test.go +++ b/api/types/accesslist/accesslist_test.go @@ -26,6 +26,7 @@ import ( "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/header" "github.com/gravitational/teleport/api/utils/testutils/structfill" ) @@ -524,6 +525,9 @@ func TestEqualIgnoreEphemeralFields(t *testing.T) { al2 := createAccessList("test1") al2.Status.OwnerOf = []string{"different", "lists"} al2.Status.MemberOf = []string{"other", "lists"} + al2.Status.OwnerDisplays = map[string]types.UserDisplay{ + "owner1": {Primary: "Owner Name", Secondary: "owner@example.com"}, + } result := EqualAccessLists(al1, al2, WithIgnoreEphemeralFields()) require.True(t, result) diff --git a/api/types/accesslist/convert/v1/accesslist.go b/api/types/accesslist/convert/v1/accesslist.go index ee73bb9f811..4e3446fac01 100644 --- a/api/types/accesslist/convert/v1/accesslist.go +++ b/api/types/accesslist/convert/v1/accesslist.go @@ -24,6 +24,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" headerv1 "github.com/gravitational/teleport/api/types/header/convert/v1" traitv1 "github.com/gravitational/teleport/api/types/trait/convert/v1" @@ -151,6 +152,51 @@ func ConvertGrantsFromProto(protoGrants *accesslistv1.AccessListGrants) accessli } } +// ToUserDisplayProto converts display values into the access list proto shape. +func ToUserDisplayProto(display types.UserDisplay) *accesslistv1.UserDisplay { + return &accesslistv1.UserDisplay{ + Primary: display.Primary, + Secondary: display.Secondary, + } +} + +// FromUserDisplayProto converts access list proto display values into the shared type. +func FromUserDisplayProto(display *accesslistv1.UserDisplay) types.UserDisplay { + if display == nil { + return types.UserDisplay{} + } + return types.UserDisplay{ + Primary: display.GetPrimary(), + Secondary: display.GetSecondary(), + } +} + +// ToUserDisplaysProto converts display values keyed by username into proto display values. +func ToUserDisplaysProto(displays map[string]types.UserDisplay) map[string]*accesslistv1.UserDisplay { + if displays == nil { + return nil + } + + out := make(map[string]*accesslistv1.UserDisplay, len(displays)) + for username, display := range displays { + out[username] = ToUserDisplayProto(display) + } + return out +} + +// FromUserDisplaysProto converts proto display values keyed by username into the shared type. +func FromUserDisplaysProto(displays map[string]*accesslistv1.UserDisplay) map[string]types.UserDisplay { + if displays == nil { + return nil + } + + out := make(map[string]types.UserDisplay, len(displays)) + for username, display := range displays { + out[username] = FromUserDisplayProto(display) + } + return out +} + func convertScopedRoleGrantsFromProto(scopedRoleGrants []*accesslistv1.ScopedRoleGrant) []accesslist.ScopedRoleGrant { if scopedRoleGrants == nil { return nil @@ -240,6 +286,7 @@ func convertStatusToProto(status *accesslist.Status) *accesslistv1.AccessListSta MemberOf: status.MemberOf, CurrentUserAssignments: toCurrentUserAssignmentsProto(status.CurrentUserAssignments), UserAssignments: toUserAssignmentsProto(status.UserAssignments), + OwnerDisplays: ToUserDisplaysProto(status.OwnerDisplays), ScopedOwnerOf: status.ScopedOwnerOf, ScopedMemberOf: status.ScopedMemberOf, } @@ -263,6 +310,13 @@ func fromStatusProto(msg *accesslistv1.AccessList) *accesslist.Status { } } +// WithOwnerDisplaysField sets the "status.owner_displays" field to the provided proto value. +func WithOwnerDisplaysField(protoStatus *accesslistv1.AccessListStatus) AccessListOption { + return func(a *accesslist.AccessList) { + a.Status.OwnerDisplays = FromUserDisplaysProto(protoStatus.GetOwnerDisplays()) + } +} + func copyPointer[T any](val *T) *T { if val == nil { return nil diff --git a/api/types/accesslist/convert/v1/accesslist_test.go b/api/types/accesslist/convert/v1/accesslist_test.go index 8c97001b0d4..410c6ef3932 100644 --- a/api/types/accesslist/convert/v1/accesslist_test.go +++ b/api/types/accesslist/convert/v1/accesslist_test.go @@ -91,6 +91,55 @@ func TestWithOwnersIneligibleStatusField(t *testing.T) { })) } +func TestUserDisplayProtoConversion(t *testing.T) { + t.Parallel() + + require.Equal(t, &accesslistv1.UserDisplay{}, ToUserDisplayProto(types.UserDisplay{})) + require.Equal(t, types.UserDisplay{}, FromUserDisplayProto(nil)) + require.Equal(t, types.UserDisplay{}, FromUserDisplayProto(&accesslistv1.UserDisplay{})) + + display := types.UserDisplay{Primary: "Display Name", Secondary: "display@example.com"} + require.Equal(t, display, FromUserDisplayProto(ToUserDisplayProto(display))) +} + +func TestUserDisplaysProtoConversion(t *testing.T) { + t.Parallel() + + require.Nil(t, FromUserDisplaysProto(nil)) + + displays := map[string]*accesslistv1.UserDisplay{ + "empty": {}, + "populated": {Primary: "Display Name", Secondary: "display@example.com"}, + "missing": nil, + } + + require.Equal(t, map[string]types.UserDisplay{ + "empty": {}, + "populated": {Primary: "Display Name", Secondary: "display@example.com"}, + "missing": {}, + }, FromUserDisplaysProto(displays)) +} + +func TestWithOwnerDisplaysField(t *testing.T) { + t.Parallel() + + accessList := newAccessList(t, "access-list") + accessList.Status.OwnerDisplays = map[string]types.UserDisplay{ + "test-user1": {Primary: "Test User", Secondary: "test@example.com"}, + "test-user2": {}, + } + protoAccessList := ToProto(accessList) + + converted, err := FromProto(protoAccessList) + require.NoError(t, err) + require.Empty(t, converted.Status.OwnerDisplays) + require.Equal(t, accessList.Status.MemberCount, converted.Status.MemberCount) + + converted, err = FromProto(protoAccessList, WithOwnerDisplaysField(protoAccessList.GetStatus())) + require.NoError(t, err) + require.Empty(t, cmp.Diff(accessList.Status.OwnerDisplays, converted.Status.OwnerDisplays)) +} + func TestRoundtrip(t *testing.T) { t.Parallel() diff --git a/api/types/accesslist/convert/v1/member.go b/api/types/accesslist/convert/v1/member.go index 5e34cec9b1d..b9014f343d6 100644 --- a/api/types/accesslist/convert/v1/member.go +++ b/api/types/accesslist/convert/v1/member.go @@ -20,6 +20,7 @@ import ( "github.com/gravitational/trace" accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" headerv1 "github.com/gravitational/teleport/api/types/header/convert/v1" "github.com/gravitational/teleport/api/utils" @@ -65,7 +66,7 @@ func FromMembersProto(msgs []*accesslistv1.Member) ([]*accesslist.AccessListMemb members := make([]*accesslist.AccessListMember, len(msgs)) for i, msg := range msgs { var err error - members[i], err = FromMemberProto(msg, WithMemberIneligibleStatusField(msg)) + members[i], err = FromMemberProto(msg, WithMemberIneligibleStatusField(msg), WithMemberStatusField(msg)) if err != nil { return nil, trace.Wrap(err) } @@ -98,9 +99,45 @@ func ToMemberProto(member *accesslist.AccessListMember) *accesslistv1.Member { IneligibleStatus: ineligibleStatus, MembershipKind: membershipKind, }, + Status: toMemberStatusProto(member.Status), } } +func toMemberStatusProto(status *accesslist.AccessListMemberStatus) *accesslistv1.MemberStatus { + if status == nil { + return nil + } + return &accesslistv1.MemberStatus{ + Display: toUserDisplayProtoOrNil(status.Display), + AddedByDisplay: toUserDisplayProtoOrNil(status.AddedByDisplay), + } +} + +func fromMemberStatusProto(status *accesslistv1.MemberStatus) *accesslist.AccessListMemberStatus { + if status == nil { + return nil + } + return &accesslist.AccessListMemberStatus{ + Display: fromUserDisplayProtoOrNil(status.GetDisplay()), + AddedByDisplay: fromUserDisplayProtoOrNil(status.GetAddedByDisplay()), + } +} + +func toUserDisplayProtoOrNil(display *types.UserDisplay) *accesslistv1.UserDisplay { + if display == nil { + return nil + } + return ToUserDisplayProto(*display) +} + +func fromUserDisplayProtoOrNil(display *accesslistv1.UserDisplay) *types.UserDisplay { + if display == nil { + return nil + } + out := FromUserDisplayProto(display) + return &out +} + // ToMembersProto converts a list of internal access list members into a list of v1 access list members. func ToMembersProto(members []*accesslist.AccessListMember) []*accesslistv1.Member { out := make([]*accesslistv1.Member, len(members)) @@ -121,3 +158,10 @@ func WithMemberIneligibleStatusField(protoMember *accesslistv1.Member) MemberOpt m.Spec.IneligibleStatus = ineligibleStatus } } + +// WithMemberStatusField sets the "status" field to the provided proto value. +func WithMemberStatusField(protoMember *accesslistv1.Member) MemberOption { + return func(m *accesslist.AccessListMember) { + m.Status = fromMemberStatusProto(protoMember.GetStatus()) + } +} diff --git a/api/types/accesslist/convert/v1/member_test.go b/api/types/accesslist/convert/v1/member_test.go index 1b0e171ec87..953b7da9dac 100644 --- a/api/types/accesslist/convert/v1/member_test.go +++ b/api/types/accesslist/convert/v1/member_test.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/header" ) @@ -55,6 +56,49 @@ func TestWithMemberIneligibleStatusField(t *testing.T) { require.Equal(t, accesslistv1.IneligibleStatus_INELIGIBLE_STATUS_EXPIRED.Enum().String(), alMember.Spec.IneligibleStatus) } +func TestMemberStatusIgnoredByDefault(t *testing.T) { + member := newAccessListMember(t, "access-list-member") + member.Status = &accesslist.AccessListMemberStatus{ + Display: &types.UserDisplay{Primary: "Member Name", Secondary: "member@example.com"}, + AddedByDisplay: &types.UserDisplay{Primary: "Adder Name", Secondary: "adder@example.com"}, + } + + converted, err := FromMemberProto(ToMemberProto(member)) + require.NoError(t, err) + + require.Nil(t, converted.Status) +} + +func TestWithMemberStatusField(t *testing.T) { + member := newAccessListMember(t, "access-list-member") + member.Status = &accesslist.AccessListMemberStatus{ + Display: &types.UserDisplay{Primary: "Member Name", Secondary: "member@example.com"}, + AddedByDisplay: &types.UserDisplay{Primary: "Adder Name", Secondary: "adder@example.com"}, + } + protoMember := ToMemberProto(member) + + converted, err := FromMemberProto(protoMember, WithMemberStatusField(protoMember)) + require.NoError(t, err) + + require.Empty(t, cmp.Diff(member, converted)) +} + +func TestWithMemberStatusFieldPreservesEmptyDisplay(t *testing.T) { + protoMember := ToMemberProto(newAccessListMember(t, "access-list-member")) + protoMember.Status = &accesslistv1.MemberStatus{ + Display: &accesslistv1.UserDisplay{}, + AddedByDisplay: &accesslistv1.UserDisplay{Primary: "Adder Name"}, + } + + member, err := FromMemberProto(protoMember, WithMemberStatusField(protoMember)) + require.NoError(t, err) + + require.NotNil(t, member.Status) + require.NotNil(t, member.Status.Display) + require.Empty(t, *member.Status.Display) + require.Equal(t, &types.UserDisplay{Primary: "Adder Name"}, member.Status.AddedByDisplay) +} + // Make sure that we don't panic if any of the message fields are missing. func TestMemberFromProtoNils(t *testing.T) { testCases := []struct { diff --git a/api/types/accesslist/derived.gen.go b/api/types/accesslist/derived.gen.go index a9ad547912c..b51326460a0 100644 --- a/api/types/accesslist/derived.gen.go +++ b/api/types/accesslist/derived.gen.go @@ -3,6 +3,7 @@ package accesslist import ( + types "github.com/gravitational/teleport/api/types" header "github.com/gravitational/teleport/api/types/header" "time" ) @@ -57,6 +58,12 @@ func deriveDeepCopyAccessListMember(dst, src *AccessListMember) { deriveDeepCopy_2(field, &src.Spec) dst.Spec = *field }() + if src.Status == nil { + dst.Status = nil + } else { + dst.Status = new(AccessListMemberStatus) + deriveDeepCopy_3(dst.Status, src.Status) + } dst.Scope = src.Scope } @@ -69,7 +76,7 @@ func deriveDeepCopyReview(dst, src *Review) { }() func() { field := new(ReviewSpec) - deriveDeepCopy_3(field, &src.Spec) + deriveDeepCopy_4(field, &src.Spec) dst.Spec = *field }() dst.Scope = src.Scope @@ -122,7 +129,7 @@ func deriveDeepCopy(dst, src *header.ResourceHeader) { dst.Version = src.Version func() { field := new(header.Metadata) - deriveDeepCopy_4(field, &src.Metadata) + deriveDeepCopy_5(field, &src.Metadata) dst.Metadata = *field }() } @@ -152,27 +159,27 @@ func deriveDeepCopy_(dst, src *Spec) { } func() { field := new(Audit) - deriveDeepCopy_5(field, &src.Audit) + deriveDeepCopy_6(field, &src.Audit) dst.Audit = *field }() func() { field := new(Requires) - deriveDeepCopy_6(field, &src.MembershipRequires) + deriveDeepCopy_7(field, &src.MembershipRequires) dst.MembershipRequires = *field }() func() { field := new(Requires) - deriveDeepCopy_6(field, &src.OwnershipRequires) + deriveDeepCopy_7(field, &src.OwnershipRequires) dst.OwnershipRequires = *field }() func() { field := new(Grants) - deriveDeepCopy_7(field, &src.Grants) + deriveDeepCopy_8(field, &src.Grants) dst.Grants = *field }() func() { field := new(Grants) - deriveDeepCopy_7(field, &src.OwnerGrants) + deriveDeepCopy_8(field, &src.OwnerGrants) dst.OwnerGrants = *field }() } @@ -227,6 +234,12 @@ func deriveDeepCopy_1(dst, src *Status) { } copy(dst.MemberOf, src.MemberOf) } + if src.OwnerDisplays != nil { + dst.OwnerDisplays = make(map[string]types.UserDisplay, len(src.OwnerDisplays)) + deriveDeepCopy_9(dst.OwnerDisplays, src.OwnerDisplays) + } else { + dst.OwnerDisplays = nil + } if src.ScopedOwnerOf == nil { dst.ScopedOwnerOf = nil } else { @@ -284,12 +297,12 @@ func deriveDeepCopy_2(dst, src *AccessListMemberSpec) { dst.Title = src.Title func() { field := new(time.Time) - deriveDeepCopy_8(field, &src.Joined) + deriveDeepCopy_10(field, &src.Joined) dst.Joined = *field }() func() { field := new(time.Time) - deriveDeepCopy_8(field, &src.Expires) + deriveDeepCopy_10(field, &src.Expires) dst.Expires = *field }() dst.Reason = src.Reason @@ -299,7 +312,23 @@ func deriveDeepCopy_2(dst, src *AccessListMemberSpec) { } // deriveDeepCopy_3 recursively copies the contents of src into dst. -func deriveDeepCopy_3(dst, src *ReviewSpec) { +func deriveDeepCopy_3(dst, src *AccessListMemberStatus) { + if src.Display == nil { + dst.Display = nil + } else { + dst.Display = new(types.UserDisplay) + *dst.Display = *src.Display + } + if src.AddedByDisplay == nil { + dst.AddedByDisplay = nil + } else { + dst.AddedByDisplay = new(types.UserDisplay) + *dst.AddedByDisplay = *src.AddedByDisplay + } +} + +// deriveDeepCopy_4 recursively copies the contents of src into dst. +func deriveDeepCopy_4(dst, src *ReviewSpec) { dst.AccessList = src.AccessList if src.Reviewers == nil { dst.Reviewers = nil @@ -321,13 +350,13 @@ func deriveDeepCopy_3(dst, src *ReviewSpec) { } func() { field := new(time.Time) - deriveDeepCopy_8(field, &src.ReviewDate) + deriveDeepCopy_10(field, &src.ReviewDate) dst.ReviewDate = *field }() dst.Notes = src.Notes func() { field := new(ReviewChanges) - deriveDeepCopy_9(field, &src.Changes) + deriveDeepCopy_11(field, &src.Changes) dst.Changes = *field }() } @@ -384,37 +413,37 @@ func deriveTeleportEqual_6(this, that *Grants) bool { deriveTeleportEqual_10(this.ScopedRoles, that.ScopedRoles) } -// deriveDeepCopy_4 recursively copies the contents of src into dst. -func deriveDeepCopy_4(dst, src *header.Metadata) { +// deriveDeepCopy_5 recursively copies the contents of src into dst. +func deriveDeepCopy_5(dst, src *header.Metadata) { dst.Name = src.Name dst.Description = src.Description if src.Labels != nil { dst.Labels = make(map[string]string, len(src.Labels)) - deriveDeepCopy_10(dst.Labels, src.Labels) + deriveDeepCopy_12(dst.Labels, src.Labels) } else { dst.Labels = nil } func() { field := new(time.Time) - deriveDeepCopy_8(field, &src.Expires) + deriveDeepCopy_10(field, &src.Expires) dst.Expires = *field }() dst.Revision = src.Revision } -// deriveDeepCopy_5 recursively copies the contents of src into dst. -func deriveDeepCopy_5(dst, src *Audit) { +// deriveDeepCopy_6 recursively copies the contents of src into dst. +func deriveDeepCopy_6(dst, src *Audit) { func() { field := new(time.Time) - deriveDeepCopy_8(field, &src.NextAuditDate) + deriveDeepCopy_10(field, &src.NextAuditDate) dst.NextAuditDate = *field }() dst.Recurrence = src.Recurrence dst.Notifications = src.Notifications } -// deriveDeepCopy_6 recursively copies the contents of src into dst. -func deriveDeepCopy_6(dst, src *Requires) { +// deriveDeepCopy_7 recursively copies the contents of src into dst. +func deriveDeepCopy_7(dst, src *Requires) { if src.Roles == nil { dst.Roles = nil } else { @@ -435,14 +464,14 @@ func deriveDeepCopy_6(dst, src *Requires) { } if src.Traits != nil { dst.Traits = make(map[string][]string, len(src.Traits)) - deriveDeepCopy_11(dst.Traits, src.Traits) + deriveDeepCopy_13(dst.Traits, src.Traits) } else { dst.Traits = nil } } -// deriveDeepCopy_7 recursively copies the contents of src into dst. -func deriveDeepCopy_7(dst, src *Grants) { +// deriveDeepCopy_8 recursively copies the contents of src into dst. +func deriveDeepCopy_8(dst, src *Grants) { if src.Roles == nil { dst.Roles = nil } else { @@ -463,7 +492,7 @@ func deriveDeepCopy_7(dst, src *Grants) { } if src.Traits != nil { dst.Traits = make(map[string][]string, len(src.Traits)) - deriveDeepCopy_11(dst.Traits, src.Traits) + deriveDeepCopy_13(dst.Traits, src.Traits) } else { dst.Traits = nil } @@ -487,18 +516,25 @@ func deriveDeepCopy_7(dst, src *Grants) { } } -// deriveDeepCopy_8 recursively copies the contents of src into dst. -func deriveDeepCopy_8(dst, src *time.Time) { +// deriveDeepCopy_9 recursively copies the contents of src into dst. +func deriveDeepCopy_9(dst, src map[string]types.UserDisplay) { + for src_key, src_value := range src { + dst[src_key] = src_value + } +} + +// deriveDeepCopy_10 recursively copies the contents of src into dst. +func deriveDeepCopy_10(dst, src *time.Time) { *dst = *src } -// deriveDeepCopy_9 recursively copies the contents of src into dst. -func deriveDeepCopy_9(dst, src *ReviewChanges) { +// deriveDeepCopy_11 recursively copies the contents of src into dst. +func deriveDeepCopy_11(dst, src *ReviewChanges) { if src.MembershipRequirementsChanged == nil { dst.MembershipRequirementsChanged = nil } else { dst.MembershipRequirementsChanged = new(Requires) - deriveDeepCopy_6(dst.MembershipRequirementsChanged, src.MembershipRequirementsChanged) + deriveDeepCopy_7(dst.MembershipRequirementsChanged, src.MembershipRequirementsChanged) } if src.RemovedMembers == nil { dst.RemovedMembers = nil @@ -612,15 +648,15 @@ func deriveTeleportEqual_10(this, that []ScopedRoleGrant) bool { return true } -// deriveDeepCopy_10 recursively copies the contents of src into dst. -func deriveDeepCopy_10(dst, src map[string]string) { +// deriveDeepCopy_12 recursively copies the contents of src into dst. +func deriveDeepCopy_12(dst, src map[string]string) { for src_key, src_value := range src { dst[src_key] = src_value } } -// deriveDeepCopy_11 recursively copies the contents of src into dst. -func deriveDeepCopy_11(dst, src map[string][]string) { +// deriveDeepCopy_13 recursively copies the contents of src into dst. +func deriveDeepCopy_13(dst, src map[string][]string) { for src_key, src_value := range src { if src_value == nil { dst[src_key] = nil diff --git a/api/types/accesslist/member.go b/api/types/accesslist/member.go index 2f3ee32fe94..f622ec1d4e6 100644 --- a/api/types/accesslist/member.go +++ b/api/types/accesslist/member.go @@ -35,11 +35,26 @@ type AccessListMember struct { // Spec is the specification for the access list member. Spec AccessListMemberSpec `json:"spec" yaml:"spec"` + // Status contains dynamically calculated fields. It is ignored when + // marshaling so tctl users do not mistake these read-time values for fields + // they could update with resource YAML. + Status *AccessListMemberStatus `json:"-" yaml:"-"` + // Scope is the scope of the access list member, it must be equal to the // scope of the parent access list. Scope string `json:"scope" yaml:"scope"` } +// AccessListMemberStatus contains dynamic fields calculated during retrieval. +// Its fields are ignored when marshaling for the same reason as AccessListMember.Status +type AccessListMemberStatus struct { + // Display contains display values for the member user. + Display *types.UserDisplay `json:"-" yaml:"-"` + + // AddedByDisplay contains display values for the user that added the member. + AddedByDisplay *types.UserDisplay `json:"-" yaml:"-"` +} + // AccessListMemberSpec describes the specification of a member of an access list. type AccessListMemberSpec struct { // AccessList is the name of the associated access list. diff --git a/api/types/accesslist/member_test.go b/api/types/accesslist/member_test.go index f9efdd00fbb..2e3cc6a10f5 100644 --- a/api/types/accesslist/member_test.go +++ b/api/types/accesslist/member_test.go @@ -70,3 +70,15 @@ func TestAccessListMemberClone(t *testing.T) { require.Empty(t, cmp.Diff(item, cpy)) require.NotSame(t, item, cpy) } + +func TestAccessListMemberEqualIgnoresStatus(t *testing.T) { + status := AccessListMemberStatus{ + Display: &types.UserDisplay{Primary: "Member Name", Secondary: "member@example.com"}, + AddedByDisplay: &types.UserDisplay{Primary: "Adder Name", Secondary: "adder@example.com"}, + } + item := &AccessListMember{} + other := item.Clone() + other.Status = &status + + require.True(t, item.IsEqual(other)) +} diff --git a/api/types/user_display.go b/api/types/user_display.go index 6d2ecbe253c..90223215b7a 100644 --- a/api/types/user_display.go +++ b/api/types/user_display.go @@ -57,9 +57,9 @@ const ( // UserDisplay contains display values derived from the user. type UserDisplay struct { // Primary is a human-readable display name when distinct from username. - Primary string + Primary string `json:"primary,omitempty"` // Secondary is supporting display context when distinct from username. - Secondary string + Secondary string `json:"secondary,omitempty"` } // GetDisplay returns display values derived from the user. diff --git a/gen/proto/ts/teleport/accesslist/v1/accesslist_pb.ts b/gen/proto/ts/teleport/accesslist/v1/accesslist_pb.ts index b4fd60c5267..7ed67885c83 100644 --- a/gen/proto/ts/teleport/accesslist/v1/accesslist_pb.ts +++ b/gen/proto/ts/teleport/accesslist/v1/accesslist_pb.ts @@ -299,6 +299,27 @@ export interface ScopedRoleGrant { */ scope: string; } +/** + * UserDisplay contains display values derived from a user. An empty message + * means the user has no primary/secondary distinct from the username; the + * absence of this message means the user was not found. + * + * @generated from protobuf message teleport.accesslist.v1.UserDisplay + */ +export interface UserDisplay { + /** + * primary is a human-readable display name when distinct from username. + * + * @generated from protobuf field: string primary = 1; + */ + primary: string; + /** + * secondary is supporting display context when distinct from username. + * + * @generated from protobuf field: string secondary = 2; + */ + secondary: string; +} /** * Member describes a member of an Access List. * @@ -324,6 +345,31 @@ export interface Member { * @generated from protobuf field: string scope = 3; */ scope: string; + /** + * status contains dynamically calculated fields. + * + * @generated from protobuf field: teleport.accesslist.v1.MemberStatus status = 4; + */ + status?: MemberStatus; +} +/** + * MemberStatus contains dynamic fields calculated during retrieval. + * + * @generated from protobuf message teleport.accesslist.v1.MemberStatus + */ +export interface MemberStatus { + /** + * display contains display values for the member user. + * + * @generated from protobuf field: teleport.accesslist.v1.UserDisplay display = 1; + */ + display?: UserDisplay; + /** + * added_by_display contains display values for the user that added the member. + * + * @generated from protobuf field: teleport.accesslist.v1.UserDisplay added_by_display = 2; + */ + addedByDisplay?: UserDisplay; } /** * MemberSpec is the specification for an Access List member. @@ -586,6 +632,14 @@ export interface AccessListStatus { * @generated from protobuf field: repeated string scoped_member_of = 8; */ scopedMemberOf: string[]; + /** + * owner_displays contains display values for owners, keyed by owner username. + * + * @generated from protobuf field: map owner_displays = 9; + */ + ownerDisplays: { + [key: string]: UserDisplay; + }; } /** * ReviewFrequency is the frequency of reviews. @@ -1316,12 +1370,68 @@ class ScopedRoleGrant$Type extends MessageType { */ export const ScopedRoleGrant = new ScopedRoleGrant$Type(); // @generated message type with reflection information, may provide speed optimized methods +class UserDisplay$Type extends MessageType { + constructor() { + super("teleport.accesslist.v1.UserDisplay", [ + { no: 1, name: "primary", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "secondary", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): UserDisplay { + const message = globalThis.Object.create((this.messagePrototype!)); + message.primary = ""; + message.secondary = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserDisplay): UserDisplay { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string primary */ 1: + message.primary = reader.string(); + break; + case /* string secondary */ 2: + message.secondary = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserDisplay, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string primary = 1; */ + if (message.primary !== "") + writer.tag(1, WireType.LengthDelimited).string(message.primary); + /* string secondary = 2; */ + if (message.secondary !== "") + writer.tag(2, WireType.LengthDelimited).string(message.secondary); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.accesslist.v1.UserDisplay + */ +export const UserDisplay = new UserDisplay$Type(); +// @generated message type with reflection information, may provide speed optimized methods class Member$Type extends MessageType { constructor() { super("teleport.accesslist.v1.Member", [ { no: 1, name: "header", kind: "message", T: () => ResourceHeader }, { no: 2, name: "spec", kind: "message", T: () => MemberSpec }, - { no: 3, name: "scope", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + { no: 3, name: "scope", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "status", kind: "message", T: () => MemberStatus } ]); } create(value?: PartialMessage): Member { @@ -1345,6 +1455,9 @@ class Member$Type extends MessageType { case /* string scope */ 3: message.scope = reader.string(); break; + case /* teleport.accesslist.v1.MemberStatus status */ 4: + message.status = MemberStatus.internalBinaryRead(reader, reader.uint32(), options, message.status); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -1366,6 +1479,9 @@ class Member$Type extends MessageType { /* string scope = 3; */ if (message.scope !== "") writer.tag(3, WireType.LengthDelimited).string(message.scope); + /* teleport.accesslist.v1.MemberStatus status = 4; */ + if (message.status) + MemberStatus.internalBinaryWrite(message.status, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -1377,6 +1493,59 @@ class Member$Type extends MessageType { */ export const Member = new Member$Type(); // @generated message type with reflection information, may provide speed optimized methods +class MemberStatus$Type extends MessageType { + constructor() { + super("teleport.accesslist.v1.MemberStatus", [ + { no: 1, name: "display", kind: "message", T: () => UserDisplay }, + { no: 2, name: "added_by_display", kind: "message", T: () => UserDisplay } + ]); + } + create(value?: PartialMessage): MemberStatus { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: MemberStatus): MemberStatus { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* teleport.accesslist.v1.UserDisplay display */ 1: + message.display = UserDisplay.internalBinaryRead(reader, reader.uint32(), options, message.display); + break; + case /* teleport.accesslist.v1.UserDisplay added_by_display */ 2: + message.addedByDisplay = UserDisplay.internalBinaryRead(reader, reader.uint32(), options, message.addedByDisplay); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: MemberStatus, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* teleport.accesslist.v1.UserDisplay display = 1; */ + if (message.display) + UserDisplay.internalBinaryWrite(message.display, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* teleport.accesslist.v1.UserDisplay added_by_display = 2; */ + if (message.addedByDisplay) + UserDisplay.internalBinaryWrite(message.addedByDisplay, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.accesslist.v1.MemberStatus + */ +export const MemberStatus = new MemberStatus$Type(); +// @generated message type with reflection information, may provide speed optimized methods class MemberSpec$Type extends MessageType { constructor() { super("teleport.accesslist.v1.MemberSpec", [ @@ -1814,7 +1983,8 @@ class AccessListStatus$Type extends MessageType { { no: 5, name: "current_user_assignments", kind: "message", T: () => CurrentUserAssignments }, { no: 6, name: "user_assignments", kind: "message", T: () => UserAssignments }, { no: 7, name: "scoped_owner_of", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, - { no: 8, name: "scoped_member_of", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } + { no: 8, name: "scoped_member_of", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 9, name: "owner_displays", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => UserDisplay } } ]); } create(value?: PartialMessage): AccessListStatus { @@ -1823,6 +1993,7 @@ class AccessListStatus$Type extends MessageType { message.memberOf = []; message.scopedOwnerOf = []; message.scopedMemberOf = []; + message.ownerDisplays = {}; if (value !== undefined) reflectionMergePartial(this, message, value); return message; @@ -1856,6 +2027,9 @@ class AccessListStatus$Type extends MessageType { case /* repeated string scoped_member_of */ 8: message.scopedMemberOf.push(reader.string()); break; + case /* map owner_displays */ 9: + this.binaryReadMap9(message.ownerDisplays, reader, options); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -1867,6 +2041,22 @@ class AccessListStatus$Type extends MessageType { } return message; } + private binaryReadMap9(map: AccessListStatus["ownerDisplays"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof AccessListStatus["ownerDisplays"] | undefined, val: AccessListStatus["ownerDisplays"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = UserDisplay.internalBinaryRead(reader, reader.uint32(), options); + break; + default: throw new globalThis.Error("unknown map entry field for field teleport.accesslist.v1.AccessListStatus.owner_displays"); + } + } + map[key ?? ""] = val ?? UserDisplay.create(); + } internalBinaryWrite(message: AccessListStatus, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { /* optional uint32 member_count = 1; */ if (message.memberCount !== undefined) @@ -1892,6 +2082,13 @@ class AccessListStatus$Type extends MessageType { /* repeated string scoped_member_of = 8; */ for (let i = 0; i < message.scopedMemberOf.length; i++) writer.tag(8, WireType.LengthDelimited).string(message.scopedMemberOf[i]); + /* map owner_displays = 9; */ + for (let k of globalThis.Object.keys(message.ownerDisplays)) { + writer.tag(9, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k); + writer.tag(2, WireType.LengthDelimited).fork(); + UserDisplay.internalBinaryWrite(message.ownerDisplays[k], writer, options); + writer.join().join(); + } let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); diff --git a/integrations/operator/crdgen/ignored.go b/integrations/operator/crdgen/ignored.go index 8dfaceb2751..73eb24b9344 100644 --- a/integrations/operator/crdgen/ignored.go +++ b/integrations/operator/crdgen/ignored.go @@ -39,6 +39,12 @@ var ignoredFields = map[string]stringSet{ "GithubConnectorSpecV3": { "TeamsToLogins": struct{}{}, // Deprecated field, removed since v11 }, + "Member": { + "Status": struct{}{}, + }, + "AccessListStatus": { + "OwnerDisplays": struct{}{}, + }, "ServerSpecV2": { // Useless field for agentless servers, and potentially dangerous as it // allows remote exec on agentful nodes. diff --git a/integrations/terraform/protoc-gen-terraform-accesslist.yaml b/integrations/terraform/protoc-gen-terraform-accesslist.yaml index e52d1b254f2..e277769d17e 100644 --- a/integrations/terraform/protoc-gen-terraform-accesslist.yaml +++ b/integrations/terraform/protoc-gen-terraform-accesslist.yaml @@ -49,6 +49,7 @@ exclude_fields: - "Member.header.metadata.id" # Read only field - "Member.spec.ineligible_status" + - "Member.status" # These fields will be marked as Computed: true computed_fields: