From d3494acd45dcf52858b59165dfa4565456a93de7 Mon Sep 17 00:00:00 2001 From: Bugs5382 <12115015+Bugs5382@users.noreply.github.com> Date: Thu, 15 Oct 2026 12:05:54 -0400 Subject: [PATCH] feat(fleet): proxy a node's OS image lifecycle (stage, activate, rollback) cryptosctl image status/stage/rollback/activate has no web equivalent: the node already exposes StageImage, ActivateImage, RollbackImage and GetImageStatus, but the manager never called them. FleetService gains GetNodeImageStatus (viewer-readable, not audited), StageNodeImage, ActivateNodeImage and RollbackNodeImage. Staging fetches image_url itself rather than taking an upload: the manager streams the image straight into the node's chunked StageImage RPC, so a GiB-sized image never has to cross a browser's Connect client (client-streaming isn't portable there) or sit fully buffered in a JSON request body. Activating still requires confirm_ca_cn, the same confirmation RebootNode uses, because it is itself a reboot. All three writes are admin-gated and audited; the node's own refusals (a bad signature, or FailedPrecondition when another upgrade is already running) are surfaced through the existing node-refusal mapping unchanged. Not exposed as an MCP tool yet; the catalog marks all four excluded. Refs CryptOS-PKI/cryptos-manager#187 Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com> --- cmd/manager/main.go | 3 +- gen/go/cryptos/fleet/v1/fleet.pb.go | 1897 ++++++++++++----- gen/go/cryptos/fleet/v1/fleet_grpc.pb.go | 192 ++ .../fleet/v1/fleetv1connect/fleet.connect.go | 156 ++ internal/fleet/enrollment_test.go | 17 + internal/fleet/nodeimage.go | 289 +++ internal/fleet/nodeimage_test.go | 315 +++ internal/fleet/nodes_test.go | 91 + internal/fleet/service.go | 10 + internal/mcpserver/catalog.go | 4 + internal/nodeclient/nodeclient.go | 67 + internal/nodeclient/nodeclient_test.go | 134 ++ proto/cryptos/fleet/v1/fleet.proto | 119 ++ 13 files changed, 2743 insertions(+), 551 deletions(-) create mode 100644 internal/fleet/nodeimage.go create mode 100644 internal/fleet/nodeimage_test.go diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 3f26a71..837d8a5 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -204,7 +204,8 @@ func main() { svc := fleet.New(st, dial). WithServerCertCapture(nodeclient.FetchServerCert). - WithUnverifiedNodes(insecure.skip) + WithUnverifiedNodes(insecure.skip). + WithImageFetch(fleet.NewHTTPImageFetch(fleet.ImageFetchTimeout, fleet.MaxNodeImageBytes)) pemDial := func(endpoint, certPEM, keyPEM, caPEM string) (fleet.NodeConn, error) { return nodeclient.DialPEM(endpoint, certPEM, keyPEM, caPEM) diff --git a/gen/go/cryptos/fleet/v1/fleet.pb.go b/gen/go/cryptos/fleet/v1/fleet.pb.go index ee70e7a..77ed9ab 100644 --- a/gen/go/cryptos/fleet/v1/fleet.pb.go +++ b/gen/go/cryptos/fleet/v1/fleet.pb.go @@ -8962,6 +8962,582 @@ func (x *VerifyNodeAuditChainResponse) GetReason() string { return "" } +// GetNodeImageStatusRequest names the node whose CryptOS image status to +// read. +type GetNodeImageStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // node_name is the managed node to read. + // Deprecated: use node_id. Still resolves the node's current name for one + // release. + NodeName string `protobuf:"bytes,1,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + // node_id is the stable ID (NodeSummary.id) of the node. Preferred over + // node_name; when both are set they must name the same node, or the + // manager returns InvalidArgument. + NodeId string `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` +} + +func (x *GetNodeImageStatusRequest) Reset() { + *x = GetNodeImageStatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[135] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetNodeImageStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetNodeImageStatusRequest) ProtoMessage() {} + +func (x *GetNodeImageStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[135] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetNodeImageStatusRequest.ProtoReflect.Descriptor instead. +func (*GetNodeImageStatusRequest) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{135} +} + +func (x *GetNodeImageStatusRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *GetNodeImageStatusRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +// NodeImageStatus describes the images on a managed node's ESP and the one +// currently running. +type NodeImageStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // running_sha256 is the digest of the image the node booted, hex encoded. + RunningSha256 string `protobuf:"bytes,1,opt,name=running_sha256,json=runningSha256,proto3" json:"running_sha256,omitempty"` + // active_sha256 is the digest of the image the firmware will boot next. It + // differs from running_sha256 exactly when a staged image is waiting for a + // reboot. + ActiveSha256 string `protobuf:"bytes,2,opt,name=active_sha256,json=activeSha256,proto3" json:"active_sha256,omitempty"` + // previous_sha256 is the retained image RollbackNodeImage would restore, + // hex encoded, empty on a node that has never been upgraded. + PreviousSha256 string `protobuf:"bytes,3,opt,name=previous_sha256,json=previousSha256,proto3" json:"previous_sha256,omitempty"` + // reboot_pending is true when active_sha256 differs from running_sha256. + RebootPending bool `protobuf:"varint,4,opt,name=reboot_pending,json=rebootPending,proto3" json:"reboot_pending,omitempty"` + // running_version is the CryptOS version string baked into the running + // image. + RunningVersion string `protobuf:"bytes,5,opt,name=running_version,json=runningVersion,proto3" json:"running_version,omitempty"` +} + +func (x *NodeImageStatus) Reset() { + *x = NodeImageStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[136] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeImageStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeImageStatus) ProtoMessage() {} + +func (x *NodeImageStatus) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[136] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeImageStatus.ProtoReflect.Descriptor instead. +func (*NodeImageStatus) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{136} +} + +func (x *NodeImageStatus) GetRunningSha256() string { + if x != nil { + return x.RunningSha256 + } + return "" +} + +func (x *NodeImageStatus) GetActiveSha256() string { + if x != nil { + return x.ActiveSha256 + } + return "" +} + +func (x *NodeImageStatus) GetPreviousSha256() string { + if x != nil { + return x.PreviousSha256 + } + return "" +} + +func (x *NodeImageStatus) GetRebootPending() bool { + if x != nil { + return x.RebootPending + } + return false +} + +func (x *NodeImageStatus) GetRunningVersion() string { + if x != nil { + return x.RunningVersion + } + return "" +} + +type GetNodeImageStatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status *NodeImageStatus `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *GetNodeImageStatusResponse) Reset() { + *x = GetNodeImageStatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[137] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetNodeImageStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetNodeImageStatusResponse) ProtoMessage() {} + +func (x *GetNodeImageStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[137] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetNodeImageStatusResponse.ProtoReflect.Descriptor instead. +func (*GetNodeImageStatusResponse) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{137} +} + +func (x *GetNodeImageStatusResponse) GetStatus() *NodeImageStatus { + if x != nil { + return x.Status + } + return nil +} + +// StageNodeImageRequest carries where to fetch the image from and the +// detached release signature over it; the manager fetches image_url itself. +type StageNodeImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // node_name is the managed node to stage onto. + // Deprecated: use node_id. Still resolves the node's current name for one + // release. + NodeName string `protobuf:"bytes,1,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + // node_id is the stable ID (NodeSummary.id) of the node. Preferred over + // node_name; when both are set they must name the same node, or the + // manager returns InvalidArgument. + NodeId string `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // image_url is an http or https URL the manager fetches the image from. + // Required. + ImageUrl string `protobuf:"bytes,3,opt,name=image_url,json=imageUrl,proto3" json:"image_url,omitempty"` + // signature is the detached release signature over the whole image: PKCS#1 + // v1.5 over a SHA-256 digest, made by the CryptOS release key. Required; + // the node refuses a transfer it cannot verify. + Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` + // sha256 is the expected digest of the image, hex encoded. Optional; when + // set the node checks it against what it received. + Sha256 string `protobuf:"bytes,5,opt,name=sha256,proto3" json:"sha256,omitempty"` +} + +func (x *StageNodeImageRequest) Reset() { + *x = StageNodeImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[138] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StageNodeImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StageNodeImageRequest) ProtoMessage() {} + +func (x *StageNodeImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[138] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StageNodeImageRequest.ProtoReflect.Descriptor instead. +func (*StageNodeImageRequest) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{138} +} + +func (x *StageNodeImageRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *StageNodeImageRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *StageNodeImageRequest) GetImageUrl() string { + if x != nil { + return x.ImageUrl + } + return "" +} + +func (x *StageNodeImageRequest) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *StageNodeImageRequest) GetSha256() string { + if x != nil { + return x.Sha256 + } + return "" +} + +type StageNodeImageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status *NodeImageStatus `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + // requires_reboot is always true on success: the staged image is what the + // firmware will boot, but the node is still running the old one. + RequiresReboot bool `protobuf:"varint,2,opt,name=requires_reboot,json=requiresReboot,proto3" json:"requires_reboot,omitempty"` +} + +func (x *StageNodeImageResponse) Reset() { + *x = StageNodeImageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[139] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StageNodeImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StageNodeImageResponse) ProtoMessage() {} + +func (x *StageNodeImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[139] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StageNodeImageResponse.ProtoReflect.Descriptor instead. +func (*StageNodeImageResponse) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{139} +} + +func (x *StageNodeImageResponse) GetStatus() *NodeImageStatus { + if x != nil { + return x.Status + } + return nil +} + +func (x *StageNodeImageResponse) GetRequiresReboot() bool { + if x != nil { + return x.RequiresReboot + } + return false +} + +// ActivateNodeImageRequest confirms an operator-initiated reboot onto a +// staged image. +type ActivateNodeImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NodeName string `protobuf:"bytes,1,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + NodeId string `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // confirm_ca_cn must equal the node's current CA common name. + ConfirmCaCn string `protobuf:"bytes,3,opt,name=confirm_ca_cn,json=confirmCaCn,proto3" json:"confirm_ca_cn,omitempty"` +} + +func (x *ActivateNodeImageRequest) Reset() { + *x = ActivateNodeImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[140] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ActivateNodeImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActivateNodeImageRequest) ProtoMessage() {} + +func (x *ActivateNodeImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[140] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ActivateNodeImageRequest.ProtoReflect.Descriptor instead. +func (*ActivateNodeImageRequest) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{140} +} + +func (x *ActivateNodeImageRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *ActivateNodeImageRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *ActivateNodeImageRequest) GetConfirmCaCn() string { + if x != nil { + return x.ConfirmCaCn + } + return "" +} + +type ActivateNodeImageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The node reboots shortly after replying; the reply exists so the caller + // learns the reboot was accepted before the connection drops. + Rebooting bool `protobuf:"varint,1,opt,name=rebooting,proto3" json:"rebooting,omitempty"` +} + +func (x *ActivateNodeImageResponse) Reset() { + *x = ActivateNodeImageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[141] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ActivateNodeImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActivateNodeImageResponse) ProtoMessage() {} + +func (x *ActivateNodeImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[141] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ActivateNodeImageResponse.ProtoReflect.Descriptor instead. +func (*ActivateNodeImageResponse) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{141} +} + +func (x *ActivateNodeImageResponse) GetRebooting() bool { + if x != nil { + return x.Rebooting + } + return false +} + +type RollbackNodeImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NodeName string `protobuf:"bytes,1,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + NodeId string `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` +} + +func (x *RollbackNodeImageRequest) Reset() { + *x = RollbackNodeImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[142] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RollbackNodeImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RollbackNodeImageRequest) ProtoMessage() {} + +func (x *RollbackNodeImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[142] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RollbackNodeImageRequest.ProtoReflect.Descriptor instead. +func (*RollbackNodeImageRequest) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{142} +} + +func (x *RollbackNodeImageRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *RollbackNodeImageRequest) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +type RollbackNodeImageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status *NodeImageStatus `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + RequiresReboot bool `protobuf:"varint,2,opt,name=requires_reboot,json=requiresReboot,proto3" json:"requires_reboot,omitempty"` +} + +func (x *RollbackNodeImageResponse) Reset() { + *x = RollbackNodeImageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[143] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RollbackNodeImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RollbackNodeImageResponse) ProtoMessage() {} + +func (x *RollbackNodeImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_cryptos_fleet_v1_fleet_proto_msgTypes[143] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RollbackNodeImageResponse.ProtoReflect.Descriptor instead. +func (*RollbackNodeImageResponse) Descriptor() ([]byte, []int) { + return file_cryptos_fleet_v1_fleet_proto_rawDescGZIP(), []int{143} +} + +func (x *RollbackNodeImageResponse) GetStatus() *NodeImageStatus { + if x != nil { + return x.Status + } + return nil +} + +func (x *RollbackNodeImageResponse) GetRequiresReboot() bool { + if x != nil { + return x.RequiresReboot + } + return false +} + var File_cryptos_fleet_v1_fleet_proto protoreflect.FileDescriptor var file_cryptos_fleet_v1_fleet_proto_rawDesc = []byte{ @@ -10013,427 +10589,520 @@ var file_cryptos_fleet_v1_fleet_proto_rawDesc = []byte{ 0x6b, 0x65, 0x6e, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x66, 0x69, 0x72, 0x73, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, - 0x52, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x45, 0x41, - 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x50, 0x10, 0x01, - 0x12, 0x0f, 0x0a, 0x0b, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, - 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x10, 0x03, 0x32, 0x8b, 0x33, 0x0a, 0x0c, 0x46, 0x6c, 0x65, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x73, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x07, 0x47, 0x65, - 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x4c, 0x69, - 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x29, - 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x12, 0x41, 0x70, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, + 0x51, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, + 0x49, 0x64, 0x22, 0xd6, 0x01, 0x0a, 0x0f, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, + 0x67, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x23, 0x0a, + 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x68, 0x61, 0x32, + 0x35, 0x36, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x73, + 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x72, 0x65, + 0x76, 0x69, 0x6f, 0x75, 0x73, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x25, 0x0a, 0x0e, 0x72, + 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0d, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x75, 0x6e, + 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x57, 0x0a, 0x1a, 0x47, + 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, + 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x15, 0x53, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x6f, + 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6e, + 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, + 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, + 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, + 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x22, 0x7c, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x67, 0x65, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x27, 0x0a, 0x0f, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, + 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x22, 0x74, 0x0a, 0x18, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, + 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x72, 0x6d, 0x5f, 0x63, 0x61, 0x5f, 0x63, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x43, 0x61, 0x43, 0x6e, 0x22, 0x39, 0x0a, 0x19, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x62, 0x6f, + 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x62, + 0x6f, 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x50, 0x0a, 0x18, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x7f, 0x0a, 0x19, 0x52, 0x6f, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x62, + 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x73, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x2a, 0x52, 0x0a, 0x06, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, + 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x48, 0x45, + 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x48, + 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x32, 0xbd, 0x36, + 0x0a, 0x0c, 0x46, 0x6c, 0x65, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x54, + 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 0x20, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x5d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, + 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, + 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, + 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x60, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x54, 0x6f, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2b, 0x2e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x6f, 0x4e, 0x6f, 0x64, 0x65, - 0x12, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x54, 0x6f, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x6f, 0x4e, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x15, 0x53, - 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x61, - 0x70, 0x74, 0x65, 0x72, 0x73, 0x12, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x61, - 0x70, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, + 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x6f, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2e, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, - 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, - 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x64, 0x61, 0x70, - 0x74, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x5d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, + 0x61, 0x70, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, + 0x0a, 0x11, 0x53, 0x65, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x45, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, + 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, + 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, + 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x66, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, - 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, - 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, + 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, + 0x74, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, + 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x4c, 0x69, + 0x73, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x45, 0x6e, - 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, - 0x6f, 0x76, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x45, - 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x69, 0x0a, 0x10, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, - 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x45, - 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, - 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x06, - 0x57, 0x68, 0x6f, 0x41, 0x6d, 0x49, 0x12, 0x1f, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x68, 0x6f, 0x41, 0x6d, 0x49, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x68, 0x6f, 0x41, 0x6d, - 0x49, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x52, 0x65, 0x76, - 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2a, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, + 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x72, 0x6f, + 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, + 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, + 0x11, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x45, 0x6e, 0x72, + 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, + 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x52, + 0x65, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x13, - 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, - 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, - 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x75, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, - 0x64, 0x69, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x2d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, - 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x56, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, - 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x73, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x54, 0x73, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x73, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x49, - 0x73, 0x73, 0x75, 0x65, 0x4c, 0x65, 0x61, 0x66, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x73, 0x75, - 0x65, 0x4c, 0x65, 0x61, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, + 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x06, 0x57, 0x68, 0x6f, 0x41, 0x6d, 0x49, + 0x12, 0x1f, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x68, 0x6f, 0x41, 0x6d, 0x49, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x68, 0x6f, 0x41, 0x6d, 0x49, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, + 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x63, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x12, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x73, 0x73, 0x75, 0x65, 0x4c, 0x65, 0x61, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x54, 0x0a, 0x09, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, + 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x2e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x14, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x12, 0x2d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4e, 0x6f, 0x64, 0x65, + 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, + 0x65, 0x54, 0x73, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x73, 0x61, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x73, + 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, - 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x67, + 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x52, 0x6f, 0x6c, + 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2a, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x4c, 0x65, 0x61, 0x66, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4c, 0x65, 0x61, + 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x4c, 0x65, 0x61, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, + 0x09, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x6b, 0x65, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x70, 0x70, 0x6c, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x4e, - 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5a, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, - 0x12, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x43, 0x41, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, - 0x0b, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x63, + 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x4e, 0x6f, + 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, + 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x96, 0x01, 0x0a, 0x1f, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x93, 0x01, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0b, 0x49, 0x6d, 0x70, + 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, + 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x96, 0x01, 0x0a, 0x1f, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x2e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x96, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x93, + 0x01, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x12, 0x37, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x96, 0x01, 0x0a, 0x1f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, + 0x0a, 0x18, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, - 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x73, 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x4c, 0x69, 0x73, - 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x73, 0x12, 0x28, 0x2e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6f, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x12, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x52, 0x65, 0x74, 0x69, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x12, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x69, 0x72, 0x65, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x69, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, - 0x16, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x43, 0x52, - 0x4c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x43, 0x52, 0x4c, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x43, 0x52, 0x4c, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x55, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x52, 0x4c, 0x12, - 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x73, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x43, 0x41, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, + 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x43, 0x41, 0x12, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2c, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, + 0x0a, 0x10, 0x52, 0x65, 0x74, 0x69, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x43, 0x41, 0x12, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x69, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x74, 0x69, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, + 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x16, 0x53, 0x65, 0x74, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x43, 0x52, 0x4c, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x43, 0x41, 0x43, 0x52, 0x4c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x43, 0x41, 0x43, 0x52, 0x4c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x52, 0x4c, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x52, 0x4c, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x4f, 0x43, 0x53, 0x50, 0x12, 0x2a, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x4f, 0x43, - 0x53, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x43, 0x41, 0x4f, 0x43, 0x53, 0x50, 0x12, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, - 0x77, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, - 0x76, 0x69, 0x65, 0x77, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, - 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x64, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, - 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, - 0x6b, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x09, 0x41, 0x64, 0x6f, - 0x70, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x4e, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, - 0x6f, 0x70, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, - 0x01, 0x12, 0x87, 0x01, 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x41, 0x64, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, - 0x12, 0x33, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x41, 0x64, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, - 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x44, - 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x43, 0x41, 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x64, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, + 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4e, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, - 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x62, - 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x57, 0x0a, 0x0a, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x73, - 0x12, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x63, - 0x70, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, - 0x0c, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4d, 0x63, - 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0c, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x63, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x4c, 0x69, + 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x12, 0x29, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x09, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x87, 0x01, + 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x33, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, - 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x63, 0x70, - 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x4c, - 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x26, 0x2e, 0x63, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x41, 0x64, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x41, 0x64, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x44, 0x65, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x29, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x12, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x52, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, + 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x72, - 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, - 0x0e, 0x44, 0x65, 0x63, 0x69, 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, - 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x69, - 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x52, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x63, 0x70, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x26, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0e, 0x44, 0x65, 0x63, + 0x69, 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, 0x27, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x63, 0x69, 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x64, 0x65, 0x41, 0x70, + 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, + 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, + 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x30, 0x2e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x73, 0x12, 0x30, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, - 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x84, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x42, 0x79, 0x49, 0x44, 0x12, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x84, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x79, 0x49, 0x44, + 0x12, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x79, 0x49, - 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, - 0x0a, 0x18, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, + 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x43, 0x72, 0x79, 0x70, 0x74, 0x4f, 0x53, 0x2d, 0x50, 0x4b, 0x49, 0x2f, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x67, 0x6f, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2f, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x2f, 0x76, 0x31, 0x3b, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x73, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x48, 0x5a, + 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, + 0x74, 0x4f, 0x53, 0x2d, 0x50, 0x4b, 0x49, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2d, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x6f, 0x73, 0x2f, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x3b, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -10449,7 +11118,7 @@ func file_cryptos_fleet_v1_fleet_proto_rawDescGZIP() []byte { } var file_cryptos_fleet_v1_fleet_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_cryptos_fleet_v1_fleet_proto_msgTypes = make([]protoimpl.MessageInfo, 136) +var file_cryptos_fleet_v1_fleet_proto_msgTypes = make([]protoimpl.MessageInfo, 145) var file_cryptos_fleet_v1_fleet_proto_goTypes = []any{ (Health)(0), // 0: cryptos.fleet.v1.Health (*ListNodesRequest)(nil), // 1: cryptos.fleet.v1.ListNodesRequest @@ -10587,58 +11256,67 @@ var file_cryptos_fleet_v1_fleet_proto_goTypes = []any{ (*ListNodeAuditEventsResponse)(nil), // 133: cryptos.fleet.v1.ListNodeAuditEventsResponse (*VerifyNodeAuditChainRequest)(nil), // 134: cryptos.fleet.v1.VerifyNodeAuditChainRequest (*VerifyNodeAuditChainResponse)(nil), // 135: cryptos.fleet.v1.VerifyNodeAuditChainResponse - nil, // 136: cryptos.fleet.v1.NodeAuditEvent.DetailsEntry - (*v1.CertificateProfile)(nil), // 137: cryptos.node.v1.CertificateProfile - (*v1.ProtocolStatus)(nil), // 138: cryptos.node.v1.ProtocolStatus - (*v1.MachineConfig)(nil), // 139: cryptos.node.v1.MachineConfig - (v1.ServiceProtocol)(0), // 140: cryptos.node.v1.ServiceProtocol - (*OperatorCA)(nil), // 141: cryptos.fleet.v1.OperatorCA - (OcspMode)(0), // 142: cryptos.fleet.v1.OcspMode - (OperatorCAAcknowledgement)(0), // 143: cryptos.fleet.v1.OperatorCAAcknowledgement - (*OcspProbeResult)(nil), // 144: cryptos.fleet.v1.OcspProbeResult - (*v1.InstallDisk)(nil), // 145: cryptos.node.v1.InstallDisk + (*GetNodeImageStatusRequest)(nil), // 136: cryptos.fleet.v1.GetNodeImageStatusRequest + (*NodeImageStatus)(nil), // 137: cryptos.fleet.v1.NodeImageStatus + (*GetNodeImageStatusResponse)(nil), // 138: cryptos.fleet.v1.GetNodeImageStatusResponse + (*StageNodeImageRequest)(nil), // 139: cryptos.fleet.v1.StageNodeImageRequest + (*StageNodeImageResponse)(nil), // 140: cryptos.fleet.v1.StageNodeImageResponse + (*ActivateNodeImageRequest)(nil), // 141: cryptos.fleet.v1.ActivateNodeImageRequest + (*ActivateNodeImageResponse)(nil), // 142: cryptos.fleet.v1.ActivateNodeImageResponse + (*RollbackNodeImageRequest)(nil), // 143: cryptos.fleet.v1.RollbackNodeImageRequest + (*RollbackNodeImageResponse)(nil), // 144: cryptos.fleet.v1.RollbackNodeImageResponse + nil, // 145: cryptos.fleet.v1.NodeAuditEvent.DetailsEntry + (*v1.CertificateProfile)(nil), // 146: cryptos.node.v1.CertificateProfile + (*v1.ProtocolStatus)(nil), // 147: cryptos.node.v1.ProtocolStatus + (*v1.MachineConfig)(nil), // 148: cryptos.node.v1.MachineConfig + (v1.ServiceProtocol)(0), // 149: cryptos.node.v1.ServiceProtocol + (*OperatorCA)(nil), // 150: cryptos.fleet.v1.OperatorCA + (OcspMode)(0), // 151: cryptos.fleet.v1.OcspMode + (OperatorCAAcknowledgement)(0), // 152: cryptos.fleet.v1.OperatorCAAcknowledgement + (*OcspProbeResult)(nil), // 153: cryptos.fleet.v1.OcspProbeResult + (*v1.InstallDisk)(nil), // 154: cryptos.node.v1.InstallDisk } var file_cryptos_fleet_v1_fleet_proto_depIdxs = []int32{ 29, // 0: cryptos.fleet.v1.ListNodesResponse.nodes:type_name -> cryptos.fleet.v1.NodeSummary 31, // 1: cryptos.fleet.v1.GetNodeResponse.node:type_name -> cryptos.fleet.v1.NodeDetail 32, // 2: cryptos.fleet.v1.ListCertificatesResponse.certificates:type_name -> cryptos.fleet.v1.Certificate - 137, // 3: cryptos.fleet.v1.ListProfilesResponse.items:type_name -> cryptos.node.v1.CertificateProfile - 137, // 4: cryptos.fleet.v1.CreateProfileRequest.profile:type_name -> cryptos.node.v1.CertificateProfile - 137, // 5: cryptos.fleet.v1.UpdateProfileRequest.profile:type_name -> cryptos.node.v1.CertificateProfile - 137, // 6: cryptos.fleet.v1.ListRequestableProfilesResponse.items:type_name -> cryptos.node.v1.CertificateProfile + 146, // 3: cryptos.fleet.v1.ListProfilesResponse.items:type_name -> cryptos.node.v1.CertificateProfile + 146, // 4: cryptos.fleet.v1.CreateProfileRequest.profile:type_name -> cryptos.node.v1.CertificateProfile + 146, // 5: cryptos.fleet.v1.UpdateProfileRequest.profile:type_name -> cryptos.node.v1.CertificateProfile + 146, // 6: cryptos.fleet.v1.ListRequestableProfilesResponse.items:type_name -> cryptos.node.v1.CertificateProfile 33, // 7: cryptos.fleet.v1.ListAdaptersResponse.items:type_name -> cryptos.fleet.v1.EnrollmentAdapter 33, // 8: cryptos.fleet.v1.SetAdapterEnabledResponse.adapter:type_name -> cryptos.fleet.v1.EnrollmentAdapter 34, // 9: cryptos.fleet.v1.ListAuditResponse.items:type_name -> cryptos.fleet.v1.AuditEvent 35, // 10: cryptos.fleet.v1.ListEnrollmentsResponse.items:type_name -> cryptos.fleet.v1.EnrollmentRequest 0, // 11: cryptos.fleet.v1.NodeSummary.health:type_name -> cryptos.fleet.v1.Health - 138, // 12: cryptos.fleet.v1.NodeSummary.protocols:type_name -> cryptos.node.v1.ProtocolStatus + 147, // 12: cryptos.fleet.v1.NodeSummary.protocols:type_name -> cryptos.node.v1.ProtocolStatus 29, // 13: cryptos.fleet.v1.NodeDetail.summary:type_name -> cryptos.fleet.v1.NodeSummary 30, // 14: cryptos.fleet.v1.NodeDetail.identity:type_name -> cryptos.fleet.v1.NodeIdentity 35, // 15: cryptos.fleet.v1.CreateEnrollmentResponse.enrollment:type_name -> cryptos.fleet.v1.EnrollmentRequest 35, // 16: cryptos.fleet.v1.ApproveEnrollmentResponse.enrollment:type_name -> cryptos.fleet.v1.EnrollmentRequest 35, // 17: cryptos.fleet.v1.RejectEnrollmentResponse.enrollment:type_name -> cryptos.fleet.v1.EnrollmentRequest 43, // 18: cryptos.fleet.v1.WhoAmIResponse.operator:type_name -> cryptos.fleet.v1.OperatorIdentity - 139, // 19: cryptos.fleet.v1.GetNodeConfigResponse.config:type_name -> cryptos.node.v1.MachineConfig - 139, // 20: cryptos.fleet.v1.ApplyNodeConfigRequest.config:type_name -> cryptos.node.v1.MachineConfig - 140, // 21: cryptos.fleet.v1.SetNodeProtocolRequest.protocol:type_name -> cryptos.node.v1.ServiceProtocol + 148, // 19: cryptos.fleet.v1.GetNodeConfigResponse.config:type_name -> cryptos.node.v1.MachineConfig + 148, // 20: cryptos.fleet.v1.ApplyNodeConfigRequest.config:type_name -> cryptos.node.v1.MachineConfig + 149, // 21: cryptos.fleet.v1.SetNodeProtocolRequest.protocol:type_name -> cryptos.node.v1.ServiceProtocol 66, // 22: cryptos.fleet.v1.ListOperatorCredentialsResponse.items:type_name -> cryptos.fleet.v1.OperatorCredential 74, // 23: cryptos.fleet.v1.ListOperatorCredentialRequestsResponse.items:type_name -> cryptos.fleet.v1.OperatorCredentialRequest 74, // 24: cryptos.fleet.v1.CancelOperatorCredentialRequestResponse.request:type_name -> cryptos.fleet.v1.OperatorCredentialRequest 66, // 25: cryptos.fleet.v1.RecordOperatorCredentialResponse.credential:type_name -> cryptos.fleet.v1.OperatorCredential - 141, // 26: cryptos.fleet.v1.ListOperatorCAsResponse.items:type_name -> cryptos.fleet.v1.OperatorCA - 142, // 27: cryptos.fleet.v1.RegisterOperatorCARequest.ocsp_mode:type_name -> cryptos.fleet.v1.OcspMode - 143, // 28: cryptos.fleet.v1.RegisterOperatorCARequest.acknowledgements:type_name -> cryptos.fleet.v1.OperatorCAAcknowledgement - 141, // 29: cryptos.fleet.v1.RegisterOperatorCAResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA - 144, // 30: cryptos.fleet.v1.RegisterOperatorCAResponse.ocsp_probe:type_name -> cryptos.fleet.v1.OcspProbeResult - 141, // 31: cryptos.fleet.v1.RetireOperatorCAResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA - 143, // 32: cryptos.fleet.v1.SetOperatorCACRLSourceRequest.acknowledgements:type_name -> cryptos.fleet.v1.OperatorCAAcknowledgement - 141, // 33: cryptos.fleet.v1.SetOperatorCACRLSourceResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA - 141, // 34: cryptos.fleet.v1.UploadOperatorCRLResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA - 142, // 35: cryptos.fleet.v1.SetOperatorCAOCSPRequest.ocsp_mode:type_name -> cryptos.fleet.v1.OcspMode - 141, // 36: cryptos.fleet.v1.SetOperatorCAOCSPResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA - 144, // 37: cryptos.fleet.v1.SetOperatorCAOCSPResponse.ocsp_probe:type_name -> cryptos.fleet.v1.OcspProbeResult - 145, // 38: cryptos.fleet.v1.ListInstallDisksResponse.disks:type_name -> cryptos.node.v1.InstallDisk - 139, // 39: cryptos.fleet.v1.AdoptNodeRequest.config:type_name -> cryptos.node.v1.MachineConfig + 150, // 26: cryptos.fleet.v1.ListOperatorCAsResponse.items:type_name -> cryptos.fleet.v1.OperatorCA + 151, // 27: cryptos.fleet.v1.RegisterOperatorCARequest.ocsp_mode:type_name -> cryptos.fleet.v1.OcspMode + 152, // 28: cryptos.fleet.v1.RegisterOperatorCARequest.acknowledgements:type_name -> cryptos.fleet.v1.OperatorCAAcknowledgement + 150, // 29: cryptos.fleet.v1.RegisterOperatorCAResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA + 153, // 30: cryptos.fleet.v1.RegisterOperatorCAResponse.ocsp_probe:type_name -> cryptos.fleet.v1.OcspProbeResult + 150, // 31: cryptos.fleet.v1.RetireOperatorCAResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA + 152, // 32: cryptos.fleet.v1.SetOperatorCACRLSourceRequest.acknowledgements:type_name -> cryptos.fleet.v1.OperatorCAAcknowledgement + 150, // 33: cryptos.fleet.v1.SetOperatorCACRLSourceResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA + 150, // 34: cryptos.fleet.v1.UploadOperatorCRLResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA + 151, // 35: cryptos.fleet.v1.SetOperatorCAOCSPRequest.ocsp_mode:type_name -> cryptos.fleet.v1.OcspMode + 150, // 36: cryptos.fleet.v1.SetOperatorCAOCSPResponse.operator_ca:type_name -> cryptos.fleet.v1.OperatorCA + 153, // 37: cryptos.fleet.v1.SetOperatorCAOCSPResponse.ocsp_probe:type_name -> cryptos.fleet.v1.OcspProbeResult + 154, // 38: cryptos.fleet.v1.ListInstallDisksResponse.disks:type_name -> cryptos.node.v1.InstallDisk + 148, // 39: cryptos.fleet.v1.AdoptNodeRequest.config:type_name -> cryptos.node.v1.MachineConfig 29, // 40: cryptos.fleet.v1.RenameNodeResponse.node:type_name -> cryptos.fleet.v1.NodeSummary 29, // 41: cryptos.fleet.v1.RemoveNodeResponse.node:type_name -> cryptos.fleet.v1.NodeSummary 111, // 42: cryptos.fleet.v1.ListMcpKeysResponse.items:type_name -> cryptos.fleet.v1.McpKey @@ -10651,133 +11329,144 @@ var file_cryptos_fleet_v1_fleet_proto_depIdxs = []int32{ 117, // 49: cryptos.fleet.v1.GetCertificateRequestByIDResponse.request:type_name -> cryptos.fleet.v1.CertificateRequest 117, // 50: cryptos.fleet.v1.CancelCertificateRequestResponse.request:type_name -> cryptos.fleet.v1.CertificateRequest 127, // 51: cryptos.fleet.v1.ListNodeTsaCertificatesResponse.certificates:type_name -> cryptos.fleet.v1.NodeTsaCertificate - 136, // 52: cryptos.fleet.v1.NodeAuditEvent.details:type_name -> cryptos.fleet.v1.NodeAuditEvent.DetailsEntry + 145, // 52: cryptos.fleet.v1.NodeAuditEvent.details:type_name -> cryptos.fleet.v1.NodeAuditEvent.DetailsEntry 132, // 53: cryptos.fleet.v1.ListNodeAuditEventsResponse.entries:type_name -> cryptos.fleet.v1.NodeAuditEvent - 1, // 54: cryptos.fleet.v1.FleetService.ListNodes:input_type -> cryptos.fleet.v1.ListNodesRequest - 3, // 55: cryptos.fleet.v1.FleetService.GetNode:input_type -> cryptos.fleet.v1.GetNodeRequest - 5, // 56: cryptos.fleet.v1.FleetService.ListCertificates:input_type -> cryptos.fleet.v1.ListCertificatesRequest - 7, // 57: cryptos.fleet.v1.FleetService.ListProfiles:input_type -> cryptos.fleet.v1.ListProfilesRequest - 9, // 58: cryptos.fleet.v1.FleetService.CreateProfile:input_type -> cryptos.fleet.v1.CreateProfileRequest - 11, // 59: cryptos.fleet.v1.FleetService.UpdateProfile:input_type -> cryptos.fleet.v1.UpdateProfileRequest - 13, // 60: cryptos.fleet.v1.FleetService.DeleteProfile:input_type -> cryptos.fleet.v1.DeleteProfileRequest - 15, // 61: cryptos.fleet.v1.FleetService.ApplyProfileToNode:input_type -> cryptos.fleet.v1.ApplyProfileToNodeRequest - 17, // 62: cryptos.fleet.v1.FleetService.SetProfileRequestable:input_type -> cryptos.fleet.v1.SetProfileRequestableRequest - 19, // 63: cryptos.fleet.v1.FleetService.ListRequestableProfiles:input_type -> cryptos.fleet.v1.ListRequestableProfilesRequest - 21, // 64: cryptos.fleet.v1.FleetService.ListAdapters:input_type -> cryptos.fleet.v1.ListAdaptersRequest - 23, // 65: cryptos.fleet.v1.FleetService.SetAdapterEnabled:input_type -> cryptos.fleet.v1.SetAdapterEnabledRequest - 57, // 66: cryptos.fleet.v1.FleetService.SetNodeProtocol:input_type -> cryptos.fleet.v1.SetNodeProtocolRequest - 25, // 67: cryptos.fleet.v1.FleetService.ListAudit:input_type -> cryptos.fleet.v1.ListAuditRequest - 27, // 68: cryptos.fleet.v1.FleetService.ListEnrollments:input_type -> cryptos.fleet.v1.ListEnrollmentsRequest - 36, // 69: cryptos.fleet.v1.FleetService.CreateEnrollment:input_type -> cryptos.fleet.v1.CreateEnrollmentRequest - 38, // 70: cryptos.fleet.v1.FleetService.ApproveEnrollment:input_type -> cryptos.fleet.v1.ApproveEnrollmentRequest - 40, // 71: cryptos.fleet.v1.FleetService.RejectEnrollment:input_type -> cryptos.fleet.v1.RejectEnrollmentRequest - 42, // 72: cryptos.fleet.v1.FleetService.WhoAmI:input_type -> cryptos.fleet.v1.WhoAmIRequest - 45, // 73: cryptos.fleet.v1.FleetService.RevokeCertificate:input_type -> cryptos.fleet.v1.RevokeCertificateRequest - 47, // 74: cryptos.fleet.v1.FleetService.GetCertificate:input_type -> cryptos.fleet.v1.GetCertificateRequest - 131, // 75: cryptos.fleet.v1.FleetService.ListNodeAuditEvents:input_type -> cryptos.fleet.v1.ListNodeAuditEventsRequest - 134, // 76: cryptos.fleet.v1.FleetService.VerifyNodeAuditChain:input_type -> cryptos.fleet.v1.VerifyNodeAuditChainRequest - 129, // 77: cryptos.fleet.v1.FleetService.ValidateCertificateChain:input_type -> cryptos.fleet.v1.ValidateCertificateChainRequest - 126, // 78: cryptos.fleet.v1.FleetService.ListNodeTsaCertificates:input_type -> cryptos.fleet.v1.ListNodeTsaCertificatesRequest - 49, // 79: cryptos.fleet.v1.FleetService.IssueLeaf:input_type -> cryptos.fleet.v1.IssueLeafRequest - 51, // 80: cryptos.fleet.v1.FleetService.RekeyNode:input_type -> cryptos.fleet.v1.RekeyNodeRequest - 53, // 81: cryptos.fleet.v1.FleetService.GetNodeConfig:input_type -> cryptos.fleet.v1.GetNodeConfigRequest - 55, // 82: cryptos.fleet.v1.FleetService.ApplyNodeConfig:input_type -> cryptos.fleet.v1.ApplyNodeConfigRequest - 59, // 83: cryptos.fleet.v1.FleetService.ExportCAKey:input_type -> cryptos.fleet.v1.ExportCAKeyRequest - 61, // 84: cryptos.fleet.v1.FleetService.ImportCAKey:input_type -> cryptos.fleet.v1.ImportCAKeyRequest - 68, // 85: cryptos.fleet.v1.FleetService.CreateOperatorCredentialRequest:input_type -> cryptos.fleet.v1.CreateOperatorCredentialRequestRequest - 70, // 86: cryptos.fleet.v1.FleetService.ListOperatorCredentialRequests:input_type -> cryptos.fleet.v1.ListOperatorCredentialRequestsRequest - 72, // 87: cryptos.fleet.v1.FleetService.CancelOperatorCredentialRequest:input_type -> cryptos.fleet.v1.CancelOperatorCredentialRequestRequest - 75, // 88: cryptos.fleet.v1.FleetService.RecordOperatorCredential:input_type -> cryptos.fleet.v1.RecordOperatorCredentialRequest - 63, // 89: cryptos.fleet.v1.FleetService.RevokeOperatorCredential:input_type -> cryptos.fleet.v1.RevokeOperatorCredentialRequest - 65, // 90: cryptos.fleet.v1.FleetService.ListOperatorCredentials:input_type -> cryptos.fleet.v1.ListOperatorCredentialsRequest - 77, // 91: cryptos.fleet.v1.FleetService.ListOperatorCAs:input_type -> cryptos.fleet.v1.ListOperatorCAsRequest - 79, // 92: cryptos.fleet.v1.FleetService.RegisterOperatorCA:input_type -> cryptos.fleet.v1.RegisterOperatorCARequest - 81, // 93: cryptos.fleet.v1.FleetService.RetireOperatorCA:input_type -> cryptos.fleet.v1.RetireOperatorCARequest - 83, // 94: cryptos.fleet.v1.FleetService.SetOperatorCACRLSource:input_type -> cryptos.fleet.v1.SetOperatorCACRLSourceRequest - 85, // 95: cryptos.fleet.v1.FleetService.UploadOperatorCRL:input_type -> cryptos.fleet.v1.UploadOperatorCRLRequest - 87, // 96: cryptos.fleet.v1.FleetService.SetOperatorCAOCSP:input_type -> cryptos.fleet.v1.SetOperatorCAOCSPRequest - 89, // 97: cryptos.fleet.v1.FleetService.PreviewAdoption:input_type -> cryptos.fleet.v1.PreviewAdoptionRequest - 91, // 98: cryptos.fleet.v1.FleetService.ListInstallDisks:input_type -> cryptos.fleet.v1.ListInstallDisksRequest - 93, // 99: cryptos.fleet.v1.FleetService.AdoptNode:input_type -> cryptos.fleet.v1.AdoptNodeRequest - 95, // 100: cryptos.fleet.v1.FleetService.ConfirmAdoptionFingerprint:input_type -> cryptos.fleet.v1.ConfirmAdoptionFingerprintRequest - 97, // 101: cryptos.fleet.v1.FleetService.DecommissionNode:input_type -> cryptos.fleet.v1.DecommissionNodeRequest - 99, // 102: cryptos.fleet.v1.FleetService.RebootNode:input_type -> cryptos.fleet.v1.RebootNodeRequest - 101, // 103: cryptos.fleet.v1.FleetService.RenameNode:input_type -> cryptos.fleet.v1.RenameNodeRequest - 103, // 104: cryptos.fleet.v1.FleetService.RemoveNode:input_type -> cryptos.fleet.v1.RemoveNodeRequest - 105, // 105: cryptos.fleet.v1.FleetService.ListMcpKeys:input_type -> cryptos.fleet.v1.ListMcpKeysRequest - 107, // 106: cryptos.fleet.v1.FleetService.RevokeMcpKey:input_type -> cryptos.fleet.v1.RevokeMcpKeyRequest - 109, // 107: cryptos.fleet.v1.FleetService.CreateMcpKey:input_type -> cryptos.fleet.v1.CreateMcpKeyRequest - 112, // 108: cryptos.fleet.v1.FleetService.ListApprovals:input_type -> cryptos.fleet.v1.ListApprovalsRequest - 114, // 109: cryptos.fleet.v1.FleetService.DecideApproval:input_type -> cryptos.fleet.v1.DecideApprovalRequest - 118, // 110: cryptos.fleet.v1.FleetService.CreateCertificateRequest:input_type -> cryptos.fleet.v1.CreateCertificateRequestRequest - 120, // 111: cryptos.fleet.v1.FleetService.ListCertificateRequests:input_type -> cryptos.fleet.v1.ListCertificateRequestsRequest - 122, // 112: cryptos.fleet.v1.FleetService.GetCertificateRequestByID:input_type -> cryptos.fleet.v1.GetCertificateRequestByIDRequest - 124, // 113: cryptos.fleet.v1.FleetService.CancelCertificateRequest:input_type -> cryptos.fleet.v1.CancelCertificateRequestRequest - 2, // 114: cryptos.fleet.v1.FleetService.ListNodes:output_type -> cryptos.fleet.v1.ListNodesResponse - 4, // 115: cryptos.fleet.v1.FleetService.GetNode:output_type -> cryptos.fleet.v1.GetNodeResponse - 6, // 116: cryptos.fleet.v1.FleetService.ListCertificates:output_type -> cryptos.fleet.v1.ListCertificatesResponse - 8, // 117: cryptos.fleet.v1.FleetService.ListProfiles:output_type -> cryptos.fleet.v1.ListProfilesResponse - 10, // 118: cryptos.fleet.v1.FleetService.CreateProfile:output_type -> cryptos.fleet.v1.CreateProfileResponse - 12, // 119: cryptos.fleet.v1.FleetService.UpdateProfile:output_type -> cryptos.fleet.v1.UpdateProfileResponse - 14, // 120: cryptos.fleet.v1.FleetService.DeleteProfile:output_type -> cryptos.fleet.v1.DeleteProfileResponse - 16, // 121: cryptos.fleet.v1.FleetService.ApplyProfileToNode:output_type -> cryptos.fleet.v1.ApplyProfileToNodeResponse - 18, // 122: cryptos.fleet.v1.FleetService.SetProfileRequestable:output_type -> cryptos.fleet.v1.SetProfileRequestableResponse - 20, // 123: cryptos.fleet.v1.FleetService.ListRequestableProfiles:output_type -> cryptos.fleet.v1.ListRequestableProfilesResponse - 22, // 124: cryptos.fleet.v1.FleetService.ListAdapters:output_type -> cryptos.fleet.v1.ListAdaptersResponse - 24, // 125: cryptos.fleet.v1.FleetService.SetAdapterEnabled:output_type -> cryptos.fleet.v1.SetAdapterEnabledResponse - 58, // 126: cryptos.fleet.v1.FleetService.SetNodeProtocol:output_type -> cryptos.fleet.v1.SetNodeProtocolResponse - 26, // 127: cryptos.fleet.v1.FleetService.ListAudit:output_type -> cryptos.fleet.v1.ListAuditResponse - 28, // 128: cryptos.fleet.v1.FleetService.ListEnrollments:output_type -> cryptos.fleet.v1.ListEnrollmentsResponse - 37, // 129: cryptos.fleet.v1.FleetService.CreateEnrollment:output_type -> cryptos.fleet.v1.CreateEnrollmentResponse - 39, // 130: cryptos.fleet.v1.FleetService.ApproveEnrollment:output_type -> cryptos.fleet.v1.ApproveEnrollmentResponse - 41, // 131: cryptos.fleet.v1.FleetService.RejectEnrollment:output_type -> cryptos.fleet.v1.RejectEnrollmentResponse - 44, // 132: cryptos.fleet.v1.FleetService.WhoAmI:output_type -> cryptos.fleet.v1.WhoAmIResponse - 46, // 133: cryptos.fleet.v1.FleetService.RevokeCertificate:output_type -> cryptos.fleet.v1.RevokeCertificateResponse - 48, // 134: cryptos.fleet.v1.FleetService.GetCertificate:output_type -> cryptos.fleet.v1.GetCertificateResponse - 133, // 135: cryptos.fleet.v1.FleetService.ListNodeAuditEvents:output_type -> cryptos.fleet.v1.ListNodeAuditEventsResponse - 135, // 136: cryptos.fleet.v1.FleetService.VerifyNodeAuditChain:output_type -> cryptos.fleet.v1.VerifyNodeAuditChainResponse - 130, // 137: cryptos.fleet.v1.FleetService.ValidateCertificateChain:output_type -> cryptos.fleet.v1.ValidateCertificateChainResponse - 128, // 138: cryptos.fleet.v1.FleetService.ListNodeTsaCertificates:output_type -> cryptos.fleet.v1.ListNodeTsaCertificatesResponse - 50, // 139: cryptos.fleet.v1.FleetService.IssueLeaf:output_type -> cryptos.fleet.v1.IssueLeafResponse - 52, // 140: cryptos.fleet.v1.FleetService.RekeyNode:output_type -> cryptos.fleet.v1.RekeyNodeResponse - 54, // 141: cryptos.fleet.v1.FleetService.GetNodeConfig:output_type -> cryptos.fleet.v1.GetNodeConfigResponse - 56, // 142: cryptos.fleet.v1.FleetService.ApplyNodeConfig:output_type -> cryptos.fleet.v1.ApplyNodeConfigResponse - 60, // 143: cryptos.fleet.v1.FleetService.ExportCAKey:output_type -> cryptos.fleet.v1.ExportCAKeyResponse - 62, // 144: cryptos.fleet.v1.FleetService.ImportCAKey:output_type -> cryptos.fleet.v1.ImportCAKeyResponse - 69, // 145: cryptos.fleet.v1.FleetService.CreateOperatorCredentialRequest:output_type -> cryptos.fleet.v1.CreateOperatorCredentialRequestResponse - 71, // 146: cryptos.fleet.v1.FleetService.ListOperatorCredentialRequests:output_type -> cryptos.fleet.v1.ListOperatorCredentialRequestsResponse - 73, // 147: cryptos.fleet.v1.FleetService.CancelOperatorCredentialRequest:output_type -> cryptos.fleet.v1.CancelOperatorCredentialRequestResponse - 76, // 148: cryptos.fleet.v1.FleetService.RecordOperatorCredential:output_type -> cryptos.fleet.v1.RecordOperatorCredentialResponse - 64, // 149: cryptos.fleet.v1.FleetService.RevokeOperatorCredential:output_type -> cryptos.fleet.v1.RevokeOperatorCredentialResponse - 67, // 150: cryptos.fleet.v1.FleetService.ListOperatorCredentials:output_type -> cryptos.fleet.v1.ListOperatorCredentialsResponse - 78, // 151: cryptos.fleet.v1.FleetService.ListOperatorCAs:output_type -> cryptos.fleet.v1.ListOperatorCAsResponse - 80, // 152: cryptos.fleet.v1.FleetService.RegisterOperatorCA:output_type -> cryptos.fleet.v1.RegisterOperatorCAResponse - 82, // 153: cryptos.fleet.v1.FleetService.RetireOperatorCA:output_type -> cryptos.fleet.v1.RetireOperatorCAResponse - 84, // 154: cryptos.fleet.v1.FleetService.SetOperatorCACRLSource:output_type -> cryptos.fleet.v1.SetOperatorCACRLSourceResponse - 86, // 155: cryptos.fleet.v1.FleetService.UploadOperatorCRL:output_type -> cryptos.fleet.v1.UploadOperatorCRLResponse - 88, // 156: cryptos.fleet.v1.FleetService.SetOperatorCAOCSP:output_type -> cryptos.fleet.v1.SetOperatorCAOCSPResponse - 90, // 157: cryptos.fleet.v1.FleetService.PreviewAdoption:output_type -> cryptos.fleet.v1.PreviewAdoptionResponse - 92, // 158: cryptos.fleet.v1.FleetService.ListInstallDisks:output_type -> cryptos.fleet.v1.ListInstallDisksResponse - 94, // 159: cryptos.fleet.v1.FleetService.AdoptNode:output_type -> cryptos.fleet.v1.AdoptNodeResponse - 96, // 160: cryptos.fleet.v1.FleetService.ConfirmAdoptionFingerprint:output_type -> cryptos.fleet.v1.ConfirmAdoptionFingerprintResponse - 98, // 161: cryptos.fleet.v1.FleetService.DecommissionNode:output_type -> cryptos.fleet.v1.DecommissionNodeResponse - 100, // 162: cryptos.fleet.v1.FleetService.RebootNode:output_type -> cryptos.fleet.v1.RebootNodeResponse - 102, // 163: cryptos.fleet.v1.FleetService.RenameNode:output_type -> cryptos.fleet.v1.RenameNodeResponse - 104, // 164: cryptos.fleet.v1.FleetService.RemoveNode:output_type -> cryptos.fleet.v1.RemoveNodeResponse - 106, // 165: cryptos.fleet.v1.FleetService.ListMcpKeys:output_type -> cryptos.fleet.v1.ListMcpKeysResponse - 108, // 166: cryptos.fleet.v1.FleetService.RevokeMcpKey:output_type -> cryptos.fleet.v1.RevokeMcpKeyResponse - 110, // 167: cryptos.fleet.v1.FleetService.CreateMcpKey:output_type -> cryptos.fleet.v1.CreateMcpKeyResponse - 113, // 168: cryptos.fleet.v1.FleetService.ListApprovals:output_type -> cryptos.fleet.v1.ListApprovalsResponse - 115, // 169: cryptos.fleet.v1.FleetService.DecideApproval:output_type -> cryptos.fleet.v1.DecideApprovalResponse - 119, // 170: cryptos.fleet.v1.FleetService.CreateCertificateRequest:output_type -> cryptos.fleet.v1.CreateCertificateRequestResponse - 121, // 171: cryptos.fleet.v1.FleetService.ListCertificateRequests:output_type -> cryptos.fleet.v1.ListCertificateRequestsResponse - 123, // 172: cryptos.fleet.v1.FleetService.GetCertificateRequestByID:output_type -> cryptos.fleet.v1.GetCertificateRequestByIDResponse - 125, // 173: cryptos.fleet.v1.FleetService.CancelCertificateRequest:output_type -> cryptos.fleet.v1.CancelCertificateRequestResponse - 114, // [114:174] is the sub-list for method output_type - 54, // [54:114] is the sub-list for method input_type - 54, // [54:54] is the sub-list for extension type_name - 54, // [54:54] is the sub-list for extension extendee - 0, // [0:54] is the sub-list for field type_name + 137, // 54: cryptos.fleet.v1.GetNodeImageStatusResponse.status:type_name -> cryptos.fleet.v1.NodeImageStatus + 137, // 55: cryptos.fleet.v1.StageNodeImageResponse.status:type_name -> cryptos.fleet.v1.NodeImageStatus + 137, // 56: cryptos.fleet.v1.RollbackNodeImageResponse.status:type_name -> cryptos.fleet.v1.NodeImageStatus + 1, // 57: cryptos.fleet.v1.FleetService.ListNodes:input_type -> cryptos.fleet.v1.ListNodesRequest + 3, // 58: cryptos.fleet.v1.FleetService.GetNode:input_type -> cryptos.fleet.v1.GetNodeRequest + 5, // 59: cryptos.fleet.v1.FleetService.ListCertificates:input_type -> cryptos.fleet.v1.ListCertificatesRequest + 7, // 60: cryptos.fleet.v1.FleetService.ListProfiles:input_type -> cryptos.fleet.v1.ListProfilesRequest + 9, // 61: cryptos.fleet.v1.FleetService.CreateProfile:input_type -> cryptos.fleet.v1.CreateProfileRequest + 11, // 62: cryptos.fleet.v1.FleetService.UpdateProfile:input_type -> cryptos.fleet.v1.UpdateProfileRequest + 13, // 63: cryptos.fleet.v1.FleetService.DeleteProfile:input_type -> cryptos.fleet.v1.DeleteProfileRequest + 15, // 64: cryptos.fleet.v1.FleetService.ApplyProfileToNode:input_type -> cryptos.fleet.v1.ApplyProfileToNodeRequest + 17, // 65: cryptos.fleet.v1.FleetService.SetProfileRequestable:input_type -> cryptos.fleet.v1.SetProfileRequestableRequest + 19, // 66: cryptos.fleet.v1.FleetService.ListRequestableProfiles:input_type -> cryptos.fleet.v1.ListRequestableProfilesRequest + 21, // 67: cryptos.fleet.v1.FleetService.ListAdapters:input_type -> cryptos.fleet.v1.ListAdaptersRequest + 23, // 68: cryptos.fleet.v1.FleetService.SetAdapterEnabled:input_type -> cryptos.fleet.v1.SetAdapterEnabledRequest + 57, // 69: cryptos.fleet.v1.FleetService.SetNodeProtocol:input_type -> cryptos.fleet.v1.SetNodeProtocolRequest + 25, // 70: cryptos.fleet.v1.FleetService.ListAudit:input_type -> cryptos.fleet.v1.ListAuditRequest + 27, // 71: cryptos.fleet.v1.FleetService.ListEnrollments:input_type -> cryptos.fleet.v1.ListEnrollmentsRequest + 36, // 72: cryptos.fleet.v1.FleetService.CreateEnrollment:input_type -> cryptos.fleet.v1.CreateEnrollmentRequest + 38, // 73: cryptos.fleet.v1.FleetService.ApproveEnrollment:input_type -> cryptos.fleet.v1.ApproveEnrollmentRequest + 40, // 74: cryptos.fleet.v1.FleetService.RejectEnrollment:input_type -> cryptos.fleet.v1.RejectEnrollmentRequest + 42, // 75: cryptos.fleet.v1.FleetService.WhoAmI:input_type -> cryptos.fleet.v1.WhoAmIRequest + 45, // 76: cryptos.fleet.v1.FleetService.RevokeCertificate:input_type -> cryptos.fleet.v1.RevokeCertificateRequest + 47, // 77: cryptos.fleet.v1.FleetService.GetCertificate:input_type -> cryptos.fleet.v1.GetCertificateRequest + 131, // 78: cryptos.fleet.v1.FleetService.ListNodeAuditEvents:input_type -> cryptos.fleet.v1.ListNodeAuditEventsRequest + 134, // 79: cryptos.fleet.v1.FleetService.VerifyNodeAuditChain:input_type -> cryptos.fleet.v1.VerifyNodeAuditChainRequest + 129, // 80: cryptos.fleet.v1.FleetService.ValidateCertificateChain:input_type -> cryptos.fleet.v1.ValidateCertificateChainRequest + 126, // 81: cryptos.fleet.v1.FleetService.ListNodeTsaCertificates:input_type -> cryptos.fleet.v1.ListNodeTsaCertificatesRequest + 136, // 82: cryptos.fleet.v1.FleetService.GetNodeImageStatus:input_type -> cryptos.fleet.v1.GetNodeImageStatusRequest + 139, // 83: cryptos.fleet.v1.FleetService.StageNodeImage:input_type -> cryptos.fleet.v1.StageNodeImageRequest + 141, // 84: cryptos.fleet.v1.FleetService.ActivateNodeImage:input_type -> cryptos.fleet.v1.ActivateNodeImageRequest + 143, // 85: cryptos.fleet.v1.FleetService.RollbackNodeImage:input_type -> cryptos.fleet.v1.RollbackNodeImageRequest + 49, // 86: cryptos.fleet.v1.FleetService.IssueLeaf:input_type -> cryptos.fleet.v1.IssueLeafRequest + 51, // 87: cryptos.fleet.v1.FleetService.RekeyNode:input_type -> cryptos.fleet.v1.RekeyNodeRequest + 53, // 88: cryptos.fleet.v1.FleetService.GetNodeConfig:input_type -> cryptos.fleet.v1.GetNodeConfigRequest + 55, // 89: cryptos.fleet.v1.FleetService.ApplyNodeConfig:input_type -> cryptos.fleet.v1.ApplyNodeConfigRequest + 59, // 90: cryptos.fleet.v1.FleetService.ExportCAKey:input_type -> cryptos.fleet.v1.ExportCAKeyRequest + 61, // 91: cryptos.fleet.v1.FleetService.ImportCAKey:input_type -> cryptos.fleet.v1.ImportCAKeyRequest + 68, // 92: cryptos.fleet.v1.FleetService.CreateOperatorCredentialRequest:input_type -> cryptos.fleet.v1.CreateOperatorCredentialRequestRequest + 70, // 93: cryptos.fleet.v1.FleetService.ListOperatorCredentialRequests:input_type -> cryptos.fleet.v1.ListOperatorCredentialRequestsRequest + 72, // 94: cryptos.fleet.v1.FleetService.CancelOperatorCredentialRequest:input_type -> cryptos.fleet.v1.CancelOperatorCredentialRequestRequest + 75, // 95: cryptos.fleet.v1.FleetService.RecordOperatorCredential:input_type -> cryptos.fleet.v1.RecordOperatorCredentialRequest + 63, // 96: cryptos.fleet.v1.FleetService.RevokeOperatorCredential:input_type -> cryptos.fleet.v1.RevokeOperatorCredentialRequest + 65, // 97: cryptos.fleet.v1.FleetService.ListOperatorCredentials:input_type -> cryptos.fleet.v1.ListOperatorCredentialsRequest + 77, // 98: cryptos.fleet.v1.FleetService.ListOperatorCAs:input_type -> cryptos.fleet.v1.ListOperatorCAsRequest + 79, // 99: cryptos.fleet.v1.FleetService.RegisterOperatorCA:input_type -> cryptos.fleet.v1.RegisterOperatorCARequest + 81, // 100: cryptos.fleet.v1.FleetService.RetireOperatorCA:input_type -> cryptos.fleet.v1.RetireOperatorCARequest + 83, // 101: cryptos.fleet.v1.FleetService.SetOperatorCACRLSource:input_type -> cryptos.fleet.v1.SetOperatorCACRLSourceRequest + 85, // 102: cryptos.fleet.v1.FleetService.UploadOperatorCRL:input_type -> cryptos.fleet.v1.UploadOperatorCRLRequest + 87, // 103: cryptos.fleet.v1.FleetService.SetOperatorCAOCSP:input_type -> cryptos.fleet.v1.SetOperatorCAOCSPRequest + 89, // 104: cryptos.fleet.v1.FleetService.PreviewAdoption:input_type -> cryptos.fleet.v1.PreviewAdoptionRequest + 91, // 105: cryptos.fleet.v1.FleetService.ListInstallDisks:input_type -> cryptos.fleet.v1.ListInstallDisksRequest + 93, // 106: cryptos.fleet.v1.FleetService.AdoptNode:input_type -> cryptos.fleet.v1.AdoptNodeRequest + 95, // 107: cryptos.fleet.v1.FleetService.ConfirmAdoptionFingerprint:input_type -> cryptos.fleet.v1.ConfirmAdoptionFingerprintRequest + 97, // 108: cryptos.fleet.v1.FleetService.DecommissionNode:input_type -> cryptos.fleet.v1.DecommissionNodeRequest + 99, // 109: cryptos.fleet.v1.FleetService.RebootNode:input_type -> cryptos.fleet.v1.RebootNodeRequest + 101, // 110: cryptos.fleet.v1.FleetService.RenameNode:input_type -> cryptos.fleet.v1.RenameNodeRequest + 103, // 111: cryptos.fleet.v1.FleetService.RemoveNode:input_type -> cryptos.fleet.v1.RemoveNodeRequest + 105, // 112: cryptos.fleet.v1.FleetService.ListMcpKeys:input_type -> cryptos.fleet.v1.ListMcpKeysRequest + 107, // 113: cryptos.fleet.v1.FleetService.RevokeMcpKey:input_type -> cryptos.fleet.v1.RevokeMcpKeyRequest + 109, // 114: cryptos.fleet.v1.FleetService.CreateMcpKey:input_type -> cryptos.fleet.v1.CreateMcpKeyRequest + 112, // 115: cryptos.fleet.v1.FleetService.ListApprovals:input_type -> cryptos.fleet.v1.ListApprovalsRequest + 114, // 116: cryptos.fleet.v1.FleetService.DecideApproval:input_type -> cryptos.fleet.v1.DecideApprovalRequest + 118, // 117: cryptos.fleet.v1.FleetService.CreateCertificateRequest:input_type -> cryptos.fleet.v1.CreateCertificateRequestRequest + 120, // 118: cryptos.fleet.v1.FleetService.ListCertificateRequests:input_type -> cryptos.fleet.v1.ListCertificateRequestsRequest + 122, // 119: cryptos.fleet.v1.FleetService.GetCertificateRequestByID:input_type -> cryptos.fleet.v1.GetCertificateRequestByIDRequest + 124, // 120: cryptos.fleet.v1.FleetService.CancelCertificateRequest:input_type -> cryptos.fleet.v1.CancelCertificateRequestRequest + 2, // 121: cryptos.fleet.v1.FleetService.ListNodes:output_type -> cryptos.fleet.v1.ListNodesResponse + 4, // 122: cryptos.fleet.v1.FleetService.GetNode:output_type -> cryptos.fleet.v1.GetNodeResponse + 6, // 123: cryptos.fleet.v1.FleetService.ListCertificates:output_type -> cryptos.fleet.v1.ListCertificatesResponse + 8, // 124: cryptos.fleet.v1.FleetService.ListProfiles:output_type -> cryptos.fleet.v1.ListProfilesResponse + 10, // 125: cryptos.fleet.v1.FleetService.CreateProfile:output_type -> cryptos.fleet.v1.CreateProfileResponse + 12, // 126: cryptos.fleet.v1.FleetService.UpdateProfile:output_type -> cryptos.fleet.v1.UpdateProfileResponse + 14, // 127: cryptos.fleet.v1.FleetService.DeleteProfile:output_type -> cryptos.fleet.v1.DeleteProfileResponse + 16, // 128: cryptos.fleet.v1.FleetService.ApplyProfileToNode:output_type -> cryptos.fleet.v1.ApplyProfileToNodeResponse + 18, // 129: cryptos.fleet.v1.FleetService.SetProfileRequestable:output_type -> cryptos.fleet.v1.SetProfileRequestableResponse + 20, // 130: cryptos.fleet.v1.FleetService.ListRequestableProfiles:output_type -> cryptos.fleet.v1.ListRequestableProfilesResponse + 22, // 131: cryptos.fleet.v1.FleetService.ListAdapters:output_type -> cryptos.fleet.v1.ListAdaptersResponse + 24, // 132: cryptos.fleet.v1.FleetService.SetAdapterEnabled:output_type -> cryptos.fleet.v1.SetAdapterEnabledResponse + 58, // 133: cryptos.fleet.v1.FleetService.SetNodeProtocol:output_type -> cryptos.fleet.v1.SetNodeProtocolResponse + 26, // 134: cryptos.fleet.v1.FleetService.ListAudit:output_type -> cryptos.fleet.v1.ListAuditResponse + 28, // 135: cryptos.fleet.v1.FleetService.ListEnrollments:output_type -> cryptos.fleet.v1.ListEnrollmentsResponse + 37, // 136: cryptos.fleet.v1.FleetService.CreateEnrollment:output_type -> cryptos.fleet.v1.CreateEnrollmentResponse + 39, // 137: cryptos.fleet.v1.FleetService.ApproveEnrollment:output_type -> cryptos.fleet.v1.ApproveEnrollmentResponse + 41, // 138: cryptos.fleet.v1.FleetService.RejectEnrollment:output_type -> cryptos.fleet.v1.RejectEnrollmentResponse + 44, // 139: cryptos.fleet.v1.FleetService.WhoAmI:output_type -> cryptos.fleet.v1.WhoAmIResponse + 46, // 140: cryptos.fleet.v1.FleetService.RevokeCertificate:output_type -> cryptos.fleet.v1.RevokeCertificateResponse + 48, // 141: cryptos.fleet.v1.FleetService.GetCertificate:output_type -> cryptos.fleet.v1.GetCertificateResponse + 133, // 142: cryptos.fleet.v1.FleetService.ListNodeAuditEvents:output_type -> cryptos.fleet.v1.ListNodeAuditEventsResponse + 135, // 143: cryptos.fleet.v1.FleetService.VerifyNodeAuditChain:output_type -> cryptos.fleet.v1.VerifyNodeAuditChainResponse + 130, // 144: cryptos.fleet.v1.FleetService.ValidateCertificateChain:output_type -> cryptos.fleet.v1.ValidateCertificateChainResponse + 128, // 145: cryptos.fleet.v1.FleetService.ListNodeTsaCertificates:output_type -> cryptos.fleet.v1.ListNodeTsaCertificatesResponse + 138, // 146: cryptos.fleet.v1.FleetService.GetNodeImageStatus:output_type -> cryptos.fleet.v1.GetNodeImageStatusResponse + 140, // 147: cryptos.fleet.v1.FleetService.StageNodeImage:output_type -> cryptos.fleet.v1.StageNodeImageResponse + 142, // 148: cryptos.fleet.v1.FleetService.ActivateNodeImage:output_type -> cryptos.fleet.v1.ActivateNodeImageResponse + 144, // 149: cryptos.fleet.v1.FleetService.RollbackNodeImage:output_type -> cryptos.fleet.v1.RollbackNodeImageResponse + 50, // 150: cryptos.fleet.v1.FleetService.IssueLeaf:output_type -> cryptos.fleet.v1.IssueLeafResponse + 52, // 151: cryptos.fleet.v1.FleetService.RekeyNode:output_type -> cryptos.fleet.v1.RekeyNodeResponse + 54, // 152: cryptos.fleet.v1.FleetService.GetNodeConfig:output_type -> cryptos.fleet.v1.GetNodeConfigResponse + 56, // 153: cryptos.fleet.v1.FleetService.ApplyNodeConfig:output_type -> cryptos.fleet.v1.ApplyNodeConfigResponse + 60, // 154: cryptos.fleet.v1.FleetService.ExportCAKey:output_type -> cryptos.fleet.v1.ExportCAKeyResponse + 62, // 155: cryptos.fleet.v1.FleetService.ImportCAKey:output_type -> cryptos.fleet.v1.ImportCAKeyResponse + 69, // 156: cryptos.fleet.v1.FleetService.CreateOperatorCredentialRequest:output_type -> cryptos.fleet.v1.CreateOperatorCredentialRequestResponse + 71, // 157: cryptos.fleet.v1.FleetService.ListOperatorCredentialRequests:output_type -> cryptos.fleet.v1.ListOperatorCredentialRequestsResponse + 73, // 158: cryptos.fleet.v1.FleetService.CancelOperatorCredentialRequest:output_type -> cryptos.fleet.v1.CancelOperatorCredentialRequestResponse + 76, // 159: cryptos.fleet.v1.FleetService.RecordOperatorCredential:output_type -> cryptos.fleet.v1.RecordOperatorCredentialResponse + 64, // 160: cryptos.fleet.v1.FleetService.RevokeOperatorCredential:output_type -> cryptos.fleet.v1.RevokeOperatorCredentialResponse + 67, // 161: cryptos.fleet.v1.FleetService.ListOperatorCredentials:output_type -> cryptos.fleet.v1.ListOperatorCredentialsResponse + 78, // 162: cryptos.fleet.v1.FleetService.ListOperatorCAs:output_type -> cryptos.fleet.v1.ListOperatorCAsResponse + 80, // 163: cryptos.fleet.v1.FleetService.RegisterOperatorCA:output_type -> cryptos.fleet.v1.RegisterOperatorCAResponse + 82, // 164: cryptos.fleet.v1.FleetService.RetireOperatorCA:output_type -> cryptos.fleet.v1.RetireOperatorCAResponse + 84, // 165: cryptos.fleet.v1.FleetService.SetOperatorCACRLSource:output_type -> cryptos.fleet.v1.SetOperatorCACRLSourceResponse + 86, // 166: cryptos.fleet.v1.FleetService.UploadOperatorCRL:output_type -> cryptos.fleet.v1.UploadOperatorCRLResponse + 88, // 167: cryptos.fleet.v1.FleetService.SetOperatorCAOCSP:output_type -> cryptos.fleet.v1.SetOperatorCAOCSPResponse + 90, // 168: cryptos.fleet.v1.FleetService.PreviewAdoption:output_type -> cryptos.fleet.v1.PreviewAdoptionResponse + 92, // 169: cryptos.fleet.v1.FleetService.ListInstallDisks:output_type -> cryptos.fleet.v1.ListInstallDisksResponse + 94, // 170: cryptos.fleet.v1.FleetService.AdoptNode:output_type -> cryptos.fleet.v1.AdoptNodeResponse + 96, // 171: cryptos.fleet.v1.FleetService.ConfirmAdoptionFingerprint:output_type -> cryptos.fleet.v1.ConfirmAdoptionFingerprintResponse + 98, // 172: cryptos.fleet.v1.FleetService.DecommissionNode:output_type -> cryptos.fleet.v1.DecommissionNodeResponse + 100, // 173: cryptos.fleet.v1.FleetService.RebootNode:output_type -> cryptos.fleet.v1.RebootNodeResponse + 102, // 174: cryptos.fleet.v1.FleetService.RenameNode:output_type -> cryptos.fleet.v1.RenameNodeResponse + 104, // 175: cryptos.fleet.v1.FleetService.RemoveNode:output_type -> cryptos.fleet.v1.RemoveNodeResponse + 106, // 176: cryptos.fleet.v1.FleetService.ListMcpKeys:output_type -> cryptos.fleet.v1.ListMcpKeysResponse + 108, // 177: cryptos.fleet.v1.FleetService.RevokeMcpKey:output_type -> cryptos.fleet.v1.RevokeMcpKeyResponse + 110, // 178: cryptos.fleet.v1.FleetService.CreateMcpKey:output_type -> cryptos.fleet.v1.CreateMcpKeyResponse + 113, // 179: cryptos.fleet.v1.FleetService.ListApprovals:output_type -> cryptos.fleet.v1.ListApprovalsResponse + 115, // 180: cryptos.fleet.v1.FleetService.DecideApproval:output_type -> cryptos.fleet.v1.DecideApprovalResponse + 119, // 181: cryptos.fleet.v1.FleetService.CreateCertificateRequest:output_type -> cryptos.fleet.v1.CreateCertificateRequestResponse + 121, // 182: cryptos.fleet.v1.FleetService.ListCertificateRequests:output_type -> cryptos.fleet.v1.ListCertificateRequestsResponse + 123, // 183: cryptos.fleet.v1.FleetService.GetCertificateRequestByID:output_type -> cryptos.fleet.v1.GetCertificateRequestByIDResponse + 125, // 184: cryptos.fleet.v1.FleetService.CancelCertificateRequest:output_type -> cryptos.fleet.v1.CancelCertificateRequestResponse + 121, // [121:185] is the sub-list for method output_type + 57, // [57:121] is the sub-list for method input_type + 57, // [57:57] is the sub-list for extension type_name + 57, // [57:57] is the sub-list for extension extendee + 0, // [0:57] is the sub-list for field type_name } func init() { file_cryptos_fleet_v1_fleet_proto_init() } @@ -12407,6 +13096,114 @@ func file_cryptos_fleet_v1_fleet_proto_init() { return nil } } + file_cryptos_fleet_v1_fleet_proto_msgTypes[135].Exporter = func(v any, i int) any { + switch v := v.(*GetNodeImageStatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[136].Exporter = func(v any, i int) any { + switch v := v.(*NodeImageStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[137].Exporter = func(v any, i int) any { + switch v := v.(*GetNodeImageStatusResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[138].Exporter = func(v any, i int) any { + switch v := v.(*StageNodeImageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[139].Exporter = func(v any, i int) any { + switch v := v.(*StageNodeImageResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[140].Exporter = func(v any, i int) any { + switch v := v.(*ActivateNodeImageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[141].Exporter = func(v any, i int) any { + switch v := v.(*ActivateNodeImageResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[142].Exporter = func(v any, i int) any { + switch v := v.(*RollbackNodeImageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cryptos_fleet_v1_fleet_proto_msgTypes[143].Exporter = func(v any, i int) any { + switch v := v.(*RollbackNodeImageResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_cryptos_fleet_v1_fleet_proto_msgTypes[78].OneofWrappers = []any{ (*RegisterOperatorCARequest_Url)(nil), @@ -12424,7 +13221,7 @@ func file_cryptos_fleet_v1_fleet_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cryptos_fleet_v1_fleet_proto_rawDesc, NumEnums: 1, - NumMessages: 136, + NumMessages: 145, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/go/cryptos/fleet/v1/fleet_grpc.pb.go b/gen/go/cryptos/fleet/v1/fleet_grpc.pb.go index 8f0dd8b..6152e24 100644 --- a/gen/go/cryptos/fleet/v1/fleet_grpc.pb.go +++ b/gen/go/cryptos/fleet/v1/fleet_grpc.pb.go @@ -44,6 +44,10 @@ const ( FleetService_VerifyNodeAuditChain_FullMethodName = "/cryptos.fleet.v1.FleetService/VerifyNodeAuditChain" FleetService_ValidateCertificateChain_FullMethodName = "/cryptos.fleet.v1.FleetService/ValidateCertificateChain" FleetService_ListNodeTsaCertificates_FullMethodName = "/cryptos.fleet.v1.FleetService/ListNodeTsaCertificates" + FleetService_GetNodeImageStatus_FullMethodName = "/cryptos.fleet.v1.FleetService/GetNodeImageStatus" + FleetService_StageNodeImage_FullMethodName = "/cryptos.fleet.v1.FleetService/StageNodeImage" + FleetService_ActivateNodeImage_FullMethodName = "/cryptos.fleet.v1.FleetService/ActivateNodeImage" + FleetService_RollbackNodeImage_FullMethodName = "/cryptos.fleet.v1.FleetService/RollbackNodeImage" FleetService_IssueLeaf_FullMethodName = "/cryptos.fleet.v1.FleetService/IssueLeaf" FleetService_RekeyNode_FullMethodName = "/cryptos.fleet.v1.FleetService/RekeyNode" FleetService_GetNodeConfig_FullMethodName = "/cryptos.fleet.v1.FleetService/GetNodeConfig" @@ -191,6 +195,30 @@ type FleetServiceClient interface { // list while its TSA is not running. Readable at viewer level and above; a // read, so it is not audited. ListNodeTsaCertificates(ctx context.Context, in *ListNodeTsaCertificatesRequest, opts ...grpc.CallOption) (*ListNodeTsaCertificatesResponse, error) + // GetNodeImageStatus reports what CryptOS image a managed node is running, + // what it will boot next, and what it could roll back to. Readable at + // viewer level and above; a read, so it is not audited. + GetNodeImageStatus(ctx context.Context, in *GetNodeImageStatusRequest, opts ...grpc.CallOption) (*GetNodeImageStatusResponse, error) + // StageNodeImage installs a new CryptOS image on a managed node's spare ESP + // slot without touching the one it is running from. The manager fetches + // image_url itself (the browser never carries the image), checks the + // detached release signature, and streams it to the node the same way + // `cryptosctl image stage` does. The node will not boot it until + // ActivateNodeImage runs. Admin-gated (an unreviewed image on a trust + // anchor) and audited; the node's own refusals (a bad signature, or + // FailedPrecondition when another upgrade is already running) are + // surfaced unchanged. + StageNodeImage(ctx context.Context, in *StageNodeImageRequest, opts ...grpc.CallOption) (*StageNodeImageResponse, error) + // ActivateNodeImage reboots a managed node so a staged image starts + // running. confirm_ca_cn must equal the node's current CA common name, the + // same confirmation RebootNode requires, because activating is itself a + // reboot. Admin-gated and audited. + ActivateNodeImage(ctx context.Context, in *ActivateNodeImageRequest, opts ...grpc.CallOption) (*ActivateNodeImageResponse, error) + // RollbackNodeImage puts a managed node's previously running image back on + // the boot path, for a node that was already activated onto a bad image. + // ActivateNodeImage (or a reboot) is still needed to actually boot it. + // Admin-gated and audited. + RollbackNodeImage(ctx context.Context, in *RollbackNodeImageRequest, opts ...grpc.CallOption) (*RollbackNodeImageResponse, error) // IssueLeaf signs a leaf certificate on the named issuing node from a // browser-generated PKCS#10 CSR under a named issuance profile. Only the // CSR crosses the wire; the leaf private key stays in the browser. @@ -656,6 +684,46 @@ func (c *fleetServiceClient) ListNodeTsaCertificates(ctx context.Context, in *Li return out, nil } +func (c *fleetServiceClient) GetNodeImageStatus(ctx context.Context, in *GetNodeImageStatusRequest, opts ...grpc.CallOption) (*GetNodeImageStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetNodeImageStatusResponse) + err := c.cc.Invoke(ctx, FleetService_GetNodeImageStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fleetServiceClient) StageNodeImage(ctx context.Context, in *StageNodeImageRequest, opts ...grpc.CallOption) (*StageNodeImageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(StageNodeImageResponse) + err := c.cc.Invoke(ctx, FleetService_StageNodeImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fleetServiceClient) ActivateNodeImage(ctx context.Context, in *ActivateNodeImageRequest, opts ...grpc.CallOption) (*ActivateNodeImageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ActivateNodeImageResponse) + err := c.cc.Invoke(ctx, FleetService_ActivateNodeImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fleetServiceClient) RollbackNodeImage(ctx context.Context, in *RollbackNodeImageRequest, opts ...grpc.CallOption) (*RollbackNodeImageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RollbackNodeImageResponse) + err := c.cc.Invoke(ctx, FleetService_RollbackNodeImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *fleetServiceClient) IssueLeaf(ctx context.Context, in *IssueLeafRequest, opts ...grpc.CallOption) (*IssueLeafResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(IssueLeafResponse) @@ -1125,6 +1193,30 @@ type FleetServiceServer interface { // list while its TSA is not running. Readable at viewer level and above; a // read, so it is not audited. ListNodeTsaCertificates(context.Context, *ListNodeTsaCertificatesRequest) (*ListNodeTsaCertificatesResponse, error) + // GetNodeImageStatus reports what CryptOS image a managed node is running, + // what it will boot next, and what it could roll back to. Readable at + // viewer level and above; a read, so it is not audited. + GetNodeImageStatus(context.Context, *GetNodeImageStatusRequest) (*GetNodeImageStatusResponse, error) + // StageNodeImage installs a new CryptOS image on a managed node's spare ESP + // slot without touching the one it is running from. The manager fetches + // image_url itself (the browser never carries the image), checks the + // detached release signature, and streams it to the node the same way + // `cryptosctl image stage` does. The node will not boot it until + // ActivateNodeImage runs. Admin-gated (an unreviewed image on a trust + // anchor) and audited; the node's own refusals (a bad signature, or + // FailedPrecondition when another upgrade is already running) are + // surfaced unchanged. + StageNodeImage(context.Context, *StageNodeImageRequest) (*StageNodeImageResponse, error) + // ActivateNodeImage reboots a managed node so a staged image starts + // running. confirm_ca_cn must equal the node's current CA common name, the + // same confirmation RebootNode requires, because activating is itself a + // reboot. Admin-gated and audited. + ActivateNodeImage(context.Context, *ActivateNodeImageRequest) (*ActivateNodeImageResponse, error) + // RollbackNodeImage puts a managed node's previously running image back on + // the boot path, for a node that was already activated onto a bad image. + // ActivateNodeImage (or a reboot) is still needed to actually boot it. + // Admin-gated and audited. + RollbackNodeImage(context.Context, *RollbackNodeImageRequest) (*RollbackNodeImageResponse, error) // IssueLeaf signs a leaf certificate on the named issuing node from a // browser-generated PKCS#10 CSR under a named issuance profile. Only the // CSR crosses the wire; the leaf private key stays in the browser. @@ -1414,6 +1506,18 @@ func (UnimplementedFleetServiceServer) ValidateCertificateChain(context.Context, func (UnimplementedFleetServiceServer) ListNodeTsaCertificates(context.Context, *ListNodeTsaCertificatesRequest) (*ListNodeTsaCertificatesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListNodeTsaCertificates not implemented") } +func (UnimplementedFleetServiceServer) GetNodeImageStatus(context.Context, *GetNodeImageStatusRequest) (*GetNodeImageStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetNodeImageStatus not implemented") +} +func (UnimplementedFleetServiceServer) StageNodeImage(context.Context, *StageNodeImageRequest) (*StageNodeImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StageNodeImage not implemented") +} +func (UnimplementedFleetServiceServer) ActivateNodeImage(context.Context, *ActivateNodeImageRequest) (*ActivateNodeImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ActivateNodeImage not implemented") +} +func (UnimplementedFleetServiceServer) RollbackNodeImage(context.Context, *RollbackNodeImageRequest) (*RollbackNodeImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RollbackNodeImage not implemented") +} func (UnimplementedFleetServiceServer) IssueLeaf(context.Context, *IssueLeafRequest) (*IssueLeafResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method IssueLeaf not implemented") } @@ -1989,6 +2093,78 @@ func _FleetService_ListNodeTsaCertificates_Handler(srv interface{}, ctx context. return interceptor(ctx, in, info, handler) } +func _FleetService_GetNodeImageStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetNodeImageStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FleetServiceServer).GetNodeImageStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FleetService_GetNodeImageStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FleetServiceServer).GetNodeImageStatus(ctx, req.(*GetNodeImageStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _FleetService_StageNodeImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StageNodeImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FleetServiceServer).StageNodeImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FleetService_StageNodeImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FleetServiceServer).StageNodeImage(ctx, req.(*StageNodeImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _FleetService_ActivateNodeImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ActivateNodeImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FleetServiceServer).ActivateNodeImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FleetService_ActivateNodeImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FleetServiceServer).ActivateNodeImage(ctx, req.(*ActivateNodeImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _FleetService_RollbackNodeImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RollbackNodeImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FleetServiceServer).RollbackNodeImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FleetService_RollbackNodeImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FleetServiceServer).RollbackNodeImage(ctx, req.(*RollbackNodeImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _FleetService_IssueLeaf_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(IssueLeafRequest) if err := dec(in); err != nil { @@ -2719,6 +2895,22 @@ var FleetService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListNodeTsaCertificates", Handler: _FleetService_ListNodeTsaCertificates_Handler, }, + { + MethodName: "GetNodeImageStatus", + Handler: _FleetService_GetNodeImageStatus_Handler, + }, + { + MethodName: "StageNodeImage", + Handler: _FleetService_StageNodeImage_Handler, + }, + { + MethodName: "ActivateNodeImage", + Handler: _FleetService_ActivateNodeImage_Handler, + }, + { + MethodName: "RollbackNodeImage", + Handler: _FleetService_RollbackNodeImage_Handler, + }, { MethodName: "IssueLeaf", Handler: _FleetService_IssueLeaf_Handler, diff --git a/gen/go/cryptos/fleet/v1/fleetv1connect/fleet.connect.go b/gen/go/cryptos/fleet/v1/fleetv1connect/fleet.connect.go index fc84087..f7fefbc 100644 --- a/gen/go/cryptos/fleet/v1/fleetv1connect/fleet.connect.go +++ b/gen/go/cryptos/fleet/v1/fleetv1connect/fleet.connect.go @@ -104,6 +104,18 @@ const ( // FleetServiceListNodeTsaCertificatesProcedure is the fully-qualified name of the FleetService's // ListNodeTsaCertificates RPC. FleetServiceListNodeTsaCertificatesProcedure = "/cryptos.fleet.v1.FleetService/ListNodeTsaCertificates" + // FleetServiceGetNodeImageStatusProcedure is the fully-qualified name of the FleetService's + // GetNodeImageStatus RPC. + FleetServiceGetNodeImageStatusProcedure = "/cryptos.fleet.v1.FleetService/GetNodeImageStatus" + // FleetServiceStageNodeImageProcedure is the fully-qualified name of the FleetService's + // StageNodeImage RPC. + FleetServiceStageNodeImageProcedure = "/cryptos.fleet.v1.FleetService/StageNodeImage" + // FleetServiceActivateNodeImageProcedure is the fully-qualified name of the FleetService's + // ActivateNodeImage RPC. + FleetServiceActivateNodeImageProcedure = "/cryptos.fleet.v1.FleetService/ActivateNodeImage" + // FleetServiceRollbackNodeImageProcedure is the fully-qualified name of the FleetService's + // RollbackNodeImage RPC. + FleetServiceRollbackNodeImageProcedure = "/cryptos.fleet.v1.FleetService/RollbackNodeImage" // FleetServiceIssueLeafProcedure is the fully-qualified name of the FleetService's IssueLeaf RPC. FleetServiceIssueLeafProcedure = "/cryptos.fleet.v1.FleetService/IssueLeaf" // FleetServiceRekeyNodeProcedure is the fully-qualified name of the FleetService's RekeyNode RPC. @@ -308,6 +320,30 @@ type FleetServiceClient interface { // list while its TSA is not running. Readable at viewer level and above; a // read, so it is not audited. ListNodeTsaCertificates(context.Context, *connect.Request[v1.ListNodeTsaCertificatesRequest]) (*connect.Response[v1.ListNodeTsaCertificatesResponse], error) + // GetNodeImageStatus reports what CryptOS image a managed node is running, + // what it will boot next, and what it could roll back to. Readable at + // viewer level and above; a read, so it is not audited. + GetNodeImageStatus(context.Context, *connect.Request[v1.GetNodeImageStatusRequest]) (*connect.Response[v1.GetNodeImageStatusResponse], error) + // StageNodeImage installs a new CryptOS image on a managed node's spare ESP + // slot without touching the one it is running from. The manager fetches + // image_url itself (the browser never carries the image), checks the + // detached release signature, and streams it to the node the same way + // `cryptosctl image stage` does. The node will not boot it until + // ActivateNodeImage runs. Admin-gated (an unreviewed image on a trust + // anchor) and audited; the node's own refusals (a bad signature, or + // FailedPrecondition when another upgrade is already running) are + // surfaced unchanged. + StageNodeImage(context.Context, *connect.Request[v1.StageNodeImageRequest]) (*connect.Response[v1.StageNodeImageResponse], error) + // ActivateNodeImage reboots a managed node so a staged image starts + // running. confirm_ca_cn must equal the node's current CA common name, the + // same confirmation RebootNode requires, because activating is itself a + // reboot. Admin-gated and audited. + ActivateNodeImage(context.Context, *connect.Request[v1.ActivateNodeImageRequest]) (*connect.Response[v1.ActivateNodeImageResponse], error) + // RollbackNodeImage puts a managed node's previously running image back on + // the boot path, for a node that was already activated onto a bad image. + // ActivateNodeImage (or a reboot) is still needed to actually boot it. + // Admin-gated and audited. + RollbackNodeImage(context.Context, *connect.Request[v1.RollbackNodeImageRequest]) (*connect.Response[v1.RollbackNodeImageResponse], error) // IssueLeaf signs a leaf certificate on the named issuing node from a // browser-generated PKCS#10 CSR under a named issuance profile. Only the // CSR crosses the wire; the leaf private key stays in the browser. @@ -676,6 +712,30 @@ func NewFleetServiceClient(httpClient connect.HTTPClient, baseURL string, opts . connect.WithSchema(fleetServiceMethods.ByName("ListNodeTsaCertificates")), connect.WithClientOptions(opts...), ), + getNodeImageStatus: connect.NewClient[v1.GetNodeImageStatusRequest, v1.GetNodeImageStatusResponse]( + httpClient, + baseURL+FleetServiceGetNodeImageStatusProcedure, + connect.WithSchema(fleetServiceMethods.ByName("GetNodeImageStatus")), + connect.WithClientOptions(opts...), + ), + stageNodeImage: connect.NewClient[v1.StageNodeImageRequest, v1.StageNodeImageResponse]( + httpClient, + baseURL+FleetServiceStageNodeImageProcedure, + connect.WithSchema(fleetServiceMethods.ByName("StageNodeImage")), + connect.WithClientOptions(opts...), + ), + activateNodeImage: connect.NewClient[v1.ActivateNodeImageRequest, v1.ActivateNodeImageResponse]( + httpClient, + baseURL+FleetServiceActivateNodeImageProcedure, + connect.WithSchema(fleetServiceMethods.ByName("ActivateNodeImage")), + connect.WithClientOptions(opts...), + ), + rollbackNodeImage: connect.NewClient[v1.RollbackNodeImageRequest, v1.RollbackNodeImageResponse]( + httpClient, + baseURL+FleetServiceRollbackNodeImageProcedure, + connect.WithSchema(fleetServiceMethods.ByName("RollbackNodeImage")), + connect.WithClientOptions(opts...), + ), issueLeaf: connect.NewClient[v1.IssueLeafRequest, v1.IssueLeafResponse]( httpClient, baseURL+FleetServiceIssueLeafProcedure, @@ -916,6 +976,10 @@ type fleetServiceClient struct { verifyNodeAuditChain *connect.Client[v1.VerifyNodeAuditChainRequest, v1.VerifyNodeAuditChainResponse] validateCertificateChain *connect.Client[v1.ValidateCertificateChainRequest, v1.ValidateCertificateChainResponse] listNodeTsaCertificates *connect.Client[v1.ListNodeTsaCertificatesRequest, v1.ListNodeTsaCertificatesResponse] + getNodeImageStatus *connect.Client[v1.GetNodeImageStatusRequest, v1.GetNodeImageStatusResponse] + stageNodeImage *connect.Client[v1.StageNodeImageRequest, v1.StageNodeImageResponse] + activateNodeImage *connect.Client[v1.ActivateNodeImageRequest, v1.ActivateNodeImageResponse] + rollbackNodeImage *connect.Client[v1.RollbackNodeImageRequest, v1.RollbackNodeImageResponse] issueLeaf *connect.Client[v1.IssueLeafRequest, v1.IssueLeafResponse] rekeyNode *connect.Client[v1.RekeyNodeRequest, v1.RekeyNodeResponse] getNodeConfig *connect.Client[v1.GetNodeConfigRequest, v1.GetNodeConfigResponse] @@ -1078,6 +1142,26 @@ func (c *fleetServiceClient) ListNodeTsaCertificates(ctx context.Context, req *c return c.listNodeTsaCertificates.CallUnary(ctx, req) } +// GetNodeImageStatus calls cryptos.fleet.v1.FleetService.GetNodeImageStatus. +func (c *fleetServiceClient) GetNodeImageStatus(ctx context.Context, req *connect.Request[v1.GetNodeImageStatusRequest]) (*connect.Response[v1.GetNodeImageStatusResponse], error) { + return c.getNodeImageStatus.CallUnary(ctx, req) +} + +// StageNodeImage calls cryptos.fleet.v1.FleetService.StageNodeImage. +func (c *fleetServiceClient) StageNodeImage(ctx context.Context, req *connect.Request[v1.StageNodeImageRequest]) (*connect.Response[v1.StageNodeImageResponse], error) { + return c.stageNodeImage.CallUnary(ctx, req) +} + +// ActivateNodeImage calls cryptos.fleet.v1.FleetService.ActivateNodeImage. +func (c *fleetServiceClient) ActivateNodeImage(ctx context.Context, req *connect.Request[v1.ActivateNodeImageRequest]) (*connect.Response[v1.ActivateNodeImageResponse], error) { + return c.activateNodeImage.CallUnary(ctx, req) +} + +// RollbackNodeImage calls cryptos.fleet.v1.FleetService.RollbackNodeImage. +func (c *fleetServiceClient) RollbackNodeImage(ctx context.Context, req *connect.Request[v1.RollbackNodeImageRequest]) (*connect.Response[v1.RollbackNodeImageResponse], error) { + return c.rollbackNodeImage.CallUnary(ctx, req) +} + // IssueLeaf calls cryptos.fleet.v1.FleetService.IssueLeaf. func (c *fleetServiceClient) IssueLeaf(ctx context.Context, req *connect.Request[v1.IssueLeafRequest]) (*connect.Response[v1.IssueLeafResponse], error) { return c.issueLeaf.CallUnary(ctx, req) @@ -1359,6 +1443,30 @@ type FleetServiceHandler interface { // list while its TSA is not running. Readable at viewer level and above; a // read, so it is not audited. ListNodeTsaCertificates(context.Context, *connect.Request[v1.ListNodeTsaCertificatesRequest]) (*connect.Response[v1.ListNodeTsaCertificatesResponse], error) + // GetNodeImageStatus reports what CryptOS image a managed node is running, + // what it will boot next, and what it could roll back to. Readable at + // viewer level and above; a read, so it is not audited. + GetNodeImageStatus(context.Context, *connect.Request[v1.GetNodeImageStatusRequest]) (*connect.Response[v1.GetNodeImageStatusResponse], error) + // StageNodeImage installs a new CryptOS image on a managed node's spare ESP + // slot without touching the one it is running from. The manager fetches + // image_url itself (the browser never carries the image), checks the + // detached release signature, and streams it to the node the same way + // `cryptosctl image stage` does. The node will not boot it until + // ActivateNodeImage runs. Admin-gated (an unreviewed image on a trust + // anchor) and audited; the node's own refusals (a bad signature, or + // FailedPrecondition when another upgrade is already running) are + // surfaced unchanged. + StageNodeImage(context.Context, *connect.Request[v1.StageNodeImageRequest]) (*connect.Response[v1.StageNodeImageResponse], error) + // ActivateNodeImage reboots a managed node so a staged image starts + // running. confirm_ca_cn must equal the node's current CA common name, the + // same confirmation RebootNode requires, because activating is itself a + // reboot. Admin-gated and audited. + ActivateNodeImage(context.Context, *connect.Request[v1.ActivateNodeImageRequest]) (*connect.Response[v1.ActivateNodeImageResponse], error) + // RollbackNodeImage puts a managed node's previously running image back on + // the boot path, for a node that was already activated onto a bad image. + // ActivateNodeImage (or a reboot) is still needed to actually boot it. + // Admin-gated and audited. + RollbackNodeImage(context.Context, *connect.Request[v1.RollbackNodeImageRequest]) (*connect.Response[v1.RollbackNodeImageResponse], error) // IssueLeaf signs a leaf certificate on the named issuing node from a // browser-generated PKCS#10 CSR under a named issuance profile. Only the // CSR crosses the wire; the leaf private key stays in the browser. @@ -1723,6 +1831,30 @@ func NewFleetServiceHandler(svc FleetServiceHandler, opts ...connect.HandlerOpti connect.WithSchema(fleetServiceMethods.ByName("ListNodeTsaCertificates")), connect.WithHandlerOptions(opts...), ) + fleetServiceGetNodeImageStatusHandler := connect.NewUnaryHandler( + FleetServiceGetNodeImageStatusProcedure, + svc.GetNodeImageStatus, + connect.WithSchema(fleetServiceMethods.ByName("GetNodeImageStatus")), + connect.WithHandlerOptions(opts...), + ) + fleetServiceStageNodeImageHandler := connect.NewUnaryHandler( + FleetServiceStageNodeImageProcedure, + svc.StageNodeImage, + connect.WithSchema(fleetServiceMethods.ByName("StageNodeImage")), + connect.WithHandlerOptions(opts...), + ) + fleetServiceActivateNodeImageHandler := connect.NewUnaryHandler( + FleetServiceActivateNodeImageProcedure, + svc.ActivateNodeImage, + connect.WithSchema(fleetServiceMethods.ByName("ActivateNodeImage")), + connect.WithHandlerOptions(opts...), + ) + fleetServiceRollbackNodeImageHandler := connect.NewUnaryHandler( + FleetServiceRollbackNodeImageProcedure, + svc.RollbackNodeImage, + connect.WithSchema(fleetServiceMethods.ByName("RollbackNodeImage")), + connect.WithHandlerOptions(opts...), + ) fleetServiceIssueLeafHandler := connect.NewUnaryHandler( FleetServiceIssueLeafProcedure, svc.IssueLeaf, @@ -1985,6 +2117,14 @@ func NewFleetServiceHandler(svc FleetServiceHandler, opts ...connect.HandlerOpti fleetServiceValidateCertificateChainHandler.ServeHTTP(w, r) case FleetServiceListNodeTsaCertificatesProcedure: fleetServiceListNodeTsaCertificatesHandler.ServeHTTP(w, r) + case FleetServiceGetNodeImageStatusProcedure: + fleetServiceGetNodeImageStatusHandler.ServeHTTP(w, r) + case FleetServiceStageNodeImageProcedure: + fleetServiceStageNodeImageHandler.ServeHTTP(w, r) + case FleetServiceActivateNodeImageProcedure: + fleetServiceActivateNodeImageHandler.ServeHTTP(w, r) + case FleetServiceRollbackNodeImageProcedure: + fleetServiceRollbackNodeImageHandler.ServeHTTP(w, r) case FleetServiceIssueLeafProcedure: fleetServiceIssueLeafHandler.ServeHTTP(w, r) case FleetServiceRekeyNodeProcedure: @@ -2164,6 +2304,22 @@ func (UnimplementedFleetServiceHandler) ListNodeTsaCertificates(context.Context, return nil, connect.NewError(connect.CodeUnimplemented, errors.New("cryptos.fleet.v1.FleetService.ListNodeTsaCertificates is not implemented")) } +func (UnimplementedFleetServiceHandler) GetNodeImageStatus(context.Context, *connect.Request[v1.GetNodeImageStatusRequest]) (*connect.Response[v1.GetNodeImageStatusResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("cryptos.fleet.v1.FleetService.GetNodeImageStatus is not implemented")) +} + +func (UnimplementedFleetServiceHandler) StageNodeImage(context.Context, *connect.Request[v1.StageNodeImageRequest]) (*connect.Response[v1.StageNodeImageResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("cryptos.fleet.v1.FleetService.StageNodeImage is not implemented")) +} + +func (UnimplementedFleetServiceHandler) ActivateNodeImage(context.Context, *connect.Request[v1.ActivateNodeImageRequest]) (*connect.Response[v1.ActivateNodeImageResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("cryptos.fleet.v1.FleetService.ActivateNodeImage is not implemented")) +} + +func (UnimplementedFleetServiceHandler) RollbackNodeImage(context.Context, *connect.Request[v1.RollbackNodeImageRequest]) (*connect.Response[v1.RollbackNodeImageResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("cryptos.fleet.v1.FleetService.RollbackNodeImage is not implemented")) +} + func (UnimplementedFleetServiceHandler) IssueLeaf(context.Context, *connect.Request[v1.IssueLeafRequest]) (*connect.Response[v1.IssueLeafResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("cryptos.fleet.v1.FleetService.IssueLeaf is not implemented")) } diff --git a/internal/fleet/enrollment_test.go b/internal/fleet/enrollment_test.go index 14a41b0..831581f 100644 --- a/internal/fleet/enrollment_test.go +++ b/internal/fleet/enrollment_test.go @@ -22,6 +22,7 @@ import ( "crypto/elliptic" "crypto/rand" "errors" + "io" "testing" connect "connectrpc.com/connect" @@ -662,6 +663,22 @@ func (r *routingConn) ListTsaCertificates(ctx context.Context) (*nodev1.ListTsaC return r.ferry.ListTsaCertificates(ctx) } +func (r *routingConn) GetImageStatus(ctx context.Context) (*nodev1.GetImageStatusResponse, error) { + return r.ferry.GetImageStatus(ctx) +} + +func (r *routingConn) StageImage(ctx context.Context, signature []byte, sizeBytes uint64, sha256Hex string, body io.Reader) (*nodev1.StageImageResponse, error) { + return r.ferry.StageImage(ctx, signature, sizeBytes, sha256Hex, body) +} + +func (r *routingConn) ActivateImage(ctx context.Context, confirmCN string) (*nodev1.ActivateImageResponse, error) { + return r.ferry.ActivateImage(ctx, confirmCN) +} + +func (r *routingConn) RollbackImage(ctx context.Context) (*nodev1.RollbackImageResponse, error) { + return r.ferry.RollbackImage(ctx) +} + func (r *routingConn) Close() error { _ = r.ferry.Close() return r.identity.Close() diff --git a/internal/fleet/nodeimage.go b/internal/fleet/nodeimage.go new file mode 100644 index 0000000..4ac32ac --- /dev/null +++ b/internal/fleet/nodeimage.go @@ -0,0 +1,289 @@ +package fleet + +/* +Copyright The CryptOS Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "time" + + connect "connectrpc.com/connect" + fleetv1 "github.com/CryptOS-PKI/cryptos-manager/gen/go/cryptos/fleet/v1" + "github.com/CryptOS-PKI/cryptos-manager/internal/auditlog" + "github.com/CryptOS-PKI/cryptos-manager/internal/operatorca" + "github.com/CryptOS-PKI/cryptos-manager/internal/store" + nodev1 "github.com/CryptOS-PKI/cryptos-node/gen/go/cryptos/node/v1" +) + +// MaxNodeImageBytes bounds a CryptOS image StageNodeImage will fetch and +// stream to a node: generous for a UKI, small enough that a misbehaving +// image_url can't exhaust the manager. +const MaxNodeImageBytes = 2 << 30 // 2 GiB + +// ImageFetchTimeout bounds the whole image_url fetch StageNodeImage makes +// before it starts streaming to the node. +const ImageFetchTimeout = 30 * time.Minute + +// WithImageFetch supplies the seam StageNodeImage uses to retrieve an image +// from a URL: the browser never carries the image itself. Returns s for +// chaining. +func (s *Service) WithImageFetch(fetch func(ctx context.Context, url string) (io.ReadCloser, int64, error)) *Service { + s.imageFetch = fetch + + return s +} + +// NewHTTPImageFetch builds the production image_url fetch seam: an http or +// https GET, no proxy from the environment, at most maxBytes, reporting the +// response's Content-Length as the size the node's StageImageBegin expects. +// A response with no Content-Length is refused, since the node needs the +// size up front to check the transfer will fit before it spends the upload. +func NewHTTPImageFetch(timeout time.Duration, maxBytes int64) func(ctx context.Context, url string) (io.ReadCloser, int64, error) { + client := &http.Client{Transport: &http.Transport{Proxy: nil}} + return func(ctx context.Context, rawURL string) (io.ReadCloser, int64, error) { + if err := operatorca.ValidateFetchURL(rawURL); err != nil { + return nil, 0, fmt.Errorf("refused: %w", err) + } + ctx, cancel := context.WithTimeout(ctx, timeout) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil) + if err != nil { + cancel() + return nil, 0, err + } + resp, err := client.Do(req) + if err != nil { + cancel() + return nil, 0, err + } + if resp.StatusCode != http.StatusOK { + _ = resp.Body.Close() + cancel() + return nil, 0, fmt.Errorf("HTTP %d", resp.StatusCode) + } + if resp.ContentLength <= 0 { + _ = resp.Body.Close() + cancel() + return nil, 0, errors.New("response did not report Content-Length") + } + if resp.ContentLength > maxBytes { + _ = resp.Body.Close() + cancel() + return nil, 0, fmt.Errorf("response is %d bytes, more than the %d byte limit", resp.ContentLength, maxBytes) + } + return &cancelOnCloseReader{ReadCloser: resp.Body, cancel: cancel}, resp.ContentLength, nil + } +} + +// cancelOnCloseReader cancels its context's timeout once the body is closed, +// so a fetch that completes well inside ImageFetchTimeout doesn't hold the +// timer open for the rest of it. +type cancelOnCloseReader struct { + io.ReadCloser + cancel context.CancelFunc +} + +func (r *cancelOnCloseReader) Close() error { + defer r.cancel() + return r.ReadCloser.Close() +} + +// GetNodeImageStatus reports what CryptOS image a managed node is running, +// what it will boot next, and what it could roll back to. Any level may +// read it; a read, so it is not audited. +func (s *Service) GetNodeImageStatus(ctx context.Context, req *connect.Request[fleetv1.GetNodeImageStatusRequest]) (*connect.Response[fleetv1.GetNodeImageStatusResponse], error) { + if _, err := operatorLevel(ctx); err != nil { + return nil, err + } + + node, err := s.resolveNode("GetNodeImageStatus", req.Msg.GetNodeId(), req.Msg.GetNodeName(), currentNames) + if err != nil { + return nil, err + } + + conn, err := s.dial(node) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("fleet: dial node: %w", err)) + } + defer func() { _ = conn.Close() }() + + resp, err := conn.GetImageStatus(ctx) + if err != nil { + return nil, nodeError("get image status", err) + } + + return connect.NewResponse(&fleetv1.GetNodeImageStatusResponse{ + Status: nodeImageStatusFromProto(resp.GetStatus()), + }), nil +} + +// StageNodeImage fetches image_url itself (the browser never carries the +// image) and streams it to a managed node's spare ESP slot, the same way +// `cryptosctl image stage` does. Admin-gated (an unreviewed image on a trust +// anchor) and audited; the node's own refusals (a bad signature, or +// FailedPrecondition when another upgrade is already running) are surfaced +// unchanged. +func (s *Service) StageNodeImage(ctx context.Context, req *connect.Request[fleetv1.StageNodeImageRequest]) (*connect.Response[fleetv1.StageNodeImageResponse], error) { + if err := requireAdmin(ctx); err != nil { + return nil, err + } + + node, err := s.resolveNode("StageNodeImage", req.Msg.GetNodeId(), req.Msg.GetNodeName(), currentNames) + if err != nil { + return nil, err + } + + imageURL := req.Msg.GetImageUrl() + if imageURL == "" { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("fleet: image_url is required")) + } + if len(req.Msg.GetSignature()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("fleet: signature is required")) + } + if s.imageFetch == nil { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("fleet: image staging not configured (no image fetch seam)")) + } + + body, size, err := s.imageFetch(ctx, imageURL) + if err != nil { + return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("fleet: fetch image_url: %w", err)) + } + defer func() { _ = body.Close() }() + + conn, err := s.dial(node) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("fleet: dial node: %w", err)) + } + defer func() { _ = conn.Close() }() + + resp, err := conn.StageImage(ctx, req.Msg.GetSignature(), uint64(size), req.Msg.GetSha256(), body) + if err != nil { + return nil, nodeError("stage image", err) + } + + auditlog.Record(ctx, s.store, store.AuditEvent{ + ID: newAuditID(), + At: time.Now().UTC().Format(time.RFC3339), + Kind: "node-image-staged", + Summary: fmt.Sprintf("Staged a new CryptOS image on %s", node.Name), + TargetKind: "node", + TargetPath: nodeTarget(node), + }) + + return connect.NewResponse(&fleetv1.StageNodeImageResponse{ + Status: nodeImageStatusFromProto(resp.GetStatus()), + RequiresReboot: resp.GetRequiresReboot(), + }), nil +} + +// ActivateNodeImage reboots a managed node so a staged image starts running. +// confirm_ca_cn must equal the node's current CA common name, the same +// confirmation RebootNode requires, because activating is itself a reboot. +// Admin-gated and audited. +func (s *Service) ActivateNodeImage(ctx context.Context, req *connect.Request[fleetv1.ActivateNodeImageRequest]) (*connect.Response[fleetv1.ActivateNodeImageResponse], error) { + if err := requireAdmin(ctx); err != nil { + return nil, err + } + + node, err := s.resolveNode("ActivateNodeImage", req.Msg.GetNodeId(), req.Msg.GetNodeName(), currentNames) + if err != nil { + return nil, err + } + + confirmCN := req.Msg.GetConfirmCaCn() + if confirmCN == "" { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("fleet: confirm_ca_cn is required")) + } + + conn, err := s.dial(node) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("fleet: dial node: %w", err)) + } + defer func() { _ = conn.Close() }() + + resp, err := conn.ActivateImage(ctx, confirmCN) + if err != nil { + return nil, nodeError("activate image", err) + } + + auditlog.Record(ctx, s.store, store.AuditEvent{ + ID: newAuditID(), + At: time.Now().UTC().Format(time.RFC3339), + Kind: "node-image-activated", + Summary: fmt.Sprintf("Activated the staged CryptOS image on %s", node.Name), + TargetKind: "node", + TargetPath: nodeTarget(node), + }) + + return connect.NewResponse(&fleetv1.ActivateNodeImageResponse{ + Rebooting: resp.GetRebooting(), + }), nil +} + +// RollbackNodeImage puts a managed node's previously running image back on +// the boot path. ActivateNodeImage (or a reboot) is still needed to actually +// boot it. Admin-gated and audited. +func (s *Service) RollbackNodeImage(ctx context.Context, req *connect.Request[fleetv1.RollbackNodeImageRequest]) (*connect.Response[fleetv1.RollbackNodeImageResponse], error) { + if err := requireAdmin(ctx); err != nil { + return nil, err + } + + node, err := s.resolveNode("RollbackNodeImage", req.Msg.GetNodeId(), req.Msg.GetNodeName(), currentNames) + if err != nil { + return nil, err + } + + conn, err := s.dial(node) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("fleet: dial node: %w", err)) + } + defer func() { _ = conn.Close() }() + + resp, err := conn.RollbackImage(ctx) + if err != nil { + return nil, nodeError("rollback image", err) + } + + auditlog.Record(ctx, s.store, store.AuditEvent{ + ID: newAuditID(), + At: time.Now().UTC().Format(time.RFC3339), + Kind: "node-image-rolled-back", + Summary: fmt.Sprintf("Rolled back the CryptOS image on %s", node.Name), + TargetKind: "node", + TargetPath: nodeTarget(node), + }) + + return connect.NewResponse(&fleetv1.RollbackNodeImageResponse{ + Status: nodeImageStatusFromProto(resp.GetStatus()), + RequiresReboot: resp.GetRequiresReboot(), + }), nil +} + +// nodeImageStatusFromProto flattens a node's ImageStatus into the fleet +// API's display shape; the node's fields are already plain strings and +// booleans, so this is a 1:1 copy that keeps the two protos independent. +func nodeImageStatusFromProto(s *nodev1.ImageStatus) *fleetv1.NodeImageStatus { + return &fleetv1.NodeImageStatus{ + RunningSha256: s.GetRunningSha256(), + ActiveSha256: s.GetActiveSha256(), + PreviousSha256: s.GetPreviousSha256(), + RebootPending: s.GetRebootPending(), + RunningVersion: s.GetRunningVersion(), + } +} diff --git a/internal/fleet/nodeimage_test.go b/internal/fleet/nodeimage_test.go new file mode 100644 index 0000000..4d1031f --- /dev/null +++ b/internal/fleet/nodeimage_test.go @@ -0,0 +1,315 @@ +package fleet + +/* +Copyright The CryptOS Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "context" + "io" + "strings" + "testing" + + connect "connectrpc.com/connect" + fleetv1 "github.com/CryptOS-PKI/cryptos-manager/gen/go/cryptos/fleet/v1" + "github.com/CryptOS-PKI/cryptos-manager/internal/apperr" + "github.com/CryptOS-PKI/cryptos-manager/internal/authz" + nodev1 "github.com/CryptOS-PKI/cryptos-node/gen/go/cryptos/node/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// fakeImageFetch returns body (and its length) for any URL, recording the +// last URL it was asked for. +func fakeImageFetch(body string, gotURL *string) func(context.Context, string) (io.ReadCloser, int64, error) { + return func(_ context.Context, url string) (io.ReadCloser, int64, error) { + if gotURL != nil { + *gotURL = url + } + return io.NopCloser(strings.NewReader(body)), int64(len(body)), nil + } +} + +func TestGetNodeImageStatus_Viewer_ReturnsStatus(t *testing.T) { + conn := &fakeConn{imageStatusResp: &nodev1.GetImageStatusResponse{ + Status: &nodev1.ImageStatus{ + RunningSha256: "aaaa", ActiveSha256: "aaaa", RunningVersion: "0.1.0", + }, + }} + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{"A": conn})) + + ctx := operatorCtx("viewer@acme.example", authz.LevelViewer) + resp, err := svc.GetNodeImageStatus(ctx, connect.NewRequest(&fleetv1.GetNodeImageStatusRequest{NodeName: "A"})) + if err != nil { + t.Fatalf("GetNodeImageStatus() error = %v, want nil", err) + } + st := resp.Msg.GetStatus() + if st.GetRunningSha256() != "aaaa" || st.GetRunningVersion() != "0.1.0" || st.GetRebootPending() { + t.Errorf("status = %+v, want the node's fields flattened through", st) + } +} + +func TestGetNodeImageStatus_Unauthenticated_Refused(t *testing.T) { + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{"A": {}})) + _, err := svc.GetNodeImageStatus(context.Background(), connect.NewRequest(&fleetv1.GetNodeImageStatusRequest{NodeName: "A"})) + requireConnectCode(t, err, connect.CodeUnauthenticated) +} + +func TestGetNodeImageStatus_UnknownNode_NotFound(t *testing.T) { + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{})) + ctx := operatorCtx("viewer@acme.example", authz.LevelViewer) + _, err := svc.GetNodeImageStatus(ctx, connect.NewRequest(&fleetv1.GetNodeImageStatusRequest{NodeName: "missing"})) + requireConnectCode(t, err, connect.CodeNotFound) +} + +func TestStageNodeImage_Admin_FetchesAndStreamsToNode_Audits(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{stageImageResp: &nodev1.StageImageResponse{ + Status: &nodev1.ImageStatus{ActiveSha256: "deadbeef"}, + RequiresReboot: true, + }} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + var gotURL string + svc = svc.WithImageFetch(fakeImageFetch("the image bytes", &gotURL)) + + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + resp, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", + ImageUrl: "https://example.org/images/cryptos.img", + Signature: []byte{1, 2, 3}, + Sha256: "abc123", + })) + if err != nil { + t.Fatalf("StageNodeImage(admin) error = %v, want nil", err) + } + if gotURL != "https://example.org/images/cryptos.img" { + t.Errorf("fetched URL = %q, want the request's image_url", gotURL) + } + if string(conn.gotStageBytes) != "the image bytes" { + t.Errorf("node received %q, want the fetched body", conn.gotStageBytes) + } + if conn.gotStageSize != uint64(len("the image bytes")) { + t.Errorf("node StageImage size = %d, want %d", conn.gotStageSize, len("the image bytes")) + } + if string(conn.gotStageSignature) != "\x01\x02\x03" || conn.gotStageSha256 != "abc123" { + t.Errorf("node StageImage signature/sha256 = %v/%q, want the request's", conn.gotStageSignature, conn.gotStageSha256) + } + if !resp.Msg.GetRequiresReboot() || resp.Msg.GetStatus().GetActiveSha256() != "deadbeef" { + t.Errorf("response = %+v, want the node's reply flattened through", resp.Msg) + } + + audit := st.Audit() + if len(audit) != 1 || audit[0].Kind != "node-image-staged" { + t.Fatalf("audit = %+v, want one node-image-staged event", audit) + } + if !strings.Contains(audit[0].Summary, "A") { + t.Errorf("audit summary %q does not name the node", audit[0].Summary) + } +} + +func TestStageNodeImage_ViewerDenied_NoFetchNoDialNoAudit(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + fetchCalled := false + svc = svc.WithImageFetch(func(context.Context, string) (io.ReadCloser, int64, error) { + fetchCalled = true + return io.NopCloser(strings.NewReader("")), 0, nil + }) + + ctx := operatorCtx("operator@acme.example", authz.LevelOperator) + _, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", ImageUrl: "https://example.org/img", Signature: []byte{1}, + })) + requireConnectCode(t, err, connect.CodePermissionDenied) + if fetchCalled || conn.closed { + t.Error("image was fetched or node was dialed on a denied request") + } + if len(st.Audit()) != 0 { + t.Error("denied request wrote an audit event") + } +} + +func TestStageNodeImage_MissingImageURL_InvalidArgument(t *testing.T) { + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{"A": {}})).WithImageFetch(fakeImageFetch("x", nil)) + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", Signature: []byte{1}, + })) + requireConnectCode(t, err, connect.CodeInvalidArgument) +} + +func TestStageNodeImage_MissingSignature_InvalidArgument(t *testing.T) { + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{"A": {}})).WithImageFetch(fakeImageFetch("x", nil)) + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", ImageUrl: "https://example.org/img", + })) + requireConnectCode(t, err, connect.CodeInvalidArgument) +} + +func TestStageNodeImage_NoFetchSeam_Unimplemented(t *testing.T) { + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{"A": {}})) + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", ImageUrl: "https://example.org/img", Signature: []byte{1}, + })) + requireConnectCode(t, err, connect.CodeUnimplemented) +} + +func TestStageNodeImage_NodeRefusesConcurrentUpgrade_FailedPrecondition_NoAudit(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{stageImageErr: status.Error(codes.FailedPrecondition, "cryptos: an image transfer is already in progress")} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})).WithImageFetch(fakeImageFetch("x", nil)) + + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", ImageUrl: "https://example.org/img", Signature: []byte{1}, + })) + requireConnectCode(t, err, connect.CodeFailedPrecondition) + requireAppCode(t, err, apperr.CodeNodeRefused) + requireNodeReason(t, err, "cryptos: an image transfer is already in progress") + if len(st.Audit()) != 0 { + t.Error("a node refusal wrote an audit event") + } +} + +func TestStageNodeImage_NodeRefusesBadSignature_NoAudit(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{stageImageErr: status.Error(codes.InvalidArgument, "cryptos: image signature did not verify")} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})).WithImageFetch(fakeImageFetch("x", nil)) + + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.StageNodeImage(ctx, connect.NewRequest(&fleetv1.StageNodeImageRequest{ + NodeName: "A", ImageUrl: "https://example.org/img", Signature: []byte{1}, + })) + requireConnectCode(t, err, connect.CodeInvalidArgument) + requireNodeReason(t, err, "cryptos: image signature did not verify") + if len(st.Audit()) != 0 { + t.Error("a node refusal wrote an audit event") + } +} + +func TestActivateNodeImage_Admin_ActivatesAndAudits(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{activateImageResp: &nodev1.ActivateImageResponse{Rebooting: true}} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + resp, err := svc.ActivateNodeImage(ctx, connect.NewRequest(&fleetv1.ActivateNodeImageRequest{ + NodeName: "A", ConfirmCaCn: "Root CA A", + })) + if err != nil { + t.Fatalf("ActivateNodeImage(admin) error = %v", err) + } + if conn.gotActivateCN != "Root CA A" { + t.Errorf("node ActivateImage CN = %q, want Root CA A", conn.gotActivateCN) + } + if !resp.Msg.GetRebooting() { + t.Error("response Rebooting = false, want true") + } + audit := st.Audit() + if len(audit) != 1 || audit[0].Kind != "node-image-activated" { + t.Fatalf("audit = %+v, want one node-image-activated event", audit) + } +} + +func TestActivateNodeImage_MissingConfirmCN_InvalidArgument(t *testing.T) { + svc := New(certsTestStore(), dialFor(map[string]*fakeConn{"A": {}})) + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.ActivateNodeImage(ctx, connect.NewRequest(&fleetv1.ActivateNodeImageRequest{NodeName: "A"})) + requireConnectCode(t, err, connect.CodeInvalidArgument) +} + +func TestActivateNodeImage_OperatorDenied_NoAudit(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + ctx := operatorCtx("operator@acme.example", authz.LevelOperator) + _, err := svc.ActivateNodeImage(ctx, connect.NewRequest(&fleetv1.ActivateNodeImageRequest{ + NodeName: "A", ConfirmCaCn: "Root CA A", + })) + requireConnectCode(t, err, connect.CodePermissionDenied) + if conn.gotActivateCN != "" || conn.closed { + t.Error("node was dialed/activated on a denied request") + } + if len(st.Audit()) != 0 { + t.Error("denied request wrote an audit event") + } +} + +func TestActivateNodeImage_CNMismatch_MappedToNodeRefused(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{activateImageErr: status.Error(codes.PermissionDenied, "cryptos: confirmation CN does not match the CA CN")} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.ActivateNodeImage(ctx, connect.NewRequest(&fleetv1.ActivateNodeImageRequest{ + NodeName: "A", ConfirmCaCn: "wrong", + })) + requireConnectCode(t, err, connect.CodePermissionDenied) + requireAppCode(t, err, apperr.CodeNodeRefused) + if len(st.Audit()) != 0 { + t.Error("a CN mismatch wrote an audit event") + } +} + +func TestRollbackNodeImage_Admin_RollsBackAndAudits(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{rollbackImageResp: &nodev1.RollbackImageResponse{ + Status: &nodev1.ImageStatus{ActiveSha256: "old"}, + RequiresReboot: true, + }} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + resp, err := svc.RollbackNodeImage(ctx, connect.NewRequest(&fleetv1.RollbackNodeImageRequest{NodeName: "A"})) + if err != nil { + t.Fatalf("RollbackNodeImage(admin) error = %v", err) + } + if resp.Msg.GetStatus().GetActiveSha256() != "old" || !resp.Msg.GetRequiresReboot() { + t.Errorf("response = %+v, want the node's reply flattened through", resp.Msg) + } + audit := st.Audit() + if len(audit) != 1 || audit[0].Kind != "node-image-rolled-back" { + t.Fatalf("audit = %+v, want one node-image-rolled-back event", audit) + } +} + +func TestRollbackNodeImage_ViewerDenied_NoAudit(t *testing.T) { + st := certsTestStore() + conn := &fakeConn{} + svc := New(st, dialFor(map[string]*fakeConn{"A": conn})) + ctx := operatorCtx("viewer@acme.example", authz.LevelViewer) + _, err := svc.RollbackNodeImage(ctx, connect.NewRequest(&fleetv1.RollbackNodeImageRequest{NodeName: "A"})) + requireConnectCode(t, err, connect.CodePermissionDenied) + if conn.closed { + t.Error("node was dialed on a denied request") + } + if len(st.Audit()) != 0 { + t.Error("denied request wrote an audit event") + } +} + +func TestRollbackNodeImage_UnknownNode_NotFound_NoAudit(t *testing.T) { + st := certsTestStore() + svc := New(st, dialFor(map[string]*fakeConn{})) + ctx := operatorCtx("admin@acme.example", authz.LevelAdmin) + _, err := svc.RollbackNodeImage(ctx, connect.NewRequest(&fleetv1.RollbackNodeImageRequest{NodeName: "missing"})) + requireConnectCode(t, err, connect.CodeNotFound) + if len(st.Audit()) != 0 { + t.Error("unknown node wrote an audit event") + } +} diff --git a/internal/fleet/nodes_test.go b/internal/fleet/nodes_test.go index 7d96f59..a4177cb 100644 --- a/internal/fleet/nodes_test.go +++ b/internal/fleet/nodes_test.go @@ -27,6 +27,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "errors" + "io" "math/big" "testing" "time" @@ -198,6 +199,43 @@ type fakeConn struct { // listTsaCertificatesErr, when set, is returned by ListTsaCertificates // instead of err. listTsaCertificatesErr error + + // imageStatusResp, when set, is returned by GetImageStatus instead of the + // zero-value response. + imageStatusResp *nodev1.GetImageStatusResponse + // imageStatusErr, when set, is returned by GetImageStatus instead of err. + imageStatusErr error + + // gotStageSignature, gotStageSize, gotStageSha256 and gotStageBytes + // record what StageImage was called with (gotStageBytes is the fully + // drained reader), so a test can assert the handler forwarded the fetched + // image to the node unchanged. + gotStageSignature []byte + gotStageSize uint64 + gotStageSha256 string + gotStageBytes []byte + // stageImageResp, when set, is returned by StageImage instead of the + // zero-value response. + stageImageResp *nodev1.StageImageResponse + // stageImageErr, when set, is returned by StageImage instead of err. + stageImageErr error + + // gotActivateCN records the confirmation CN ActivateImage was called + // with. + gotActivateCN string + // activateImageResp, when set, is returned by ActivateImage instead of + // the zero-value response. + activateImageResp *nodev1.ActivateImageResponse + // activateImageErr, when set, is returned by ActivateImage instead of + // err. + activateImageErr error + + // rollbackImageResp, when set, is returned by RollbackImage instead of + // the zero-value response. + rollbackImageResp *nodev1.RollbackImageResponse + // rollbackImageErr, when set, is returned by RollbackImage instead of + // err. + rollbackImageErr error } func (f *fakeConn) BeginKeyRotation(context.Context) (*nodev1.BeginKeyRotationResponse, error) { @@ -511,6 +549,59 @@ func (f *fakeConn) ListTsaCertificates(context.Context) (*nodev1.ListTsaCertific return &nodev1.ListTsaCertificatesResponse{}, nil } +func (f *fakeConn) GetImageStatus(context.Context) (*nodev1.GetImageStatusResponse, error) { + f.record("GetImageStatus") + if f.imageStatusErr != nil { + return nil, f.imageStatusErr + } + if f.imageStatusResp != nil { + return f.imageStatusResp, nil + } + return &nodev1.GetImageStatusResponse{}, nil +} + +func (f *fakeConn) StageImage(_ context.Context, signature []byte, sizeBytes uint64, sha256Hex string, r io.Reader) (*nodev1.StageImageResponse, error) { + f.record("StageImage") + f.gotStageSignature = signature + f.gotStageSize = sizeBytes + f.gotStageSha256 = sha256Hex + b, err := io.ReadAll(r) + if err != nil { + return nil, err + } + f.gotStageBytes = b + if f.stageImageErr != nil { + return nil, f.stageImageErr + } + if f.stageImageResp != nil { + return f.stageImageResp, nil + } + return &nodev1.StageImageResponse{}, nil +} + +func (f *fakeConn) ActivateImage(_ context.Context, confirmCN string) (*nodev1.ActivateImageResponse, error) { + f.record("ActivateImage") + f.gotActivateCN = confirmCN + if f.activateImageErr != nil { + return nil, f.activateImageErr + } + if f.activateImageResp != nil { + return f.activateImageResp, nil + } + return &nodev1.ActivateImageResponse{}, nil +} + +func (f *fakeConn) RollbackImage(context.Context) (*nodev1.RollbackImageResponse, error) { + f.record("RollbackImage") + if f.rollbackImageErr != nil { + return nil, f.rollbackImageErr + } + if f.rollbackImageResp != nil { + return f.rollbackImageResp, nil + } + return &nodev1.RollbackImageResponse{}, nil +} + // record appends name to the shared call log, if this fake was given one. // Used by the SUBORDINATE ferry tests to assert child/parent call order. func (f *fakeConn) record(name string) { diff --git a/internal/fleet/service.go b/internal/fleet/service.go index 8aacb5c..e71d011 100644 --- a/internal/fleet/service.go +++ b/internal/fleet/service.go @@ -23,6 +23,7 @@ limitations under the License. import ( "context" "crypto/x509" + "io" log "github.com/Bugs5382/go-log" fleetv1connect "github.com/CryptOS-PKI/cryptos-manager/gen/go/cryptos/fleet/v1/fleetv1connect" @@ -63,6 +64,10 @@ type NodeConn interface { VerifyAuditChain(ctx context.Context) (*nodev1.VerifyAuditChainResponse, error) ListTsaCertificates(ctx context.Context) (*nodev1.ListTsaCertificatesResponse, error) StartCeremony(ctx context.Context, kind nodev1.CeremonyKind, machineConfigYAML []byte) (nodeclient.CeremonyStream, error) + GetImageStatus(ctx context.Context) (*nodev1.GetImageStatusResponse, error) + StageImage(ctx context.Context, signature []byte, sizeBytes uint64, sha256Hex string, r io.Reader) (*nodev1.StageImageResponse, error) + ActivateImage(ctx context.Context, confirmCN string) (*nodev1.ActivateImageResponse, error) + RollbackImage(ctx context.Context) (*nodev1.RollbackImageResponse, error) Close() error } @@ -115,6 +120,11 @@ type Service struct { // nodeCAWatch sees every CA chain a node reports. nodeCAWatch *operatorca.NodeCAWatch + // imageFetch retrieves a CryptOS image from a URL for StageNodeImage, so + // the browser never carries the image. Tests inject a fake; production + // wires an operatorca.Fetcher sized for an image rather than a CRL. + imageFetch func(ctx context.Context, url string) (io.ReadCloser, int64, error) + log log.Logger } diff --git a/internal/mcpserver/catalog.go b/internal/mcpserver/catalog.go index b8a631c..3449162 100644 --- a/internal/mcpserver/catalog.go +++ b/internal/mcpserver/catalog.go @@ -125,6 +125,10 @@ var Catalog = []Spec{ {Name: "node_audit_verify_chain", RPC: "VerifyNodeAuditChain", Policy: Excluded, Reason: "not yet exposed to agents"}, {Name: "certificate_chain_validate", RPC: "ValidateCertificateChain", Policy: Excluded, Reason: "not yet exposed to agents"}, {Name: "node_tsa_list", RPC: "ListNodeTsaCertificates", Policy: Excluded, Reason: "not yet exposed to agents"}, + {Name: "node_image_status", RPC: "GetNodeImageStatus", Policy: Excluded, Reason: "not yet exposed to agents"}, + {Name: "node_image_stage", RPC: "StageNodeImage", Policy: Excluded, Reason: "stages an unreviewed OS image on a node"}, + {Name: "node_image_activate", RPC: "ActivateNodeImage", Policy: Excluded, Reason: "an outage of everything the node signs for"}, + {Name: "node_image_rollback", RPC: "RollbackNodeImage", Policy: Excluded, Reason: "changes what image a node boots next"}, } func spec(name string) Spec { diff --git a/internal/nodeclient/nodeclient.go b/internal/nodeclient/nodeclient.go index 6a24f96..e01fb58 100644 --- a/internal/nodeclient/nodeclient.go +++ b/internal/nodeclient/nodeclient.go @@ -25,6 +25,7 @@ import ( "crypto/tls" "encoding/hex" "fmt" + "io" "strings" "unicode" @@ -430,6 +431,72 @@ func (c *Client) ListTsaCertificates(ctx context.Context) (*nodev1.ListTsaCertif return c.node.ListTsaCertificates(ctx, &nodev1.ListTsaCertificatesRequest{}) } +// GetImageStatus reports what CryptOS image the dialed node is running, what +// it will boot next, and what it could roll back to. +func (c *Client) GetImageStatus(ctx context.Context) (*nodev1.GetImageStatusResponse, error) { + return c.node.GetImageStatus(ctx, &nodev1.GetImageStatusRequest{}) +} + +// StageImage streams an image from r to the dialed node, preceded by the +// begin header the node verifies the transfer against. r is read to the end +// and sent in fixed-size chunks; the node refuses the transfer +// (FailedPrecondition) when another upgrade is already in progress, and +// refuses the assembled image (its own signature/size/digest checks) once +// the last chunk arrives. +func (c *Client) StageImage(ctx context.Context, signature []byte, sizeBytes uint64, sha256Hex string, r io.Reader) (*nodev1.StageImageResponse, error) { + stream, err := c.node.StageImage(ctx) + if err != nil { + return nil, err + } + if err := stream.Send(&nodev1.StageImageRequest{ + Payload: &nodev1.StageImageRequest_Begin{Begin: &nodev1.StageImageBegin{ + Signature: signature, + SizeBytes: sizeBytes, + Sha256: sha256Hex, + }}, + }); err != nil { + return nil, err + } + + buf := make([]byte, stageImageChunkSize) + for { + n, readErr := r.Read(buf) + if n > 0 { + chunk := make([]byte, n) + copy(chunk, buf[:n]) + if sendErr := stream.Send(&nodev1.StageImageRequest{ + Payload: &nodev1.StageImageRequest_Chunk{Chunk: chunk}, + }); sendErr != nil { + return nil, sendErr + } + } + if readErr == io.EOF { + break + } + if readErr != nil { + return nil, fmt.Errorf("nodeclient: read image: %w", readErr) + } + } + return stream.CloseAndRecv() +} + +// stageImageChunkSize is the size of each StageImageRequest chunk sent to the +// node. +const stageImageChunkSize = 1 << 20 + +// ActivateImage reboots the dialed node so a staged image starts running. +// confirmCN must equal the node's current CA CN or the node refuses +// (PermissionDenied), the same confirmation Reboot requires. +func (c *Client) ActivateImage(ctx context.Context, confirmCN string) (*nodev1.ActivateImageResponse, error) { + return c.node.ActivateImage(ctx, &nodev1.ActivateImageRequest{ConfirmCaCn: confirmCN}) +} + +// RollbackImage puts the dialed node's retained previous image back on the +// boot path. +func (c *Client) RollbackImage(ctx context.Context) (*nodev1.RollbackImageResponse, error) { + return c.node.RollbackImage(ctx, &nodev1.RollbackImageRequest{}) +} + // Close releases the underlying gRPC connection. func (c *Client) Close() error { return c.conn.Close() diff --git a/internal/nodeclient/nodeclient_test.go b/internal/nodeclient/nodeclient_test.go index 67bde67..ae30bfd 100644 --- a/internal/nodeclient/nodeclient_test.go +++ b/internal/nodeclient/nodeclient_test.go @@ -26,17 +26,22 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "fmt" + "io" "math/big" "net" "os" "path/filepath" + "strings" "testing" "time" "github.com/CryptOS-PKI/cryptos-manager/internal/store" nodev1 "github.com/CryptOS-PKI/cryptos-node/gen/go/cryptos/node/v1" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/status" ) // fakeNodeService is a minimal NodeService that answers GetStatus and @@ -109,6 +114,55 @@ func (fakeNodeService) ImportCAKey(_ context.Context, req *nodev1.ImportCAKeyReq }, nil } +func (fakeNodeService) GetImageStatus(context.Context, *nodev1.GetImageStatusRequest) (*nodev1.GetImageStatusResponse, error) { + return &nodev1.GetImageStatusResponse{ + Status: &nodev1.ImageStatus{RunningSha256: "fake-image-test-marker"}, + }, nil +} + +// StageImage reads the begin header and every chunk, and echoes the +// reassembled image's length and the begin header's fields back so the test +// can assert the Client split and reassembled it correctly across the wire. +func (fakeNodeService) StageImage(stream nodev1.NodeService_StageImageServer) error { + var ( + begin *nodev1.StageImageBegin + image []byte + ) + for { + req, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + switch p := req.GetPayload().(type) { + case *nodev1.StageImageRequest_Begin: + begin = p.Begin + case *nodev1.StageImageRequest_Chunk: + image = append(image, p.Chunk...) + } + } + return stream.SendAndClose(&nodev1.StageImageResponse{ + Status: &nodev1.ImageStatus{ + ActiveSha256: fmt.Sprintf("len=%d sig=%s sha256=%s", len(image), begin.GetSignature(), begin.GetSha256()), + RunningVersion: string(image), + }, + RequiresReboot: true, + }) +} + +func (fakeNodeService) ActivateImage(_ context.Context, req *nodev1.ActivateImageRequest) (*nodev1.ActivateImageResponse, error) { + if req.GetConfirmCaCn() != "fake-node" { + return nil, status.Error(codes.PermissionDenied, "confirmation CN does not match the CA CN") + } + return &nodev1.ActivateImageResponse{Rebooting: true}, nil +} + +func (fakeNodeService) RollbackImage(context.Context, *nodev1.RollbackImageRequest) (*nodev1.RollbackImageResponse, error) { + return &nodev1.RollbackImageResponse{Status: &nodev1.ImageStatus{ActiveSha256: "rolled-back-test-marker"}}, nil +} + // testCA is a minimal self-signed CA used to mint both the fake node's // server cert and the test admin client cert. type testCA struct { @@ -336,6 +390,86 @@ func TestDial_GetStatus_GetIdentity(t *testing.T) { if got := importResp.GetIdentity().GetChainPem(); got != "imported:env-bytes:relayed-passphrase" { t.Errorf("ImportCAKey().Identity.ChainPem = %q, want imported:env-bytes:relayed-passphrase (envelope/passphrase not relayed)", got) } + + imageStatusResp, err := client.GetImageStatus(ctx) + if err != nil { + t.Fatalf("GetImageStatus() error = %v, want nil", err) + } + if got := imageStatusResp.GetStatus().GetRunningSha256(); got != "fake-image-test-marker" { + t.Errorf("GetImageStatus().Status.RunningSha256 = %q, want fake-image-test-marker", got) + } + + rollbackResp, err := client.RollbackImage(ctx) + if err != nil { + t.Fatalf("RollbackImage() error = %v, want nil", err) + } + if got := rollbackResp.GetStatus().GetActiveSha256(); got != "rolled-back-test-marker" { + t.Errorf("RollbackImage().Status.ActiveSha256 = %q, want rolled-back-test-marker", got) + } + + activateResp, err := client.ActivateImage(ctx, "fake-node") + if err != nil { + t.Fatalf("ActivateImage() error = %v, want nil", err) + } + if !activateResp.GetRebooting() { + t.Error("ActivateImage().Rebooting = false, want true") + } + if _, err := client.ActivateImage(ctx, "wrong-cn"); status.Code(err) != codes.PermissionDenied { + t.Errorf("ActivateImage(wrong CN) code = %v, want PermissionDenied", status.Code(err)) + } +} + +// TestClient_StageImage_ChunksAndReassembles proves StageImage splits an +// image larger than one chunk into multiple StageImageRequest_Chunk +// messages and that the fake node's reassembly matches byte for byte, so +// chunking never reorders or drops bytes. +func TestClient_StageImage_ChunksAndReassembles(t *testing.T) { + serverCA := newTestCA(t, "fake-node-server-ca") + clientCA := newTestCA(t, "fake-node-client-ca") + + addr, stop := startFakeNode(t, serverCA, clientCA) + defer stop() + + adminPair := clientCA.issueLeaf(t, "manager-admin", []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}) + dir := t.TempDir() + certPath, keyPath := writePEMFiles(t, dir, adminPair) + + node := store.Node{ + Name: "fake-node", + Endpoint: addr, + Role: "root", + AdminCert: certPath, + AdminKey: keyPath, + CACert: writeCAChainPEM(t, dir, serverCA), + } + + client, err := Dial(node) + if err != nil { + t.Fatalf("Dial() error = %v, want nil", err) + } + defer func() { _ = client.Close() }() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Bigger than stageImageChunkSize (1 MiB) so the Client must send more + // than one chunk. + image := strings.Repeat("a", stageImageChunkSize+12345) + + resp, err := client.StageImage(ctx, []byte("sig-bytes"), uint64(len(image)), "deadbeef", strings.NewReader(image)) + if err != nil { + t.Fatalf("StageImage() error = %v, want nil", err) + } + if got := resp.GetStatus().GetRunningVersion(); got != image { + t.Errorf("fake node reassembled %d bytes, want the original %d bytes back byte for byte", len(got), len(image)) + } + wantMarker := fmt.Sprintf("len=%d sig=sig-bytes sha256=deadbeef", len(image)) + if got := resp.GetStatus().GetActiveSha256(); got != wantMarker { + t.Errorf("fake node begin header = %q, want %q", got, wantMarker) + } + if !resp.GetRequiresReboot() { + t.Error("StageImage().RequiresReboot = false, want true") + } } func TestDial_BadCertPath(t *testing.T) { diff --git a/proto/cryptos/fleet/v1/fleet.proto b/proto/cryptos/fleet/v1/fleet.proto index 289eb17..00689af 100644 --- a/proto/cryptos/fleet/v1/fleet.proto +++ b/proto/cryptos/fleet/v1/fleet.proto @@ -155,6 +155,34 @@ service FleetService { // read, so it is not audited. rpc ListNodeTsaCertificates(ListNodeTsaCertificatesRequest) returns (ListNodeTsaCertificatesResponse); + // GetNodeImageStatus reports what CryptOS image a managed node is running, + // what it will boot next, and what it could roll back to. Readable at + // viewer level and above; a read, so it is not audited. + rpc GetNodeImageStatus(GetNodeImageStatusRequest) returns (GetNodeImageStatusResponse); + + // StageNodeImage installs a new CryptOS image on a managed node's spare ESP + // slot without touching the one it is running from. The manager fetches + // image_url itself (the browser never carries the image), checks the + // detached release signature, and streams it to the node the same way + // `cryptosctl image stage` does. The node will not boot it until + // ActivateNodeImage runs. Admin-gated (an unreviewed image on a trust + // anchor) and audited; the node's own refusals (a bad signature, or + // FailedPrecondition when another upgrade is already running) are + // surfaced unchanged. + rpc StageNodeImage(StageNodeImageRequest) returns (StageNodeImageResponse); + + // ActivateNodeImage reboots a managed node so a staged image starts + // running. confirm_ca_cn must equal the node's current CA common name, the + // same confirmation RebootNode requires, because activating is itself a + // reboot. Admin-gated and audited. + rpc ActivateNodeImage(ActivateNodeImageRequest) returns (ActivateNodeImageResponse); + + // RollbackNodeImage puts a managed node's previously running image back on + // the boot path, for a node that was already activated onto a bad image. + // ActivateNodeImage (or a reboot) is still needed to actually boot it. + // Admin-gated and audited. + rpc RollbackNodeImage(RollbackNodeImageRequest) returns (RollbackNodeImageResponse); + // IssueLeaf signs a leaf certificate on the named issuing node from a // browser-generated PKCS#10 CSR under a named issuance profile. Only the // CSR crosses the wire; the leaf private key stays in the browser. @@ -1708,3 +1736,94 @@ message VerifyNodeAuditChainResponse { // intact. string reason = 4; } + +// GetNodeImageStatusRequest names the node whose CryptOS image status to +// read. +message GetNodeImageStatusRequest { + // node_name is the managed node to read. + // Deprecated: use node_id. Still resolves the node's current name for one + // release. + string node_name = 1; + // node_id is the stable ID (NodeSummary.id) of the node. Preferred over + // node_name; when both are set they must name the same node, or the + // manager returns InvalidArgument. + string node_id = 2; +} + +// NodeImageStatus describes the images on a managed node's ESP and the one +// currently running. +message NodeImageStatus { + // running_sha256 is the digest of the image the node booted, hex encoded. + string running_sha256 = 1; + // active_sha256 is the digest of the image the firmware will boot next. It + // differs from running_sha256 exactly when a staged image is waiting for a + // reboot. + string active_sha256 = 2; + // previous_sha256 is the retained image RollbackNodeImage would restore, + // hex encoded, empty on a node that has never been upgraded. + string previous_sha256 = 3; + // reboot_pending is true when active_sha256 differs from running_sha256. + bool reboot_pending = 4; + // running_version is the CryptOS version string baked into the running + // image. + string running_version = 5; +} + +message GetNodeImageStatusResponse { + NodeImageStatus status = 1; +} + +// StageNodeImageRequest carries where to fetch the image from and the +// detached release signature over it; the manager fetches image_url itself. +message StageNodeImageRequest { + // node_name is the managed node to stage onto. + // Deprecated: use node_id. Still resolves the node's current name for one + // release. + string node_name = 1; + // node_id is the stable ID (NodeSummary.id) of the node. Preferred over + // node_name; when both are set they must name the same node, or the + // manager returns InvalidArgument. + string node_id = 2; + // image_url is an http or https URL the manager fetches the image from. + // Required. + string image_url = 3; + // signature is the detached release signature over the whole image: PKCS#1 + // v1.5 over a SHA-256 digest, made by the CryptOS release key. Required; + // the node refuses a transfer it cannot verify. + bytes signature = 4; + // sha256 is the expected digest of the image, hex encoded. Optional; when + // set the node checks it against what it received. + string sha256 = 5; +} + +message StageNodeImageResponse { + NodeImageStatus status = 1; + // requires_reboot is always true on success: the staged image is what the + // firmware will boot, but the node is still running the old one. + bool requires_reboot = 2; +} + +// ActivateNodeImageRequest confirms an operator-initiated reboot onto a +// staged image. +message ActivateNodeImageRequest { + string node_name = 1; + string node_id = 2; + // confirm_ca_cn must equal the node's current CA common name. + string confirm_ca_cn = 3; +} + +message ActivateNodeImageResponse { + // The node reboots shortly after replying; the reply exists so the caller + // learns the reboot was accepted before the connection drops. + bool rebooting = 1; +} + +message RollbackNodeImageRequest { + string node_name = 1; + string node_id = 2; +} + +message RollbackNodeImageResponse { + NodeImageStatus status = 1; + bool requires_reboot = 2; +}