From 426816134208b8d05b4480267a8f4e47fd43fd92 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Trivino Date: Thu, 14 Sep 2023 23:41:30 +0200 Subject: [PATCH 1/3] feat(api): get workflowRuns by digest Signed-off-by: Miguel Martinez Trivino --- .../internal/action/workflow_run_describe.go | 4 +- .../api/controlplane/v1/workflow_run.pb.go | 223 +++++++++++------- .../v1/workflow_run.pb.validate.go | 63 ++++- .../api/controlplane/v1/workflow_run.proto | 8 +- .../frontend/controlplane/v1/workflow_run.ts | 26 +- .../internal/biz/mocks/WorkflowRunRepo.go | 26 ++ .../internal/biz/workflowcontract.go | 10 +- app/controlplane/internal/biz/workflowrun.go | 40 +++- .../biz/workflowrun_integration_test.go | 4 +- app/controlplane/internal/data/workflowrun.go | 21 +- .../internal/dispatcher/dispatcher.go | 2 +- .../internal/service/attestation.go | 4 +- .../internal/service/workflowrun.go | 25 +- 13 files changed, 335 insertions(+), 121 deletions(-) diff --git a/app/cli/internal/action/workflow_run_describe.go b/app/cli/internal/action/workflow_run_describe.go index ac7e40a08..b79f14012 100644 --- a/app/cli/internal/action/workflow_run_describe.go +++ b/app/cli/internal/action/workflow_run_describe.go @@ -85,7 +85,9 @@ func NewWorkflowRunDescribe(cfg *ActionsOpts) *WorkflowRunDescribe { func (action *WorkflowRunDescribe) Run(runID string, verify bool, publicKey string) (*WorkflowRunItemFull, error) { client := pb.NewWorkflowRunServiceClient(action.cfg.CPConnection) - resp, err := client.View(context.Background(), &pb.WorkflowRunServiceViewRequest{Id: runID}) + resp, err := client.View(context.Background(), &pb.WorkflowRunServiceViewRequest{ + Ref: &pb.WorkflowRunServiceViewRequest_Id{Id: runID}, + }) if err != nil { return nil, err } diff --git a/app/controlplane/api/controlplane/v1/workflow_run.pb.go b/app/controlplane/api/controlplane/v1/workflow_run.pb.go index ff4595fd3..e11db0a3e 100644 --- a/app/controlplane/api/controlplane/v1/workflow_run.pb.go +++ b/app/controlplane/api/controlplane/v1/workflow_run.pb.go @@ -601,7 +601,13 @@ type WorkflowRunServiceViewRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // It can search by either ID or digest + // + // Types that are assignable to Ref: + // + // *WorkflowRunServiceViewRequest_Id + // *WorkflowRunServiceViewRequest_Digest + Ref isWorkflowRunServiceViewRequest_Ref `protobuf_oneof:"ref"` } func (x *WorkflowRunServiceViewRequest) Reset() { @@ -636,13 +642,43 @@ func (*WorkflowRunServiceViewRequest) Descriptor() ([]byte, []int) { return file_controlplane_v1_workflow_run_proto_rawDescGZIP(), []int{10} } +func (m *WorkflowRunServiceViewRequest) GetRef() isWorkflowRunServiceViewRequest_Ref { + if m != nil { + return m.Ref + } + return nil +} + func (x *WorkflowRunServiceViewRequest) GetId() string { - if x != nil { + if x, ok := x.GetRef().(*WorkflowRunServiceViewRequest_Id); ok { return x.Id } return "" } +func (x *WorkflowRunServiceViewRequest) GetDigest() string { + if x, ok := x.GetRef().(*WorkflowRunServiceViewRequest_Digest); ok { + return x.Digest + } + return "" +} + +type isWorkflowRunServiceViewRequest_Ref interface { + isWorkflowRunServiceViewRequest_Ref() +} + +type WorkflowRunServiceViewRequest_Id struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3,oneof"` +} + +type WorkflowRunServiceViewRequest_Digest struct { + Digest string `protobuf:"bytes,2,opt,name=digest,proto3,oneof"` +} + +func (*WorkflowRunServiceViewRequest_Id) isWorkflowRunServiceViewRequest_Ref() {} + +func (*WorkflowRunServiceViewRequest_Digest) isWorkflowRunServiceViewRequest_Ref() {} + type WorkflowRunServiceViewResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1155,104 +1191,107 @@ var file_controlplane_v1_workflow_run_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x39, 0x0a, 0x1d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, + 0x6a, 0x0a, 0x1d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02, 0x69, 0x64, 0x22, 0x84, 0x02, 0x0a, 0x1e, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x06, + 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x42, + 0x0a, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0x84, 0x02, 0x0a, 0x1e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x91, 0x01, - 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x43, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, + 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x49, 0x74, 0x65, 0x6d, - 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x12, 0x42, 0x0a, - 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, + 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x91, + 0x01, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x43, 0x0a, 0x0c, 0x77, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x12, 0x42, + 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x27, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, + 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x52, 0x75, 0x6e, 0x49, 0x64, 0x22, 0xdf, 0x01, 0x0a, 0x28, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x58, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x22, 0x51, 0x0a, 0x27, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, - 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, - 0x75, 0x6e, 0x49, 0x64, 0x22, 0xdf, 0x01, 0x0a, 0x28, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x58, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, - 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x59, 0x0a, 0x06, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x07, 0x62, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x07, 0x62, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x32, 0xde, 0x04, 0x0a, 0x12, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7c, 0x0a, - 0x0b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x35, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x04, 0x49, - 0x6e, 0x69, 0x74, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x2f, 0x2e, + 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x59, 0x0a, 0x06, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x07, + 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x07, + 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x32, 0xde, 0x04, 0x0a, 0x12, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7c, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, + 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x04, + 0x49, 0x6e, 0x69, 0x74, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x85, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, - 0x65, 0x64, 0x73, 0x12, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x65, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x85, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, + 0x72, 0x65, 0x64, 0x73, 0x12, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe6, 0x01, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x67, - 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, - 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, - 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x04, 0x56, 0x69, 0x65, 0x77, 0x12, - 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x65, 0x64, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x06, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe6, 0x01, 0x0a, 0x12, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x67, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x04, 0x56, 0x69, 0x65, 0x77, + 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1572,6 +1611,10 @@ func file_controlplane_v1_workflow_run_proto_init() { } } } + file_controlplane_v1_workflow_run_proto_msgTypes[10].OneofWrappers = []interface{}{ + (*WorkflowRunServiceViewRequest_Id)(nil), + (*WorkflowRunServiceViewRequest_Digest)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/app/controlplane/api/controlplane/v1/workflow_run.pb.validate.go b/app/controlplane/api/controlplane/v1/workflow_run.pb.validate.go index ee0885557..50507d9dc 100644 --- a/app/controlplane/api/controlplane/v1/workflow_run.pb.validate.go +++ b/app/controlplane/api/controlplane/v1/workflow_run.pb.validate.go @@ -1333,11 +1333,64 @@ func (m *WorkflowRunServiceViewRequest) validate(all bool) error { var errors []error - if err := m._validateUuid(m.GetId()); err != nil { - err = WorkflowRunServiceViewRequestValidationError{ - field: "Id", - reason: "value must be a valid UUID", - cause: err, + oneofRefPresent := false + switch v := m.Ref.(type) { + case *WorkflowRunServiceViewRequest_Id: + if v == nil { + err := WorkflowRunServiceViewRequestValidationError{ + field: "Ref", + reason: "oneof value cannot be a typed-nil", + } + if !all { + return err + } + errors = append(errors, err) + } + oneofRefPresent = true + + if err := m._validateUuid(m.GetId()); err != nil { + err = WorkflowRunServiceViewRequestValidationError{ + field: "Id", + reason: "value must be a valid UUID", + cause: err, + } + if !all { + return err + } + errors = append(errors, err) + } + + case *WorkflowRunServiceViewRequest_Digest: + if v == nil { + err := WorkflowRunServiceViewRequestValidationError{ + field: "Ref", + reason: "oneof value cannot be a typed-nil", + } + if !all { + return err + } + errors = append(errors, err) + } + oneofRefPresent = true + + if utf8.RuneCountInString(m.GetDigest()) < 1 { + err := WorkflowRunServiceViewRequestValidationError{ + field: "Digest", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + default: + _ = v // ensures v is used + } + if !oneofRefPresent { + err := WorkflowRunServiceViewRequestValidationError{ + field: "Ref", + reason: "value is required", } if !all { return err diff --git a/app/controlplane/api/controlplane/v1/workflow_run.proto b/app/controlplane/api/controlplane/v1/workflow_run.proto index 199ce6219..d40e6ac34 100644 --- a/app/controlplane/api/controlplane/v1/workflow_run.proto +++ b/app/controlplane/api/controlplane/v1/workflow_run.proto @@ -107,7 +107,13 @@ message WorkflowRunServiceListResponse { } message WorkflowRunServiceViewRequest { - string id = 1 [(validate.rules).string.uuid = true]; + // It can search by either ID or digest + oneof ref { + option (validate.required) = true; + + string id = 1 [(validate.rules).string.uuid = true]; + string digest = 2 [(validate.rules).string = {min_len: 1}]; + } } message WorkflowRunServiceViewResponse { diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/workflow_run.ts b/app/controlplane/api/gen/frontend/controlplane/v1/workflow_run.ts index 931a10aea..8bc2813ef 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/workflow_run.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/workflow_run.ts @@ -118,7 +118,8 @@ export interface WorkflowRunServiceListResponse { } export interface WorkflowRunServiceViewRequest { - id: string; + id?: string | undefined; + digest?: string | undefined; } export interface WorkflowRunServiceViewResponse { @@ -1034,14 +1035,17 @@ export const WorkflowRunServiceListResponse = { }; function createBaseWorkflowRunServiceViewRequest(): WorkflowRunServiceViewRequest { - return { id: "" }; + return { id: undefined, digest: undefined }; } export const WorkflowRunServiceViewRequest = { encode(message: WorkflowRunServiceViewRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.id !== "") { + if (message.id !== undefined) { writer.uint32(10).string(message.id); } + if (message.digest !== undefined) { + writer.uint32(18).string(message.digest); + } return writer; }, @@ -1059,6 +1063,13 @@ export const WorkflowRunServiceViewRequest = { message.id = reader.string(); continue; + case 2: + if (tag !== 18) { + break; + } + + message.digest = reader.string(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -1069,12 +1080,16 @@ export const WorkflowRunServiceViewRequest = { }, fromJSON(object: any): WorkflowRunServiceViewRequest { - return { id: isSet(object.id) ? String(object.id) : "" }; + return { + id: isSet(object.id) ? String(object.id) : undefined, + digest: isSet(object.digest) ? String(object.digest) : undefined, + }; }, toJSON(message: WorkflowRunServiceViewRequest): unknown { const obj: any = {}; message.id !== undefined && (obj.id = message.id); + message.digest !== undefined && (obj.digest = message.digest); return obj; }, @@ -1086,7 +1101,8 @@ export const WorkflowRunServiceViewRequest = { object: I, ): WorkflowRunServiceViewRequest { const message = createBaseWorkflowRunServiceViewRequest(); - message.id = object.id ?? ""; + message.id = object.id ?? undefined; + message.digest = object.digest ?? undefined; return message; }, }; diff --git a/app/controlplane/internal/biz/mocks/WorkflowRunRepo.go b/app/controlplane/internal/biz/mocks/WorkflowRunRepo.go index 6913ce04f..20583e7a7 100644 --- a/app/controlplane/internal/biz/mocks/WorkflowRunRepo.go +++ b/app/controlplane/internal/biz/mocks/WorkflowRunRepo.go @@ -63,6 +63,32 @@ func (_m *WorkflowRunRepo) Expire(ctx context.Context, id uuid.UUID) error { return r0 } +// FindByAttestationDigest provides a mock function with given fields: ctx, digest +func (_m *WorkflowRunRepo) FindByAttestationDigest(ctx context.Context, digest string) (*biz.WorkflowRun, error) { + ret := _m.Called(ctx, digest) + + var r0 *biz.WorkflowRun + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*biz.WorkflowRun, error)); ok { + return rf(ctx, digest) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *biz.WorkflowRun); ok { + r0 = rf(ctx, digest) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*biz.WorkflowRun) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, digest) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindByID provides a mock function with given fields: ctx, ID func (_m *WorkflowRunRepo) FindByID(ctx context.Context, ID uuid.UUID) (*biz.WorkflowRun, error) { ret := _m.Called(ctx, ID) diff --git a/app/controlplane/internal/biz/workflowcontract.go b/app/controlplane/internal/biz/workflowcontract.go index cdd31bdf9..d211a8b12 100644 --- a/app/controlplane/internal/biz/workflowcontract.go +++ b/app/controlplane/internal/biz/workflowcontract.go @@ -18,6 +18,7 @@ package biz import ( "context" "errors" + "fmt" "time" schemav1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1" @@ -152,7 +153,14 @@ func (uc *WorkflowContractUseCase) FindVersionByID(ctx context.Context, versionI return nil, err } - return uc.repo.FindVersionByID(ctx, versionUUID) + r, err := uc.repo.FindVersionByID(ctx, versionUUID) + if err != nil { + return nil, fmt.Errorf("finding contract version: %w", err) + } else if r == nil { + return nil, NewErrNotFound("contract version") + } + + return r, nil } func (uc *WorkflowContractUseCase) Update(ctx context.Context, orgID, contractID, name string, schema *schemav1.CraftingSchema) (*WorkflowContractWithVersion, error) { diff --git a/app/controlplane/internal/biz/workflowrun.go b/app/controlplane/internal/biz/workflowrun.go index 66ecb6fad..65013fb93 100644 --- a/app/controlplane/internal/biz/workflowrun.go +++ b/app/controlplane/internal/biz/workflowrun.go @@ -26,6 +26,7 @@ import ( "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/go-kratos/kratos/v2/log" + cr_v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/uuid" ) @@ -64,6 +65,7 @@ const ( type WorkflowRunRepo interface { Create(ctx context.Context, workflowID, robotaccountID, contractVersion uuid.UUID, runURL, runnerType string, casBackends []uuid.UUID) (*WorkflowRun, error) FindByID(ctx context.Context, ID uuid.UUID) (*WorkflowRun, error) + FindByAttestationDigest(ctx context.Context, digest string) (*WorkflowRun, error) FindByIDInOrg(ctx context.Context, orgID, ID uuid.UUID) (*WorkflowRun, error) MarkAsFinished(ctx context.Context, ID uuid.UUID, status WorkflowRunStatus, reason string) error SaveAttestation(ctx context.Context, ID uuid.UUID, att *dsse.Envelope, digest string) error @@ -247,7 +249,7 @@ func (uc *WorkflowRunUseCase) List(ctx context.Context, orgID, workflowID string return uc.wfRunRepo.List(ctx, orgUUID, workflowUUID, p) } -func (uc *WorkflowRunUseCase) View(ctx context.Context, orgID, runID string) (*WorkflowRun, error) { +func (uc *WorkflowRunUseCase) GetByID(ctx context.Context, orgID, runID string) (*WorkflowRun, error) { orgUUID, err := uuid.Parse(orgID) if err != nil { return nil, NewErrInvalidUUID(err) @@ -258,7 +260,41 @@ func (uc *WorkflowRunUseCase) View(ctx context.Context, orgID, runID string) (*W return nil, NewErrInvalidUUID(err) } - return uc.wfRunRepo.FindByIDInOrg(ctx, orgUUID, runUUID) + wfrun, err := uc.wfRunRepo.FindByID(ctx, runUUID) + if err != nil { + return nil, fmt.Errorf("finding workflow run: %w", err) + } + + // If the workflow is public or belongs to the org we can return it + return workflowRunInOrgOrPublic(wfrun, orgUUID) +} + +func (uc *WorkflowRunUseCase) GetByDigest(ctx context.Context, orgID, digest string) (*WorkflowRun, error) { + orgUUID, err := uuid.Parse(orgID) + if err != nil { + return nil, NewErrInvalidUUID(err) + } + + if _, err := cr_v1.NewHash(digest); err != nil { + return nil, NewErrValidation(fmt.Errorf("invalid digest format: %w", err)) + } + + wfrun, err := uc.wfRunRepo.FindByAttestationDigest(ctx, digest) + if err != nil { + return nil, fmt.Errorf("finding workflow run: %w", err) + } + + // If the workflow is public or belongs to the org we can return it + return workflowRunInOrgOrPublic(wfrun, orgUUID) +} + +// filter the workflow runs that belong to the org or are public +func workflowRunInOrgOrPublic(wfRun *WorkflowRun, orgID uuid.UUID) (*WorkflowRun, error) { + if wfRun == nil || (wfRun.Workflow.OrgID != orgID && !wfRun.Workflow.Public) { + return nil, NewErrNotFound("workflow run") + } + + return wfRun, nil } // Implements https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues diff --git a/app/controlplane/internal/biz/workflowrun_integration_test.go b/app/controlplane/internal/biz/workflowrun_integration_test.go index 7771f98bf..a518b0ad2 100644 --- a/app/controlplane/internal/biz/workflowrun_integration_test.go +++ b/app/controlplane/internal/biz/workflowrun_integration_test.go @@ -54,7 +54,7 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() { assert.NoError(err) // Retrieve attestation ref from storage and compare - r, err := s.WorkflowRun.View(ctx, s.org.ID, run.ID.String()) + r, err := s.WorkflowRun.GetByID(ctx, s.org.ID, run.ID.String()) assert.NoError(err) assert.Equal(r.Attestation, &biz.Attestation{Envelope: validEnvelope, Digest: validDigest}) }) @@ -69,7 +69,7 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() { assert.NoError(err) // Retrieve attestation ref from storage and compare - r, err := s.WorkflowRun.View(ctx, s.org.ID, run.ID.String()) + r, err := s.WorkflowRun.GetByID(ctx, s.org.ID, run.ID.String()) assert.NoError(err) assert.Equal(r.Attestation, &biz.Attestation{Envelope: validEnvelope, Digest: ""}) }) diff --git a/app/controlplane/internal/data/workflowrun.go b/app/controlplane/internal/data/workflowrun.go index 43810d047..6818a88a4 100644 --- a/app/controlplane/internal/data/workflowrun.go +++ b/app/controlplane/internal/data/workflowrun.go @@ -62,9 +62,26 @@ func (r *WorkflowRunRepo) Create(ctx context.Context, workflowID, robotaccountID return r.FindByID(ctx, p.ID) } +func eagerLoadWorkflowRun(client *ent.Client) *ent.WorkflowRunQuery { + return client.WorkflowRun.Query(). + WithWorkflow(func(q *ent.WorkflowQuery) { q.WithOrganization() }). + WithContractVersion(). + WithCasBackends() +} + func (r *WorkflowRunRepo) FindByID(ctx context.Context, id uuid.UUID) (*biz.WorkflowRun, error) { - run, err := r.data.db.WorkflowRun.Query(). - Where(workflowrun.ID(id)).WithWorkflow().WithContractVersion().WithCasBackends().Only(ctx) + run, err := eagerLoadWorkflowRun(r.data.db).Where(workflowrun.ID(id)).Only(ctx) + if err != nil && !ent.IsNotFound(err) { + return nil, err + } else if run == nil { + return nil, nil + } + + return entWrToBizWr(run), nil +} + +func (r *WorkflowRunRepo) FindByAttestationDigest(ctx context.Context, digest string) (*biz.WorkflowRun, error) { + run, err := eagerLoadWorkflowRun(r.data.db).Where(workflowrun.AttestationDigest(digest)).Only(ctx) if err != nil && !ent.IsNotFound(err) { return nil, err } else if run == nil { diff --git a/app/controlplane/internal/dispatcher/dispatcher.go b/app/controlplane/internal/dispatcher/dispatcher.go index 77de19166..38711282f 100644 --- a/app/controlplane/internal/dispatcher/dispatcher.go +++ b/app/controlplane/internal/dispatcher/dispatcher.go @@ -102,7 +102,7 @@ func (d *FanOutDispatcher) Run(ctx context.Context, opts *RunOpts) error { return fmt.Errorf("workflow not found") } - wfRun, err := d.wfRunUC.View(ctx, opts.OrgID, opts.WorkflowRunID) + wfRun, err := d.wfRunUC.GetByID(ctx, opts.OrgID, opts.WorkflowRunID) if err != nil { return fmt.Errorf("finding workflow: %w", err) } else if wfRun == nil { diff --git a/app/controlplane/internal/service/attestation.go b/app/controlplane/internal/service/attestation.go index 19e35bf23..6b8c0893c 100644 --- a/app/controlplane/internal/service/attestation.go +++ b/app/controlplane/internal/service/attestation.go @@ -175,7 +175,7 @@ func (s *AttestationService) Store(ctx context.Context, req *cpAPI.AttestationSe return nil, sl.LogAndMaskErr(err, s.log) } - wRun, err := s.wrUseCase.View(ctx, robotAccount.OrgID, req.WorkflowRunId) + wRun, err := s.wrUseCase.GetByID(ctx, robotAccount.OrgID, req.WorkflowRunId) if err != nil { return nil, sl.LogAndMaskErr(err, s.log) } else if wRun == nil { @@ -310,7 +310,7 @@ func (s *AttestationService) GetUploadCreds(ctx context.Context, req *cpAPI.Atte } } else { // This is the new mode, where the CAS backend ref is stored in the workflow run since initialization - wRun, err := s.wrUseCase.View(ctx, robotAccount.OrgID, req.WorkflowRunId) + wRun, err := s.wrUseCase.GetByID(ctx, robotAccount.OrgID, req.WorkflowRunId) if err != nil { return nil, sl.LogAndMaskErr(err, s.log) } else if wRun == nil { diff --git a/app/controlplane/internal/service/workflowrun.go b/app/controlplane/internal/service/workflowrun.go index cddaf5ac1..54426c8ed 100644 --- a/app/controlplane/internal/service/workflowrun.go +++ b/app/controlplane/internal/service/workflowrun.go @@ -65,7 +65,7 @@ func (s *WorkflowRunService) List(ctx context.Context, req *pb.WorkflowRunServic if req.GetWorkflowId() != "" { wf, err := s.workflowUseCase.FindByIDInOrg(ctx, currentOrg.ID, req.GetWorkflowId()) if err != nil { - return nil, sl.LogAndMaskErr(err, s.log) + return nil, handleUseCaseErr(workflowRunEntity, err, s.log) } else if wf == nil { return nil, errors.NotFound("not found", "workflow not found") } @@ -96,17 +96,26 @@ func bizCursorToPb(cursor string) *pb.PaginationResponse { return &pb.PaginationResponse{NextCursor: cursor} } +const workflowRunEntity = "Workflow Run" + func (s *WorkflowRunService) View(ctx context.Context, req *pb.WorkflowRunServiceViewRequest) (*pb.WorkflowRunServiceViewResponse, error) { _, currentOrg, err := loadCurrentUserAndOrg(ctx) if err != nil { return nil, err } - run, err := s.wrUseCase.View(ctx, currentOrg.ID, req.Id) - if err != nil { - return nil, sl.LogAndMaskErr(err, s.log) - } else if run == nil { - return nil, errors.NotFound("not found", "workflow run not found") + // retrieve the workflow run either by ID or by digest + var run *biz.WorkflowRun + if req.GetId() != "" { + run, err = s.wrUseCase.GetByID(ctx, currentOrg.ID, req.GetId()) + if err != nil { + return nil, handleUseCaseErr(workflowRunEntity, err, s.log) + } + } else if req.GetDigest() != "" { + run, err = s.wrUseCase.GetByDigest(ctx, currentOrg.ID, req.GetDigest()) + if err != nil { + return nil, handleUseCaseErr(workflowRunEntity, err, s.log) + } } attestation, err := bizAttestationToPb(run.Attestation) @@ -116,9 +125,7 @@ func (s *WorkflowRunService) View(ctx context.Context, req *pb.WorkflowRunServic contractVersion, err := s.workflowContractUseCase.FindVersionByID(ctx, run.ContractVersionID.String()) if err != nil { - return nil, sl.LogAndMaskErr(err, s.log) - } else if contractVersion == nil { - return nil, errors.NotFound("not found", "contract not found") + return nil, handleUseCaseErr(workflowRunEntity, err, s.log) } wr := bizWorkFlowRunToPb(run) From d67d62922db74391002804df4812c722693dffb6 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Trivino Date: Fri, 15 Sep 2023 00:14:46 +0200 Subject: [PATCH 2/3] chore: add index to attestation digest Signed-off-by: Miguel Martinez Trivino --- app/controlplane/internal/biz/workflow.go | 3 + app/controlplane/internal/biz/workflowrun.go | 8 +- .../biz/workflowrun_integration_test.go | 100 +++++++++++++++--- .../ent/migrate/migrations/20230914221336.sql | 2 + .../data/ent/migrate/migrations/atlas.sum | 3 +- .../internal/data/ent/migrate/schema.go | 5 + .../internal/data/ent/schema/workflowrun.go | 1 + app/controlplane/internal/data/workflow.go | 1 + .../internal/dispatcher/dispatcher.go | 2 +- .../internal/service/attestation.go | 4 +- .../internal/service/workflowrun.go | 4 +- 11 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 app/controlplane/internal/data/ent/migrate/migrations/20230914221336.sql diff --git a/app/controlplane/internal/biz/workflow.go b/app/controlplane/internal/biz/workflow.go index c6f4deb9b..599994f65 100644 --- a/app/controlplane/internal/biz/workflow.go +++ b/app/controlplane/internal/biz/workflow.go @@ -49,6 +49,9 @@ type WorkflowRepo interface { type CreateOpts struct { Name, OrgID, Project, Team, ContractID string + // Public means that the associated workflow runs, attestations and materials + // are reachable by other users, regardless of their organization + Public bool } type WorkflowUseCase struct { diff --git a/app/controlplane/internal/biz/workflowrun.go b/app/controlplane/internal/biz/workflowrun.go index 65013fb93..8283e0d1a 100644 --- a/app/controlplane/internal/biz/workflowrun.go +++ b/app/controlplane/internal/biz/workflowrun.go @@ -26,7 +26,6 @@ import ( "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/go-kratos/kratos/v2/log" - cr_v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/uuid" ) @@ -249,7 +248,8 @@ func (uc *WorkflowRunUseCase) List(ctx context.Context, orgID, workflowID string return uc.wfRunRepo.List(ctx, orgUUID, workflowUUID, p) } -func (uc *WorkflowRunUseCase) GetByID(ctx context.Context, orgID, runID string) (*WorkflowRun, error) { +// Returns the workflow run with the provided ID if it belongs to the org or its public +func (uc *WorkflowRunUseCase) GetByIDInOrgOrPublic(ctx context.Context, orgID, runID string) (*WorkflowRun, error) { orgUUID, err := uuid.Parse(orgID) if err != nil { return nil, NewErrInvalidUUID(err) @@ -269,13 +269,13 @@ func (uc *WorkflowRunUseCase) GetByID(ctx context.Context, orgID, runID string) return workflowRunInOrgOrPublic(wfrun, orgUUID) } -func (uc *WorkflowRunUseCase) GetByDigest(ctx context.Context, orgID, digest string) (*WorkflowRun, error) { +func (uc *WorkflowRunUseCase) GetByDigestInOrgOrPublic(ctx context.Context, orgID, digest string) (*WorkflowRun, error) { orgUUID, err := uuid.Parse(orgID) if err != nil { return nil, NewErrInvalidUUID(err) } - if _, err := cr_v1.NewHash(digest); err != nil { + if _, err := v1.NewHash(digest); err != nil { return nil, NewErrValidation(fmt.Errorf("invalid digest format: %w", err)) } diff --git a/app/controlplane/internal/biz/workflowrun_integration_test.go b/app/controlplane/internal/biz/workflowrun_integration_test.go index a518b0ad2..6a8928d4f 100644 --- a/app/controlplane/internal/biz/workflowrun_integration_test.go +++ b/app/controlplane/internal/biz/workflowrun_integration_test.go @@ -46,7 +46,7 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() { s.T().Run("valid workflowRun", func(t *testing.T) { run, err := s.WorkflowRun.Create(ctx, &biz.WorkflowRunCreateOpts{ - WorkflowID: s.workflow.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, + WorkflowID: s.workflowOrg1.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, }) assert.NoError(err) @@ -54,14 +54,14 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() { assert.NoError(err) // Retrieve attestation ref from storage and compare - r, err := s.WorkflowRun.GetByID(ctx, s.org.ID, run.ID.String()) + r, err := s.WorkflowRun.GetByIDInOrgOrPublic(ctx, s.org.ID, run.ID.String()) assert.NoError(err) assert.Equal(r.Attestation, &biz.Attestation{Envelope: validEnvelope, Digest: validDigest}) }) s.T().Run("valid workflowRun attestation not stored in CAS", func(t *testing.T) { run, err := s.WorkflowRun.Create(ctx, &biz.WorkflowRunCreateOpts{ - WorkflowID: s.workflow.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, + WorkflowID: s.workflowOrg1.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, }) assert.NoError(err) @@ -69,25 +69,72 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() { assert.NoError(err) // Retrieve attestation ref from storage and compare - r, err := s.WorkflowRun.GetByID(ctx, s.org.ID, run.ID.String()) + r, err := s.WorkflowRun.GetByIDInOrgOrPublic(ctx, s.org.ID, run.ID.String()) assert.NoError(err) assert.Equal(r.Attestation, &biz.Attestation{Envelope: validEnvelope, Digest: ""}) }) } +func (s *workflowRunIntegrationTestSuite) TestGetByIDInOrgOrPublic() { + assert := assert.New(s.T()) + ctx := context.Background() + testCases := []struct { + name string + orgID string + runID string + wantErr bool + }{ + { + name: "non existing workflowRun", + orgID: s.org.ID, + runID: uuid.NewString(), + wantErr: true, + }, + { + name: "existing workflowRun in org1", + orgID: s.org.ID, + runID: s.runOrg1.ID.String(), + }, + { + name: "can't access workflowRun from other org", + orgID: s.org.ID, + runID: s.runOrg2.ID.String(), + wantErr: true, + }, + { + name: "can access workflowRun from other org if public", + orgID: s.org.ID, + runID: s.runOrg2Public.ID.String(), + }, + } + + for _, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + run, err := s.WorkflowRun.GetByIDInOrgOrPublic(ctx, tc.orgID, tc.runID) + if tc.wantErr { + assert.Error(err) + assert.True(biz.IsNotFound(err)) + } else { + assert.NoError(err) + assert.Equal(tc.runID, run.ID.String()) + } + }) + } +} + func (s *workflowRunIntegrationTestSuite) TestCreate() { assert := assert.New(s.T()) ctx := context.Background() s.T().Run("valid workflowRun", func(t *testing.T) { run, err := s.WorkflowRun.Create(ctx, &biz.WorkflowRunCreateOpts{ - WorkflowID: s.workflow.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, + WorkflowID: s.workflowOrg1.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, RunnerType: "runnerType", RunnerRunURL: "runURL", }) assert.NoError(err) if diff := cmp.Diff(&biz.WorkflowRun{ RunnerType: "runnerType", RunURL: "runURL", State: string(biz.WorkflowRunInitialized), ContractVersionID: s.contractVersion.Version.ID, - Workflow: s.workflow, + Workflow: s.workflowOrg1, CASBackends: []*biz.CASBackend{s.casBackend}, }, run, cmpopts.IgnoreFields(biz.WorkflowRun{}, "CreatedAt", "ID", "Workflow"), @@ -106,11 +153,12 @@ func TestWorkflowRunUseCase(t *testing.T) { // Utility struct to hold the test suite type workflowRunIntegrationTestSuite struct { testhelpers.UseCasesEachTestSuite - org *biz.Organization - casBackend *biz.CASBackend - workflow *biz.Workflow - robotAccount *biz.RobotAccount - contractVersion *biz.WorkflowContractWithVersion + org, org2 *biz.Organization + casBackend *biz.CASBackend + workflowOrg1, workflowOrg2, workflowPublicOrg2 *biz.Workflow + runOrg1, runOrg2, runOrg2Public *biz.WorkflowRun + robotAccount *biz.RobotAccount + contractVersion *biz.WorkflowContractWithVersion } func (s *workflowRunIntegrationTestSuite) SetupTest() { @@ -127,19 +175,43 @@ func (s *workflowRunIntegrationTestSuite) SetupTest() { s.org, err = s.Organization.Create(ctx, "testing org") assert.NoError(err) + s.org2, err = s.Organization.Create(ctx, "second org") + assert.NoError(err) // Workflow - s.workflow, err = s.Workflow.Create(ctx, &biz.CreateOpts{Name: "test workflow", OrgID: s.org.ID}) + s.workflowOrg1, err = s.Workflow.Create(ctx, &biz.CreateOpts{Name: "test workflow", OrgID: s.org.ID}) + assert.NoError(err) + s.workflowOrg2, err = s.Workflow.Create(ctx, &biz.CreateOpts{Name: "test workflow", OrgID: s.org2.ID}) + assert.NoError(err) + // Public workflow + s.workflowPublicOrg2, err = s.Workflow.Create(ctx, &biz.CreateOpts{Name: "test public workflow", OrgID: s.org2.ID, Public: true}) assert.NoError(err) // Robot account - s.robotAccount, err = s.RobotAccount.Create(ctx, "name", s.org.ID, s.workflow.ID.String()) + s.robotAccount, err = s.RobotAccount.Create(ctx, "name", s.org.ID, s.workflowOrg1.ID.String()) assert.NoError(err) // Find contract revision - s.contractVersion, err = s.WorkflowContract.Describe(ctx, s.org.ID, s.workflow.ContractID.String(), 0) + s.contractVersion, err = s.WorkflowContract.Describe(ctx, s.org.ID, s.workflowOrg1.ContractID.String(), 0) assert.NoError(err) s.casBackend, err = s.CASBackend.CreateOrUpdate(ctx, s.org.ID, "repo", "username", "pass", biz.CASBackendOCI, true) assert.NoError(err) + + // Let's create 2 runs, one in org1 and one in org2 + s.runOrg1, err = s.WorkflowRun.Create(ctx, + &biz.WorkflowRunCreateOpts{ + WorkflowID: s.workflowOrg1.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, + }) + assert.NoError(err) + s.runOrg2, err = s.WorkflowRun.Create(ctx, + &biz.WorkflowRunCreateOpts{ + WorkflowID: s.workflowOrg2.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, + }) + assert.NoError(err) + s.runOrg2Public, err = s.WorkflowRun.Create(ctx, + &biz.WorkflowRunCreateOpts{ + WorkflowID: s.workflowPublicOrg2.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, + }) + assert.NoError(err) } diff --git a/app/controlplane/internal/data/ent/migrate/migrations/20230914221336.sql b/app/controlplane/internal/data/ent/migrate/migrations/20230914221336.sql new file mode 100644 index 000000000..446866e0a --- /dev/null +++ b/app/controlplane/internal/data/ent/migrate/migrations/20230914221336.sql @@ -0,0 +1,2 @@ +-- Create index "workflowrun_attestation_digest" to table: "workflow_runs" +CREATE INDEX "workflowrun_attestation_digest" ON "workflow_runs" ("attestation_digest"); diff --git a/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum b/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum index b3c1815f0..455600922 100644 --- a/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:TnjHxZ66ux8YY8EtEqGaCK31/HXMMp265YEaUBwBBvE= +h1:G+LKYj/Bqo1YsBY1/Rx0Qp1OHPzxKuyGFO7hTRXKpVo= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -8,3 +8,4 @@ h1:TnjHxZ66ux8YY8EtEqGaCK31/HXMMp265YEaUBwBBvE= 20230904113722.sql h1:ZHM0s2DlzMbdU+0hA1HDxUEtKFxm1WXcQDxmBfBxIAQ= 20230904210324.sql h1:oF5XG1s8WxAwDrdS+36J3Ygkx1vj++d1xpJCtPxTFs4= 20230905084357.sql h1:VNLRcY8vRDq5WoHv6JqBMr8HCkxLxr0LFWQzvqVRTYk= +20230914221336.sql h1:MCsBIxQ6Ow1BEhCNEF0QfAkUJxPSPxJ4l5DyAOuKLlc= diff --git a/app/controlplane/internal/data/ent/migrate/schema.go b/app/controlplane/internal/data/ent/migrate/schema.go index 4247ad2de..3ce5be49e 100644 --- a/app/controlplane/internal/data/ent/migrate/schema.go +++ b/app/controlplane/internal/data/ent/migrate/schema.go @@ -343,6 +343,11 @@ var ( Unique: false, Columns: []*schema.Column{WorkflowRunsColumns[1], WorkflowRunsColumns[3]}, }, + { + Name: "workflowrun_attestation_digest", + Unique: false, + Columns: []*schema.Column{WorkflowRunsColumns[8]}, + }, }, } // WorkflowRunCasBackendsColumns holds the columns for the "workflow_run_cas_backends" table. diff --git a/app/controlplane/internal/data/ent/schema/workflowrun.go b/app/controlplane/internal/data/ent/schema/workflowrun.go index bb20d751b..d264040fa 100644 --- a/app/controlplane/internal/data/ent/schema/workflowrun.go +++ b/app/controlplane/internal/data/ent/schema/workflowrun.go @@ -74,5 +74,6 @@ func (WorkflowRun) Indexes() []ent.Index { index.Fields("created_at", "id"), // Expiration job index.Fields("created_at", "state"), + index.Fields("attestation_digest"), } } diff --git a/app/controlplane/internal/data/workflow.go b/app/controlplane/internal/data/workflow.go index af1710579..888e4d4cc 100644 --- a/app/controlplane/internal/data/workflow.go +++ b/app/controlplane/internal/data/workflow.go @@ -55,6 +55,7 @@ func (r *WorkflowRepo) Create(ctx context.Context, opts *biz.CreateOpts) (*biz.W SetName(opts.Name). SetProject(opts.Project). SetTeam(opts.Team). + SetPublic(opts.Public). SetName(opts.Name). SetContractID(contractUUID). SetOrganizationID(orgUUID). diff --git a/app/controlplane/internal/dispatcher/dispatcher.go b/app/controlplane/internal/dispatcher/dispatcher.go index 38711282f..d7007c993 100644 --- a/app/controlplane/internal/dispatcher/dispatcher.go +++ b/app/controlplane/internal/dispatcher/dispatcher.go @@ -102,7 +102,7 @@ func (d *FanOutDispatcher) Run(ctx context.Context, opts *RunOpts) error { return fmt.Errorf("workflow not found") } - wfRun, err := d.wfRunUC.GetByID(ctx, opts.OrgID, opts.WorkflowRunID) + wfRun, err := d.wfRunUC.GetByIDInOrgOrPublic(ctx, opts.OrgID, opts.WorkflowRunID) if err != nil { return fmt.Errorf("finding workflow: %w", err) } else if wfRun == nil { diff --git a/app/controlplane/internal/service/attestation.go b/app/controlplane/internal/service/attestation.go index 6b8c0893c..552ad9f09 100644 --- a/app/controlplane/internal/service/attestation.go +++ b/app/controlplane/internal/service/attestation.go @@ -175,7 +175,7 @@ func (s *AttestationService) Store(ctx context.Context, req *cpAPI.AttestationSe return nil, sl.LogAndMaskErr(err, s.log) } - wRun, err := s.wrUseCase.GetByID(ctx, robotAccount.OrgID, req.WorkflowRunId) + wRun, err := s.wrUseCase.GetByIDInOrgOrPublic(ctx, robotAccount.OrgID, req.WorkflowRunId) if err != nil { return nil, sl.LogAndMaskErr(err, s.log) } else if wRun == nil { @@ -310,7 +310,7 @@ func (s *AttestationService) GetUploadCreds(ctx context.Context, req *cpAPI.Atte } } else { // This is the new mode, where the CAS backend ref is stored in the workflow run since initialization - wRun, err := s.wrUseCase.GetByID(ctx, robotAccount.OrgID, req.WorkflowRunId) + wRun, err := s.wrUseCase.GetByIDInOrgOrPublic(ctx, robotAccount.OrgID, req.WorkflowRunId) if err != nil { return nil, sl.LogAndMaskErr(err, s.log) } else if wRun == nil { diff --git a/app/controlplane/internal/service/workflowrun.go b/app/controlplane/internal/service/workflowrun.go index 54426c8ed..23ba1e38d 100644 --- a/app/controlplane/internal/service/workflowrun.go +++ b/app/controlplane/internal/service/workflowrun.go @@ -107,12 +107,12 @@ func (s *WorkflowRunService) View(ctx context.Context, req *pb.WorkflowRunServic // retrieve the workflow run either by ID or by digest var run *biz.WorkflowRun if req.GetId() != "" { - run, err = s.wrUseCase.GetByID(ctx, currentOrg.ID, req.GetId()) + run, err = s.wrUseCase.GetByIDInOrgOrPublic(ctx, currentOrg.ID, req.GetId()) if err != nil { return nil, handleUseCaseErr(workflowRunEntity, err, s.log) } } else if req.GetDigest() != "" { - run, err = s.wrUseCase.GetByDigest(ctx, currentOrg.ID, req.GetDigest()) + run, err = s.wrUseCase.GetByDigestInOrgOrPublic(ctx, currentOrg.ID, req.GetDigest()) if err != nil { return nil, handleUseCaseErr(workflowRunEntity, err, s.log) } From 2dfcde28e7d79835e83c7cf76a891239b1924ba3 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Trivino Date: Fri, 15 Sep 2023 10:04:01 +0200 Subject: [PATCH 3/3] chore: add tests Signed-off-by: Miguel Martinez Trivino --- .../biz/workflowrun_integration_test.go | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/app/controlplane/internal/biz/workflowrun_integration_test.go b/app/controlplane/internal/biz/workflowrun_integration_test.go index 6a8928d4f..f598bf353 100644 --- a/app/controlplane/internal/biz/workflowrun_integration_test.go +++ b/app/controlplane/internal/biz/workflowrun_integration_test.go @@ -122,6 +122,59 @@ func (s *workflowRunIntegrationTestSuite) TestGetByIDInOrgOrPublic() { } } +func (s *workflowRunIntegrationTestSuite) TestGetByDigestInOrgOrPublic() { + assert := assert.New(s.T()) + ctx := context.Background() + testCases := []struct { + name string + orgID string + digest string + errTypeChecker func(err error) bool + }{ + { + name: "non existing workflowRun", + orgID: s.org.ID, + digest: "sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c", + errTypeChecker: biz.IsNotFound, + }, + { + name: "invalid digest", + orgID: s.org.ID, + digest: "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c", + errTypeChecker: biz.IsErrValidation, + }, + { + name: "existing workflowRun in org1", + orgID: s.org.ID, + digest: validDigest, + }, + { + name: "can't access workflowRun from other org", + orgID: s.org.ID, + digest: validDigest2, + errTypeChecker: biz.IsNotFound, + }, + { + name: "can access workflowRun from other org if public", + orgID: s.org.ID, + digest: validDigest3, + }, + } + + for _, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + run, err := s.WorkflowRun.GetByDigestInOrgOrPublic(ctx, tc.orgID, tc.digest) + if tc.errTypeChecker != nil { + assert.Error(err) + assert.True(tc.errTypeChecker(err)) + } else { + assert.NoError(err) + assert.Equal(tc.digest, run.Attestation.Digest) + } + }) + } +} + func (s *workflowRunIntegrationTestSuite) TestCreate() { assert := assert.New(s.T()) ctx := context.Background() @@ -198,20 +251,25 @@ func (s *workflowRunIntegrationTestSuite) SetupTest() { s.casBackend, err = s.CASBackend.CreateOrUpdate(ctx, s.org.ID, "repo", "username", "pass", biz.CASBackendOCI, true) assert.NoError(err) - // Let's create 2 runs, one in org1 and one in org2 + // Let's create 3 runs, one in org1 and 2 in org2 (one public) s.runOrg1, err = s.WorkflowRun.Create(ctx, &biz.WorkflowRunCreateOpts{ WorkflowID: s.workflowOrg1.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, }) assert.NoError(err) + assert.NoError(s.WorkflowRun.SaveAttestation(ctx, s.runOrg1.ID.String(), &dsse.Envelope{}, validDigest)) + s.runOrg2, err = s.WorkflowRun.Create(ctx, &biz.WorkflowRunCreateOpts{ WorkflowID: s.workflowOrg2.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, }) assert.NoError(err) + assert.NoError(s.WorkflowRun.SaveAttestation(ctx, s.runOrg2.ID.String(), &dsse.Envelope{}, validDigest2)) + s.runOrg2Public, err = s.WorkflowRun.Create(ctx, &biz.WorkflowRunCreateOpts{ WorkflowID: s.workflowPublicOrg2.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevisionUUID: s.contractVersion.Version.ID, CASBackendID: s.casBackend.ID, }) assert.NoError(err) + assert.NoError(s.WorkflowRun.SaveAttestation(ctx, s.runOrg2Public.ID.String(), &dsse.Envelope{}, validDigest3)) }