From 6e5b2e315bd9530a6f4334875a31d49ccb446a90 Mon Sep 17 00:00:00 2001 From: Mateusz Szostok Date: Thu, 15 Feb 2024 09:53:03 +0100 Subject: [PATCH] Update executor contract, publish local dev server --- CONTRIBUTING.md | 2 +- hack/target/serve-plugins/main.go | 45 +++ pkg/api/executor/executor.pb.go | 360 +++++++++++++-------- pkg/api/executor/grpc_adapter.go | 31 +- pkg/api/message.go | 3 + pkg/api/source/grpc_adapter.go | 2 +- pkg/bot/slack_socket.go | 6 + pkg/execute/factory.go | 1 + pkg/execute/plugin_executor.go | 4 + {test/fake => pkg/plugin}/plugin_server.go | 26 +- proto/executor.proto | 8 +- test/e2e/bots_test.go | 6 +- test/helpers/plugin_server.go | 42 --- 13 files changed, 330 insertions(+), 206 deletions(-) create mode 100644 hack/target/serve-plugins/main.go rename {test/fake => pkg/plugin}/plugin_server.go (66%) delete mode 100644 test/helpers/plugin_server.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50b70fa5a..4397097de 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -162,7 +162,7 @@ For faster development, you can also build and run Botkube outside K8s cluster. 1. Start fake plugins server to serve binaries from [`dist`](dist) folder: ```bash - go run test/helpers/plugin_server.go + go run hack/target/serve-plugins/main.go ``` > **Note** diff --git a/hack/target/serve-plugins/main.go b/hack/target/serve-plugins/main.go new file mode 100644 index 000000000..126ec3d3a --- /dev/null +++ b/hack/target/serve-plugins/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "flag" + "log" + "os" + "path/filepath" + "strconv" + + "github.com/kubeshop/botkube/pkg/loggerx" + "github.com/kubeshop/botkube/pkg/pluginx" +) + +func main() { + pluginsDir := flag.String("plugins-dir", getEnv("PLUGINS_DIR", "plugin-dist"), "Plugins directory") + host := flag.String("host", getEnv("PLUGIN_SERVER_HOST", "http://localhost"), "Local server host") + port := flag.String("port", getEnv("PLUGIN_SERVER_PORT", "3010"), "Local server port") + flag.Parse() + + dir, err := os.Getwd() + loggerx.ExitOnError(err, "while getting current directory") + + portInt, err := strconv.Atoi(*port) + loggerx.ExitOnError(err, "while casting server port value") + + binDir := filepath.Join(dir, *pluginsDir) + indexEndpoint, startServerFn := pluginx.NewStaticPluginServer(pluginx.StaticPluginServerConfig{ + BinariesDirectory: binDir, + Host: *host, + Port: portInt, + }) + + log.Printf("Service plugin binaries from %s\n", binDir) + log.Printf("Botkube repository index URL: %s", indexEndpoint) + err = startServerFn() + loggerx.ExitOnError(err, "while starting server") +} + +func getEnv(key, defaultValue string) string { + value, exists := os.LookupEnv(key) + if !exists { + return defaultValue + } + return value +} diff --git a/pkg/api/executor/executor.pb.go b/pkg/api/executor/executor.pb.go index 1f3d3ce78..585555d24 100644 --- a/pkg/api/executor/executor.pb.go +++ b/pkg/api/executor/executor.pb.go @@ -140,10 +140,11 @@ type ExecuteContext struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IsInteractivitySupported bool `protobuf:"varint,1,opt,name=isInteractivitySupported,proto3" json:"isInteractivitySupported,omitempty"` - SlackState []byte `protobuf:"bytes,2,opt,name=slackState,proto3" json:"slackState,omitempty"` - KubeConfig []byte `protobuf:"bytes,3,opt,name=kubeConfig,proto3" json:"kubeConfig,omitempty"` - Message *MessageContext `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` + IsInteractivitySupported bool `protobuf:"varint,1,opt,name=isInteractivitySupported,proto3" json:"isInteractivitySupported,omitempty"` + SlackState []byte `protobuf:"bytes,2,opt,name=slackState,proto3" json:"slackState,omitempty"` + KubeConfig []byte `protobuf:"bytes,3,opt,name=kubeConfig,proto3" json:"kubeConfig,omitempty"` + Message *MessageContext `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` + IncomingWebhook *IncomingWebhookContext `protobuf:"bytes,5,opt,name=incomingWebhook,proto3" json:"incomingWebhook,omitempty"` } func (x *ExecuteContext) Reset() { @@ -206,20 +207,75 @@ func (x *ExecuteContext) GetMessage() *MessageContext { return nil } +func (x *ExecuteContext) GetIncomingWebhook() *IncomingWebhookContext { + if x != nil { + return x.IncomingWebhook + } + return nil +} + +type IncomingWebhookContext struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BaseSourceURL string `protobuf:"bytes,1,opt,name=baseSourceURL,proto3" json:"baseSourceURL,omitempty"` +} + +func (x *IncomingWebhookContext) Reset() { + *x = IncomingWebhookContext{} + if protoimpl.UnsafeEnabled { + mi := &file_executor_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IncomingWebhookContext) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IncomingWebhookContext) ProtoMessage() {} + +func (x *IncomingWebhookContext) ProtoReflect() protoreflect.Message { + mi := &file_executor_proto_msgTypes[3] + 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 IncomingWebhookContext.ProtoReflect.Descriptor instead. +func (*IncomingWebhookContext) Descriptor() ([]byte, []int) { + return file_executor_proto_rawDescGZIP(), []int{3} +} + +func (x *IncomingWebhookContext) GetBaseSourceURL() string { + if x != nil { + return x.BaseSourceURL + } + return "" +} + type MessageContext struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - User *UserContext `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + ParentActivityId string `protobuf:"bytes,3,opt,name=parentActivityId,proto3" json:"parentActivityId,omitempty"` + User *UserContext `protobuf:"bytes,4,opt,name=user,proto3" json:"user,omitempty"` } func (x *MessageContext) Reset() { *x = MessageContext{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[3] + mi := &file_executor_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -232,7 +288,7 @@ func (x *MessageContext) String() string { func (*MessageContext) ProtoMessage() {} func (x *MessageContext) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[3] + mi := &file_executor_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -245,7 +301,7 @@ func (x *MessageContext) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageContext.ProtoReflect.Descriptor instead. func (*MessageContext) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{3} + return file_executor_proto_rawDescGZIP(), []int{4} } func (x *MessageContext) GetText() string { @@ -262,6 +318,13 @@ func (x *MessageContext) GetUrl() string { return "" } +func (x *MessageContext) GetParentActivityId() string { + if x != nil { + return x.ParentActivityId + } + return "" +} + func (x *MessageContext) GetUser() *UserContext { if x != nil { return x.User @@ -281,7 +344,7 @@ type UserContext struct { func (x *UserContext) Reset() { *x = UserContext{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[4] + mi := &file_executor_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -294,7 +357,7 @@ func (x *UserContext) String() string { func (*UserContext) ProtoMessage() {} func (x *UserContext) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[4] + mi := &file_executor_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -307,7 +370,7 @@ func (x *UserContext) ProtoReflect() protoreflect.Message { // Deprecated: Use UserContext.ProtoReflect.Descriptor instead. func (*UserContext) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{4} + return file_executor_proto_rawDescGZIP(), []int{5} } func (x *UserContext) GetMention() string { @@ -336,7 +399,7 @@ type ExecuteResponse struct { func (x *ExecuteResponse) Reset() { *x = ExecuteResponse{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[5] + mi := &file_executor_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -349,7 +412,7 @@ func (x *ExecuteResponse) String() string { func (*ExecuteResponse) ProtoMessage() {} func (x *ExecuteResponse) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[5] + mi := &file_executor_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -362,7 +425,7 @@ func (x *ExecuteResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecuteResponse.ProtoReflect.Descriptor instead. func (*ExecuteResponse) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{5} + return file_executor_proto_rawDescGZIP(), []int{6} } func (x *ExecuteResponse) GetMessage() []byte { @@ -401,7 +464,7 @@ type MetadataResponse struct { func (x *MetadataResponse) Reset() { *x = MetadataResponse{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[6] + mi := &file_executor_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -414,7 +477,7 @@ func (x *MetadataResponse) String() string { func (*MetadataResponse) ProtoMessage() {} func (x *MetadataResponse) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[6] + mi := &file_executor_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -427,7 +490,7 @@ func (x *MetadataResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MetadataResponse.ProtoReflect.Descriptor instead. func (*MetadataResponse) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{6} + return file_executor_proto_rawDescGZIP(), []int{7} } func (x *MetadataResponse) GetVersion() string { @@ -486,7 +549,7 @@ type JSONSchema struct { func (x *JSONSchema) Reset() { *x = JSONSchema{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[7] + mi := &file_executor_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -499,7 +562,7 @@ func (x *JSONSchema) String() string { func (*JSONSchema) ProtoMessage() {} func (x *JSONSchema) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[7] + mi := &file_executor_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -512,7 +575,7 @@ func (x *JSONSchema) ProtoReflect() protoreflect.Message { // Deprecated: Use JSONSchema.ProtoReflect.Descriptor instead. func (*JSONSchema) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{7} + return file_executor_proto_rawDescGZIP(), []int{8} } func (x *JSONSchema) GetValue() string { @@ -541,7 +604,7 @@ type Dependency struct { func (x *Dependency) Reset() { *x = Dependency{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[8] + mi := &file_executor_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -554,7 +617,7 @@ func (x *Dependency) String() string { func (*Dependency) ProtoMessage() {} func (x *Dependency) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[8] + mi := &file_executor_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -567,7 +630,7 @@ func (x *Dependency) ProtoReflect() protoreflect.Message { // Deprecated: Use Dependency.ProtoReflect.Descriptor instead. func (*Dependency) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{8} + return file_executor_proto_rawDescGZIP(), []int{9} } func (x *Dependency) GetUrls() map[string]string { @@ -588,7 +651,7 @@ type HelpResponse struct { func (x *HelpResponse) Reset() { *x = HelpResponse{} if protoimpl.UnsafeEnabled { - mi := &file_executor_proto_msgTypes[9] + mi := &file_executor_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -601,7 +664,7 @@ func (x *HelpResponse) String() string { func (*HelpResponse) ProtoMessage() {} func (x *HelpResponse) ProtoReflect() protoreflect.Message { - mi := &file_executor_proto_msgTypes[9] + mi := &file_executor_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -614,7 +677,7 @@ func (x *HelpResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HelpResponse.ProtoReflect.Descriptor instead. func (*HelpResponse) Descriptor() ([]byte, []int) { - return file_executor_proto_rawDescGZIP(), []int{9} + return file_executor_proto_rawDescGZIP(), []int{10} } func (x *HelpResponse) GetHelp() []byte { @@ -641,7 +704,7 @@ var file_executor_proto_rawDesc = []byte{ 0x66, 0x69, 0x67, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xc0, 0x01, 0x0a, 0x0e, 0x45, 0x78, 0x65, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x8c, 0x02, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x3a, 0x0a, 0x18, 0x69, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x69, @@ -653,75 +716,86 @@ var file_executor_proto_rawDesc = []byte{ 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61, 0x0a, 0x0e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, - 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x72, 0x6c, 0x12, 0x29, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x55, 0x73, 0x65, - 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x49, - 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, - 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x47, 0x0a, 0x0f, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x22, 0xfd, 0x02, 0x0a, 0x10, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x0b, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x6f, 0x72, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0a, - 0x6a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x50, 0x0a, 0x0c, 0x64, 0x65, - 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x65, 0x70, - 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, - 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, - 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x1a, 0x55, 0x0a, 0x11, 0x44, - 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x44, 0x65, 0x70, - 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x3b, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x66, 0x55, 0x72, 0x6c, 0x22, - 0x79, 0x0a, 0x0a, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x32, 0x0a, - 0x04, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, - 0x79, 0x2e, 0x55, 0x72, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x75, 0x72, 0x6c, - 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x55, 0x72, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x22, 0x0a, 0x0c, 0x48, 0x65, - 0x6c, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, - 0x6c, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x32, 0xc8, - 0x01, 0x0a, 0x08, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x12, 0x40, 0x0a, 0x07, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, - 0x72, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, - 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x38, 0x0a, 0x04, 0x48, 0x65, 0x6c, 0x70, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x16, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x12, 0x5a, 0x10, 0x70, 0x6b, 0x67, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x78, 0x74, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x0f, 0x69, + 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, + 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, + 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x22, 0x3e, 0x0a, 0x16, 0x49, 0x6e, 0x63, 0x6f, 0x6d, + 0x69, 0x6e, 0x67, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, + 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x22, 0x8d, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, + 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x2a, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, + 0x74, 0x79, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x49, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x6e, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x47, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0xfd, 0x02, 0x0a, 0x10, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x0b, + 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x4a, 0x53, 0x4f, + 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0a, 0x6a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x12, 0x50, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, + 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, + 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x10, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, + 0x72, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x64, 0x65, 0x64, 0x1a, 0x55, 0x0a, 0x11, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, + 0x63, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3b, 0x0a, 0x0a, 0x4a, + 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x17, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x66, 0x55, 0x72, 0x6c, 0x22, 0x79, 0x0a, 0x0a, 0x44, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x32, 0x0a, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, + 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x55, 0x72, 0x6c, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x55, 0x72, + 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x22, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x32, 0xc8, 0x01, 0x0a, 0x08, 0x45, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x6f, 0x72, 0x12, 0x40, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, + 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x04, 0x48, 0x65, 0x6c, 0x70, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x6f, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x12, 0x5a, 0x10, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -736,42 +810,44 @@ func file_executor_proto_rawDescGZIP() []byte { return file_executor_proto_rawDescData } -var file_executor_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_executor_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_executor_proto_goTypes = []interface{}{ - (*Config)(nil), // 0: executor.Config - (*ExecuteRequest)(nil), // 1: executor.ExecuteRequest - (*ExecuteContext)(nil), // 2: executor.ExecuteContext - (*MessageContext)(nil), // 3: executor.MessageContext - (*UserContext)(nil), // 4: executor.UserContext - (*ExecuteResponse)(nil), // 5: executor.ExecuteResponse - (*MetadataResponse)(nil), // 6: executor.MetadataResponse - (*JSONSchema)(nil), // 7: executor.JSONSchema - (*Dependency)(nil), // 8: executor.Dependency - (*HelpResponse)(nil), // 9: executor.HelpResponse - nil, // 10: executor.MetadataResponse.DependenciesEntry - nil, // 11: executor.Dependency.UrlsEntry - (*emptypb.Empty)(nil), // 12: google.protobuf.Empty + (*Config)(nil), // 0: executor.Config + (*ExecuteRequest)(nil), // 1: executor.ExecuteRequest + (*ExecuteContext)(nil), // 2: executor.ExecuteContext + (*IncomingWebhookContext)(nil), // 3: executor.IncomingWebhookContext + (*MessageContext)(nil), // 4: executor.MessageContext + (*UserContext)(nil), // 5: executor.UserContext + (*ExecuteResponse)(nil), // 6: executor.ExecuteResponse + (*MetadataResponse)(nil), // 7: executor.MetadataResponse + (*JSONSchema)(nil), // 8: executor.JSONSchema + (*Dependency)(nil), // 9: executor.Dependency + (*HelpResponse)(nil), // 10: executor.HelpResponse + nil, // 11: executor.MetadataResponse.DependenciesEntry + nil, // 12: executor.Dependency.UrlsEntry + (*emptypb.Empty)(nil), // 13: google.protobuf.Empty } var file_executor_proto_depIdxs = []int32{ 0, // 0: executor.ExecuteRequest.configs:type_name -> executor.Config 2, // 1: executor.ExecuteRequest.context:type_name -> executor.ExecuteContext - 3, // 2: executor.ExecuteContext.message:type_name -> executor.MessageContext - 4, // 3: executor.MessageContext.user:type_name -> executor.UserContext - 7, // 4: executor.MetadataResponse.json_schema:type_name -> executor.JSONSchema - 10, // 5: executor.MetadataResponse.dependencies:type_name -> executor.MetadataResponse.DependenciesEntry - 11, // 6: executor.Dependency.urls:type_name -> executor.Dependency.UrlsEntry - 8, // 7: executor.MetadataResponse.DependenciesEntry.value:type_name -> executor.Dependency - 1, // 8: executor.Executor.Execute:input_type -> executor.ExecuteRequest - 12, // 9: executor.Executor.Metadata:input_type -> google.protobuf.Empty - 12, // 10: executor.Executor.Help:input_type -> google.protobuf.Empty - 5, // 11: executor.Executor.Execute:output_type -> executor.ExecuteResponse - 6, // 12: executor.Executor.Metadata:output_type -> executor.MetadataResponse - 9, // 13: executor.Executor.Help:output_type -> executor.HelpResponse - 11, // [11:14] is the sub-list for method output_type - 8, // [8:11] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 4, // 2: executor.ExecuteContext.message:type_name -> executor.MessageContext + 3, // 3: executor.ExecuteContext.incomingWebhook:type_name -> executor.IncomingWebhookContext + 5, // 4: executor.MessageContext.user:type_name -> executor.UserContext + 8, // 5: executor.MetadataResponse.json_schema:type_name -> executor.JSONSchema + 11, // 6: executor.MetadataResponse.dependencies:type_name -> executor.MetadataResponse.DependenciesEntry + 12, // 7: executor.Dependency.urls:type_name -> executor.Dependency.UrlsEntry + 9, // 8: executor.MetadataResponse.DependenciesEntry.value:type_name -> executor.Dependency + 1, // 9: executor.Executor.Execute:input_type -> executor.ExecuteRequest + 13, // 10: executor.Executor.Metadata:input_type -> google.protobuf.Empty + 13, // 11: executor.Executor.Help:input_type -> google.protobuf.Empty + 6, // 12: executor.Executor.Execute:output_type -> executor.ExecuteResponse + 7, // 13: executor.Executor.Metadata:output_type -> executor.MetadataResponse + 10, // 14: executor.Executor.Help:output_type -> executor.HelpResponse + 12, // [12:15] is the sub-list for method output_type + 9, // [9:12] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_executor_proto_init() } @@ -817,7 +893,7 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessageContext); i { + switch v := v.(*IncomingWebhookContext); i { case 0: return &v.state case 1: @@ -829,7 +905,7 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserContext); i { + switch v := v.(*MessageContext); i { case 0: return &v.state case 1: @@ -841,7 +917,7 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecuteResponse); i { + switch v := v.(*UserContext); i { case 0: return &v.state case 1: @@ -853,7 +929,7 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MetadataResponse); i { + switch v := v.(*ExecuteResponse); i { case 0: return &v.state case 1: @@ -865,7 +941,7 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONSchema); i { + switch v := v.(*MetadataResponse); i { case 0: return &v.state case 1: @@ -877,7 +953,7 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Dependency); i { + switch v := v.(*JSONSchema); i { case 0: return &v.state case 1: @@ -889,6 +965,18 @@ func file_executor_proto_init() { } } file_executor_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Dependency); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_executor_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HelpResponse); i { case 0: return &v.state @@ -907,7 +995,7 @@ func file_executor_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_executor_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 13, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/api/executor/grpc_adapter.go b/pkg/api/executor/grpc_adapter.go index c8b8a5fd0..5bbc7527c 100644 --- a/pkg/api/executor/grpc_adapter.go +++ b/pkg/api/executor/grpc_adapter.go @@ -53,6 +53,13 @@ type ( // Limitations: // - It's available only for SocketSlack. In the future, it may be adopted across other platforms. Message Message + + IncomingWebhook IncomingWebhookDetailsContext + } + + // IncomingWebhookDetailsContext holds source incoming webhook context. + IncomingWebhookDetailsContext struct { + BaseSourceURL string } // Message holds information about the message that triggered a given Executor. @@ -60,6 +67,10 @@ type ( Text string URL string User User + + // ParentActivityID is the ID of the parent activity. If user follows with messages in a thread, this ID represents the originating message that started that thread. + // Otherwise, it's the ID of the initial message. + ParentActivityID string } // User represents the user that sent a message. @@ -93,7 +104,7 @@ type ( // // NOTE: In the future we can consider using VersionedPlugins. These can be used to negotiate // a compatible version between client and server. If this is set, Handshake.ProtocolVersion is not required. -const ProtocolVersion = 2 +const ProtocolVersion = 3 var _ plugin.GRPCPlugin = &Plugin{} @@ -133,13 +144,17 @@ func (p *grpcClient) Execute(ctx context.Context, in ExecuteInput) (ExecuteOutpu IsInteractivitySupported: in.Context.IsInteractivitySupported, KubeConfig: in.Context.KubeConfig, Message: &MessageContext{ - Text: in.Context.Message.Text, - Url: in.Context.Message.URL, + Text: in.Context.Message.Text, + Url: in.Context.Message.URL, + ParentActivityId: in.Context.Message.ParentActivityID, User: &UserContext{ Mention: in.Context.Message.User.Mention, DisplayName: in.Context.Message.User.DisplayName, }, }, + IncomingWebhook: &IncomingWebhookContext{ + BaseSourceURL: in.Context.IncomingWebhook.BaseSourceURL, + }, }, } @@ -241,6 +256,9 @@ func (p *grpcServer) Execute(ctx context.Context, request *ExecuteRequest) (*Exe IsInteractivitySupported: request.Context.IsInteractivitySupported, KubeConfig: request.Context.KubeConfig, Message: p.toMessageIfPresent(request.Context.Message), + IncomingWebhook: IncomingWebhookDetailsContext{ + BaseSourceURL: request.Context.IncomingWebhook.BaseSourceURL, + }, }, }) if err != nil { @@ -281,9 +299,10 @@ func (*grpcServer) toMessageIfPresent(msg *MessageContext) Message { } return Message{ - Text: msg.Text, - URL: msg.Url, - User: user, + Text: msg.Text, + URL: msg.Url, + ParentActivityID: msg.ParentActivityId, + User: user, } } diff --git a/pkg/api/message.go b/pkg/api/message.go index 685aaee83..2a5226c88 100644 --- a/pkg/api/message.go +++ b/pkg/api/message.go @@ -60,6 +60,9 @@ type Message struct { OnlyVisibleForYou bool `json:"onlyVisibleForYou,omitempty" yaml:"onlyVisibleForYou"` ReplaceOriginal bool `json:"replaceOriginal,omitempty" yaml:"replaceOriginal"` UserHandle string `json:"userHandle,omitempty" yaml:"userHandle"` + + // ParentActivityID represents the originating message that started a thread. If set, message will be sent in that thread instead of the default one. + ParentActivityID string `json:"parentActivityId" yaml:"parentActivityId"` } func (msg *Message) IsEmpty() bool { diff --git a/pkg/api/source/grpc_adapter.go b/pkg/api/source/grpc_adapter.go index 2ac629b68..05585392a 100644 --- a/pkg/api/source/grpc_adapter.go +++ b/pkg/api/source/grpc_adapter.go @@ -108,7 +108,7 @@ type ( // // NOTE: In the future we can consider using VersionedPlugins. These can be used to negotiate // a compatible version between client and server. If this is set, Handshake.ProtocolVersion is not required. -const ProtocolVersion = 2 +const ProtocolVersion = 3 var _ plugin.GRPCPlugin = &Plugin{} diff --git a/pkg/bot/slack_socket.go b/pkg/bot/slack_socket.go index affa2f825..29dcbe7aa 100644 --- a/pkg/bot/slack_socket.go +++ b/pkg/bot/slack_socket.go @@ -442,6 +442,7 @@ func (b *SocketSlack) handleMessage(ctx context.Context, event slackMessage) err SlackState: event.State, URL: permalink, Text: event.Text, + ParentActivityID: event.GetTimestamp(), }, Message: request, User: execute.UserInput{ @@ -568,6 +569,11 @@ func (b *SocketSlack) send(ctx context.Context, event slackMessage, in interacti if resp.Message.UserHandle != "" { id = resp.Message.UserHandle } + + if resp.Message.ParentActivityID != "" { + options = append(options, slack.MsgOptionTS(resp.Message.ParentActivityID)) + } + _, _, err = b.client.PostMessageContext(ctx, id, options...) if err != nil { return fmt.Errorf("while posting Slack message: %w", slackError(err, event.Channel)) diff --git a/pkg/execute/factory.go b/pkg/execute/factory.go index 432837b78..a2d3d6711 100644 --- a/pkg/execute/factory.go +++ b/pkg/execute/factory.go @@ -172,6 +172,7 @@ type Conversation struct { SlackState *slack.BlockActionStates URL string Text string + ParentActivityID string } // NewDefaultInput an input for NewDefault diff --git a/pkg/execute/plugin_executor.go b/pkg/execute/plugin_executor.go index aac91054c..da214c588 100644 --- a/pkg/execute/plugin_executor.go +++ b/pkg/execute/plugin_executor.go @@ -119,6 +119,10 @@ func (e *PluginExecutor) Execute(ctx context.Context, bindings []string, slackSt Mention: cmdCtx.User.Mention, DisplayName: cmdCtx.User.DisplayName, }, + ParentActivityID: cmdCtx.Conversation.ParentActivityID, + }, + IncomingWebhook: executor.IncomingWebhookDetailsContext{ + BaseSourceURL: e.cfg.Plugins.IncomingWebhook.InClusterBaseURL + "/sources/v1", }, }, }) diff --git a/test/fake/plugin_server.go b/pkg/plugin/plugin_server.go similarity index 66% rename from test/fake/plugin_server.go rename to pkg/plugin/plugin_server.go index 1c8a113a6..9f374b4c5 100644 --- a/test/fake/plugin_server.go +++ b/pkg/plugin/plugin_server.go @@ -1,8 +1,7 @@ -package fake +package plugin import ( "fmt" - "github.com/kubeshop/botkube/pkg/plugin" "log" "net/http" "os" @@ -16,26 +15,21 @@ import ( const indexFileEndpoint = "/botkube.yaml" type ( - // PluginConfig holds configuration for fake plugin server. - PluginConfig struct { + // StaticPluginServerConfig holds configuration for fake plugin server. + StaticPluginServerConfig struct { BinariesDirectory string - Server PluginServer - } - - // PluginServer holds configuration for HTTP plugin server. - PluginServer struct { - Host string `envconfig:"default=http://host.k3d.internal"` - Port int `envconfig:"default=3000"` + Host string `envconfig:"default=http://host.k3d.internal"` + Port int `envconfig:"default=3000"` } ) -// NewPluginServer return function to start the fake plugin HTTP server. -func NewPluginServer(cfg PluginConfig) (string, func() error) { +// NewStaticPluginServer return function to start the static plugin HTTP server suitable for local development or e2e tests. +func NewStaticPluginServer(cfg StaticPluginServerConfig) (string, func() error) { fs := http.FileServer(http.Dir(cfg.BinariesDirectory)) http.Handle("/static/", http.StripPrefix("/static/", fs)) - basePath := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port) - builder := plugin.NewIndexBuilder(loggerx.NewNoop()) + basePath := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) + builder := NewIndexBuilder(loggerx.NewNoop()) http.HandleFunc(indexFileEndpoint, func(w http.ResponseWriter, _ *http.Request) { isArchive := os.Getenv("OUTPUT_MODE") == "archive" @@ -57,7 +51,7 @@ func NewPluginServer(cfg PluginConfig) (string, func() error) { } }) - addr := fmt.Sprintf(":%d", cfg.Server.Port) + addr := fmt.Sprintf(":%d", cfg.Port) log.Printf("Listening on %s...", addr) server := &http.Server{ diff --git a/proto/executor.proto b/proto/executor.proto index 125ad6ee3..b072fe9cc 100644 --- a/proto/executor.proto +++ b/proto/executor.proto @@ -25,12 +25,18 @@ message ExecuteContext { bytes slackState = 2; bytes kubeConfig = 3; MessageContext message = 4; + IncomingWebhookContext incomingWebhook = 5; +} + +message IncomingWebhookContext { + string baseSourceURL = 1; } message MessageContext { string text = 1; string url = 2; - UserContext user = 3; + string parentActivityId = 3; + UserContext user = 4; } message UserContext { diff --git a/test/e2e/bots_test.go b/test/e2e/bots_test.go index 1ac88ba1d..f16626933 100644 --- a/test/e2e/bots_test.go +++ b/test/e2e/bots_test.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "fmt" + "github.com/kubeshop/botkube/pkg/pluginx" "net/http" "regexp" "strconv" @@ -17,7 +18,6 @@ import ( "botkube.io/botube/test/botkubex" "botkube.io/botube/test/commplatform" "botkube.io/botube/test/diff" - "botkube.io/botube/test/fake" "github.com/MakeNowJust/heredoc" "github.com/anthhub/forwarder" "github.com/hasura/go-graphql-client" @@ -87,7 +87,7 @@ type Config struct { Port int `envconfig:"default=2115"` LocalPort int `envconfig:"default=2115"` } - Plugins fake.PluginConfig + Plugins pluginx.StaticPluginServerConfig ConfigMap struct { Namespace string `envconfig:"default=botkube"` } @@ -215,7 +215,7 @@ func runBotTest(t *testing.T, var indexEndpoint string if botDriver.Type() == commplatform.DiscordBot { t.Log("Starting plugin server...") - endpoint, startServerFn := fake.NewPluginServer(appCfg.Plugins) + endpoint, startServerFn := pluginx.NewStaticPluginServer(appCfg.Plugins) indexEndpoint = endpoint go func() { require.NoError(t, startServerFn()) diff --git a/test/helpers/plugin_server.go b/test/helpers/plugin_server.go deleted file mode 100644 index 0d77509e5..000000000 --- a/test/helpers/plugin_server.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "log" - "os" - "path/filepath" - "strconv" - - "botkube.io/botube/test/fake" - - "github.com/kubeshop/botkube/pkg/loggerx" -) - -func main() { - dir, err := os.Getwd() - loggerx.ExitOnError(err, "while getting current directory") - - host := os.Getenv("PLUGIN_SERVER_HOST") - port := os.Getenv("PLUGIN_SERVER_PORT") - if host == "" { - host = "http://localhost" - } - if port == "" { - port = "3010" - } - portInt, err := strconv.Atoi(port) - loggerx.ExitOnError(err, "while starting server") - - binDir := filepath.Join(dir, "../plugin-dist") - indexEndpoint, startServerFn := fake.NewPluginServer(fake.PluginConfig{ - BinariesDirectory: binDir, - Server: fake.PluginServer{ - Host: host, - Port: portInt, - }, - }) - - log.Printf("Service plugin binaries from %s\n", binDir) - log.Printf("Botkube repository index URL: %s", indexEndpoint) - err = startServerFn() - loggerx.ExitOnError(err, "while starting server") -}