diff --git a/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go index 17e6e489aaaa7..5720d844b12e6 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go @@ -465,6 +465,8 @@ type ACL struct { RecordedSessions *ResourceAccess `protobuf:"bytes,13,opt,name=recorded_sessions,json=recordedSessions,proto3" json:"recorded_sessions,omitempty"` // active_sessions defines access to active sessions. ActiveSessions *ResourceAccess `protobuf:"bytes,14,opt,name=active_sessions,json=activeSessions,proto3" json:"active_sessions,omitempty"` + // review_requests defines the ability to review requests + ReviewRequests bool `protobuf:"varint,15,opt,name=review_requests,json=reviewRequests,proto3" json:"review_requests,omitempty"` } func (x *ACL) Reset() { @@ -588,6 +590,13 @@ func (x *ACL) GetActiveSessions() *ResourceAccess { return nil } +func (x *ACL) GetReviewRequests() bool { + if x != nil { + return x.ReviewRequests + } + return false +} + // ResourceAccess describes access verbs type ResourceAccess struct { state protoimpl.MessageState @@ -814,7 +823,7 @@ var file_teleport_lib_teleterm_v1_cluster_proto_rawDesc = []byte{ 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x53, 0x4f, 0x10, 0x02, 0x22, - 0xc8, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4c, 0x12, 0x51, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, + 0xf1, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4c, 0x12, 0x51, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, @@ -873,38 +882,41 @@ var file_teleport_lib_teleterm_v1_cluster_proto_rawDesc = []byte{ 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x0e, 0x61, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, - 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x6c, 0x69, 0x73, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x04, 0x72, 0x65, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x64, 0x69, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x65, 0x64, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x73, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x75, 0x73, 0x65, 0x22, 0x7b, 0x0a, 0x08, 0x46, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x61, 0x6e, - 0x63, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, - 0x6c, 0x6f, 0x77, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x61, 0x64, 0x76, 0x61, - 0x6e, 0x63, 0x65, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x73, 0x12, 0x33, 0x0a, 0x16, 0x69, 0x73, 0x5f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x62, 0x61, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x13, 0x69, 0x73, 0x55, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, - 0x64, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x2a, 0x73, 0x0a, 0x0d, 0x53, 0x68, 0x6f, 0x77, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x48, 0x4f, - 0x57, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x48, 0x4f, - 0x57, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x55, - 0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x48, 0x4f, - 0x57, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x53, 0x5f, 0x41, 0x43, 0x43, 0x45, - 0x53, 0x53, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x42, 0x54, 0x5a, - 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, + 0x76, 0x69, 0x65, 0x77, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, + 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, 0x65, 0x61, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x65, 0x64, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x65, 0x64, + 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x03, 0x75, 0x73, 0x65, 0x22, 0x7b, 0x0a, 0x08, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x12, 0x3a, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x17, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x33, 0x0a, 0x16, + 0x69, 0x73, 0x5f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x64, 0x5f, 0x62, + 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x69, 0x73, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x64, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, + 0x67, 0x2a, 0x73, 0x0a, 0x0d, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x48, 0x4f, 0x57, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x48, 0x4f, 0x57, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, + 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x48, 0x4f, 0x57, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x53, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x49, 0x42, 0x4c, 0x45, 0x5f, + 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x42, 0x54, 0x5a, 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, + 0x31, 0x3b, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/gen/proto/ts/teleport/lib/teleterm/v1/cluster_pb.ts b/gen/proto/ts/teleport/lib/teleterm/v1/cluster_pb.ts index 297e11f43715d..35c3ae9dcae0b 100644 --- a/gen/proto/ts/teleport/lib/teleterm/v1/cluster_pb.ts +++ b/gen/proto/ts/teleport/lib/teleterm/v1/cluster_pb.ts @@ -300,6 +300,12 @@ export interface ACL { * @generated from protobuf field: teleport.lib.teleterm.v1.ResourceAccess active_sessions = 14; */ activeSessions?: ResourceAccess; + /** + * review_requests defines the ability to review requests + * + * @generated from protobuf field: bool review_requests = 15; + */ + reviewRequests: boolean; } /** * ResourceAccess describes access verbs @@ -649,11 +655,13 @@ class ACL$Type extends MessageType { { no: 11, name: "kubeservers", kind: "message", T: () => ResourceAccess }, { no: 12, name: "access_requests", kind: "message", T: () => ResourceAccess }, { no: 13, name: "recorded_sessions", kind: "message", T: () => ResourceAccess }, - { no: 14, name: "active_sessions", kind: "message", T: () => ResourceAccess } + { no: 14, name: "active_sessions", kind: "message", T: () => ResourceAccess }, + { no: 15, name: "review_requests", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } ]); } create(value?: PartialMessage): ACL { const message = globalThis.Object.create((this.messagePrototype!)); + message.reviewRequests = false; if (value !== undefined) reflectionMergePartial(this, message, value); return message; @@ -702,6 +710,9 @@ class ACL$Type extends MessageType { case /* teleport.lib.teleterm.v1.ResourceAccess active_sessions */ 14: message.activeSessions = ResourceAccess.internalBinaryRead(reader, reader.uint32(), options, message.activeSessions); break; + case /* bool review_requests */ 15: + message.reviewRequests = reader.bool(); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -753,6 +764,9 @@ class ACL$Type extends MessageType { /* teleport.lib.teleterm.v1.ResourceAccess active_sessions = 14; */ if (message.activeSessions) ResourceAccess.internalBinaryWrite(message.activeSessions, writer.tag(14, WireType.LengthDelimited).fork(), options).join(); + /* bool review_requests = 15; */ + if (message.reviewRequests !== false) + writer.tag(15, WireType.Varint).bool(message.reviewRequests); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); diff --git a/lib/teleterm/clusters/cluster.go b/lib/teleterm/clusters/cluster.go index 3924941cdac9a..3899dc64fadff 100644 --- a/lib/teleterm/clusters/cluster.go +++ b/lib/teleterm/clusters/cluster.go @@ -213,6 +213,7 @@ func (c *Cluster) GetWithDetails(ctx context.Context, authClient authclient.Clie Dbs: convertToAPIResourceAccess(userACL.DBServers), Kubeservers: convertToAPIResourceAccess(userACL.KubeServers), AccessRequests: convertToAPIResourceAccess(userACL.AccessRequests), + ReviewRequests: userACL.ReviewRequests, } withDetails := &ClusterWithDetails{ diff --git a/proto/teleport/lib/teleterm/v1/cluster.proto b/proto/teleport/lib/teleterm/v1/cluster.proto index f0bafaf348419..8663547ab2cfd 100644 --- a/proto/teleport/lib/teleterm/v1/cluster.proto +++ b/proto/teleport/lib/teleterm/v1/cluster.proto @@ -141,6 +141,8 @@ message ACL { ResourceAccess recorded_sessions = 13; // active_sessions defines access to active sessions. ResourceAccess active_sessions = 14; + // review_requests defines the ability to review requests + bool review_requests = 15; } // ResourceAccess describes access verbs diff --git a/web/packages/shared/components/AccessRequests/ReviewRequests/RequestView/RequestView.test.tsx b/web/packages/shared/components/AccessRequests/ReviewRequests/RequestView/RequestView.test.tsx new file mode 100644 index 0000000000000..1ee774c4d75ae --- /dev/null +++ b/web/packages/shared/components/AccessRequests/ReviewRequests/RequestView/RequestView.test.tsx @@ -0,0 +1,71 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { render, screen } from 'design/utils/testing'; + +import { makeEmptyAttempt, makeSuccessAttempt } from 'shared/hooks/useAsync'; + +import { requestRolePending } from '../../fixtures'; + +import { RequestView, RequestViewProps } from './RequestView'; +import { RequestFlags } from './types'; + +const sampleFlags: RequestFlags = { + canAssume: false, + isAssumed: false, + canDelete: false, + canReview: true, + ownRequest: false, + isPromoted: false, +}; + +const props: RequestViewProps = { + user: 'loggedInUsername', + fetchRequestAttempt: makeSuccessAttempt(requestRolePending), + submitReviewAttempt: makeEmptyAttempt(), + getFlags: () => sampleFlags, + confirmDelete: false, + toggleConfirmDelete: () => null, + submitReview: () => null, + assumeRole: () => null, + fetchSuggestedAccessListsAttempt: makeSuccessAttempt([]), + assumeRoleAttempt: makeEmptyAttempt(), + assumeAccessList: () => null, + deleteRequestAttempt: makeEmptyAttempt(), + deleteRequest: () => null, +}; + +const reviewBoxText = `${props.user} - add a review`; + +test('renders review box if user can review', async () => { + render(); + expect(screen.getByText(reviewBoxText)).toBeInTheDocument(); +}); + +test('does not render review box if user cannot review', async () => { + render( + ({ + ...sampleFlags, + canReview: false, + })} + /> + ); + expect(screen.queryByText(reviewBoxText)).not.toBeInTheDocument(); +}); diff --git a/web/packages/teleterm/src/services/tshd/testHelpers.ts b/web/packages/teleterm/src/services/tshd/testHelpers.ts index f05ad0c234094..4b985282216cd 100644 --- a/web/packages/teleterm/src/services/tshd/testHelpers.ts +++ b/web/packages/teleterm/src/services/tshd/testHelpers.ts @@ -16,7 +16,10 @@ * along with this program. If not, see . */ -import { ShowResources } from 'gen-proto-ts/teleport/lib/teleterm/v1/cluster_pb'; +import { + ACL, + ShowResources, +} from 'gen-proto-ts/teleport/lib/teleterm/v1/cluster_pb'; import { TrustedDeviceRequirement } from 'gen-proto-ts/teleport/legacy/types/trusted_device_requirement_pb'; import * as tsh from './types'; @@ -113,6 +116,115 @@ export const makeLeafCluster = ( ...props, }); +export const makeAcl = (props: Partial = {}) => ({ + recordedSessions: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + activeSessions: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + authConnectors: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + roles: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + users: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + trustedClusters: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + events: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + tokens: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + servers: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + apps: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + dbs: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + kubeservers: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + accessRequests: { + list: true, + read: true, + edit: true, + create: true, + delete: true, + use: true, + }, + reviewRequests: true, + ...props, +}); + export const makeLoggedInUser = ( props: Partial = {} ): tsh.LoggedInUser => ({ @@ -120,112 +232,7 @@ export const makeLoggedInUser = ( name: 'alice', isDeviceTrusted: false, trustedDeviceRequirement: TrustedDeviceRequirement.NOT_REQUIRED, - acl: { - recordedSessions: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - activeSessions: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - authConnectors: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - roles: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - users: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - trustedClusters: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - events: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - tokens: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - servers: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - apps: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - dbs: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - kubeservers: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - accessRequests: { - list: true, - read: true, - edit: true, - create: true, - delete: true, - use: true, - }, - }, + acl: makeAcl(), sshLogins: [], roles: [], requestableRoles: [], diff --git a/web/packages/teleterm/src/ui/ConnectMyComputer/DocumentConnectMyComputer/Setup.test.tsx b/web/packages/teleterm/src/ui/ConnectMyComputer/DocumentConnectMyComputer/Setup.test.tsx index 849499de392c2..f3c90df14a358 100644 --- a/web/packages/teleterm/src/ui/ConnectMyComputer/DocumentConnectMyComputer/Setup.test.tsx +++ b/web/packages/teleterm/src/ui/ConnectMyComputer/DocumentConnectMyComputer/Setup.test.tsx @@ -22,6 +22,7 @@ import { render, screen, waitFor } from 'design/utils/testing'; import { act } from '@testing-library/react'; import { + makeAcl, makeLoggedInUser, makeRootCluster, makeServer, @@ -116,7 +117,7 @@ function setupAppContext(): { } { const cluster = makeRootCluster({ loggedInUser: makeLoggedInUser({ - acl: { + acl: makeAcl({ tokens: { create: true, list: true, @@ -125,7 +126,7 @@ function setupAppContext(): { delete: true, use: true, }, - }, + }), }), }); const appContext = new MockAppContext({ diff --git a/web/packages/teleterm/src/ui/ConnectMyComputer/access.test.ts b/web/packages/teleterm/src/ui/ConnectMyComputer/access.test.ts index cbe29910e407d..c4a75a5c6c4ab 100644 --- a/web/packages/teleterm/src/ui/ConnectMyComputer/access.test.ts +++ b/web/packages/teleterm/src/ui/ConnectMyComputer/access.test.ts @@ -18,7 +18,7 @@ import { makeRuntimeSettings } from 'teleterm/mainProcess/fixtures/mocks'; import { Platform } from 'teleterm/mainProcess/types'; -import { makeLoggedInUser } from 'teleterm/services/tshd/testHelpers'; +import { makeAcl, makeLoggedInUser } from 'teleterm/services/tshd/testHelpers'; import { ConnectMyComputerAccess, @@ -63,7 +63,7 @@ const testCases: { test.each(testCases)('$name', testCase => { const loggedInUser = makeLoggedInUser({ - acl: { + acl: makeAcl({ tokens: { create: testCase.canCreateToken, edit: false, @@ -72,7 +72,7 @@ test.each(testCases)('$name', testCase => { read: false, delete: false, }, - }, + }), }); const runtimeSettings = makeRuntimeSettings({ platform: testCase.platform }); diff --git a/web/packages/teleterm/src/ui/ConnectMyComputer/connectMyComputerContext.test.tsx b/web/packages/teleterm/src/ui/ConnectMyComputer/connectMyComputerContext.test.tsx index 47f5e9efb4c69..55913e30c231a 100644 --- a/web/packages/teleterm/src/ui/ConnectMyComputer/connectMyComputerContext.test.tsx +++ b/web/packages/teleterm/src/ui/ConnectMyComputer/connectMyComputerContext.test.tsx @@ -26,6 +26,7 @@ import { MockAppContext } from 'teleterm/ui/fixtures/mocks'; import { AgentProcessState } from 'teleterm/mainProcess/types'; import * as resourcesContext from 'teleterm/ui/DocumentCluster/resourcesContext'; import { + makeAcl, makeLoggedInUser, makeRootCluster, makeServer, @@ -49,7 +50,7 @@ beforeAll(() => { function getMocks() { const rootCluster = makeRootCluster({ loggedInUser: makeLoggedInUser({ - acl: { + acl: makeAcl({ tokens: { create: true, edit: false, @@ -58,7 +59,7 @@ function getMocks() { read: false, delete: false, }, - }, + }), }), }); const appContext = new MockAppContext({ diff --git a/web/packages/teleterm/src/ui/DocumentAccessRequests/ReviewAccessRequest/useReviewAccessRequest.ts b/web/packages/teleterm/src/ui/DocumentAccessRequests/ReviewAccessRequest/useReviewAccessRequest.ts index e85b0b278789a..ed0f182ca9c33 100644 --- a/web/packages/teleterm/src/ui/DocumentAccessRequests/ReviewAccessRequest/useReviewAccessRequest.ts +++ b/web/packages/teleterm/src/ui/DocumentAccessRequests/ReviewAccessRequest/useReviewAccessRequest.ts @@ -181,11 +181,13 @@ function getRequestFlags( ? reviewed.state === 'PENDING' : request.state === 'PENDING'; + const canReview = !ownRequest && isPendingState && user.acl.reviewRequests; + return { canAssume, isAssumed, canDelete, - canReview: !ownRequest && isPendingState, + canReview, isPromoted, ownRequest, }; diff --git a/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.story.tsx b/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.story.tsx index bfdab4a8309eb..f2472378077d8 100644 --- a/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.story.tsx +++ b/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.story.tsx @@ -35,6 +35,7 @@ import { makeApp, rootClusterUri, leafClusterUri, + makeAcl, } from 'teleterm/services/tshd/testHelpers'; import { ResourcesService } from 'teleterm/ui/services/resources'; @@ -168,7 +169,7 @@ export const OnlineEmptyResourcesAndCanAddResourcesAndConnectComputer = () => { uri: rootClusterDoc.clusterUri, loggedInUser: makeLoggedInUser({ userType: tsh.LoggedInUser_UserType.LOCAL, - acl: { + acl: makeAcl({ tokens: { create: true, list: true, @@ -177,7 +178,7 @@ export const OnlineEmptyResourcesAndCanAddResourcesAndConnectComputer = () => { read: true, use: true, }, - }, + }), }), }) ); @@ -204,7 +205,7 @@ export const OnlineEmptyResourcesAndCanAddResourcesButCannotConnectComputer = uri: rootClusterDoc.clusterUri, loggedInUser: makeLoggedInUser({ userType: tsh.LoggedInUser_UserType.SSO, - acl: { + acl: makeAcl({ tokens: { create: true, list: true, @@ -213,7 +214,7 @@ export const OnlineEmptyResourcesAndCanAddResourcesButCannotConnectComputer = read: true, use: true, }, - }, + }), }), }) ); @@ -238,7 +239,7 @@ export const OnlineEmptyResourcesAndCannotAddResources = () => { makeRootCluster({ uri: rootClusterDoc.clusterUri, loggedInUser: makeLoggedInUser({ - acl: { + acl: makeAcl({ tokens: { create: false, list: true, @@ -247,7 +248,7 @@ export const OnlineEmptyResourcesAndCannotAddResources = () => { read: true, use: true, }, - }, + }), }), }) ); diff --git a/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.test.tsx b/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.test.tsx index 095730980aa9a..1c4903d5b59c8 100644 --- a/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.test.tsx +++ b/web/packages/teleterm/src/ui/DocumentCluster/DocumentCluster.test.tsx @@ -27,6 +27,7 @@ import { MockWorkspaceContextProvider } from 'teleterm/ui/fixtures/MockWorkspace import { makeRootCluster, makeLoggedInUser, + makeAcl, } from 'teleterm/services/tshd/testHelpers'; import * as tsh from 'teleterm/services/tshd/types'; import { ConnectMyComputerContextProvider } from 'teleterm/ui/ConnectMyComputer'; @@ -50,7 +51,7 @@ it('displays a button for Connect My Computer in the empty state if the user can uri: doc.clusterUri, loggedInUser: makeLoggedInUser({ userType: tsh.LoggedInUser_UserType.LOCAL, - acl: { + acl: makeAcl({ tokens: { create: true, list: true, @@ -59,7 +60,7 @@ it('displays a button for Connect My Computer in the empty state if the user can read: true, use: true, }, - }, + }), }), }) ); @@ -123,7 +124,7 @@ it('does not display a button for Connect My Computer in the empty state if the uri: doc.clusterUri, loggedInUser: makeLoggedInUser({ userType: tsh.LoggedInUser_UserType.LOCAL, - acl: { + acl: makeAcl({ tokens: { create: false, list: true, @@ -132,7 +133,7 @@ it('does not display a button for Connect My Computer in the empty state if the read: true, use: true, }, - }, + }), }), }) );