diff --git a/app/cli/cmd/casbackend.go b/app/cli/cmd/casbackend.go index dfa818000..f81cdabab 100644 --- a/app/cli/cmd/casbackend.go +++ b/app/cli/cmd/casbackend.go @@ -25,6 +25,19 @@ func newCASBackendCmd() *cobra.Command { Short: "Operations on Artifact CAS backends", } - cmd.AddCommand(newCASBackendListCmd()) + cmd.AddCommand(newCASBackendListCmd(), newCASBackendAddCmd()) + return cmd +} + +func newCASBackendAddCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: "Add a new Artifact CAS backend", + } + + cmd.PersistentFlags().Bool("default", false, "set the backend as default in your organization") + cmd.PersistentFlags().String("description", "", "descriptive information for this registration") + + cmd.AddCommand(newCASBackendAddOCICmd()) return cmd } diff --git a/app/cli/cmd/casbackend_add_oci.go b/app/cli/cmd/casbackend_add_oci.go new file mode 100644 index 000000000..e2f293014 --- /dev/null +++ b/app/cli/cmd/casbackend_add_oci.go @@ -0,0 +1,109 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + + "github.com/chainloop-dev/chainloop/app/cli/internal/action" + "github.com/spf13/cobra" +) + +func newCASBackendAddOCICmd() *cobra.Command { + var repo, username, password string + cmd := &cobra.Command{ + Use: "oci", + Short: "Register a OCI CAS Backend", + RunE: func(cmd *cobra.Command, args []string) error { + // If we are setting the default, we list existing CAS backends + // and ask the user to confirm the rewrite + isDefault, err := cmd.Flags().GetBool("default") + cobra.CheckErr(err) + + description, err := cmd.Flags().GetString("description") + cobra.CheckErr(err) + + if isDefault { + if confirmed, err := confirmDefaultCASBackendOverride(actionOpts); err != nil { + return err + } else if !confirmed { + fmt.Println("Aborting...") + } + } + + opts := &action.NewCASBackendOCIAddOpts{ + Repo: repo, Username: username, Password: password, Default: isDefault, Description: description, + } + + res, err := action.NewCASBackendAddOCI(actionOpts).Run(opts) + if err != nil { + return err + } else if res == nil { + return nil + } + + return encodeOutput([]*action.CASBackendItem{res}, casBackendListTableOutput) + }, + } + + cmd.Flags().StringVar(&repo, "repo", "", "FQDN repository name, including path") + err := cmd.MarkFlagRequired("repo") + cobra.CheckErr(err) + + cmd.Flags().StringVarP(&username, "username", "u", "", "registry username") + err = cmd.MarkFlagRequired("username") + cobra.CheckErr(err) + + cmd.Flags().StringVarP(&password, "password", "p", "", "registry password") + err = cmd.MarkFlagRequired("password") + cobra.CheckErr(err) + return cmd +} + +// confirmDefaultCASBackendOverride asks the user to confirm the override of the default CAS backend +// in the event that there is one already set. +func confirmDefaultCASBackendOverride(actionOpts *action.ActionsOpts) (bool, error) { + // get existing backends + backends, err := action.NewCASBackendList(actionOpts).Run() + if err != nil { + return false, fmt.Errorf("failed to list existing CAS backends: %w", err) + } + + var hasDefault bool + for _, b := range backends { + if b.Default { + hasDefault = true + break + } + } + + // If there is none, we are done + if !hasDefault { + return true, nil + } + + // Ask the user to confirm the override + fmt.Println("There is already a default CAS backend in your organization.\nPlease confirm to override y/N: ") + var gotChallenge string + fmt.Scanln(&gotChallenge) + + // If the user does not confirm, we are done + if gotChallenge != "y" && gotChallenge != "Y" { + return false, nil + } + + return true, nil +} diff --git a/app/cli/cmd/casbackend_list.go b/app/cli/cmd/casbackend_list.go index c3e92a452..b0d4ea2f6 100644 --- a/app/cli/cmd/casbackend_list.go +++ b/app/cli/cmd/casbackend_list.go @@ -50,14 +50,14 @@ func casBackendListTableOutput(backends []*action.CASBackendItem) error { } t := newTableWriter() - header := table.Row{"ID", "Name", "Provider", "Default"} + header := table.Row{"ID", "Location", "Provider", "Description", "Default"} if full { header = append(header, "Validation Status", "Created At", "Validated At") } t.AppendHeader(header) for _, b := range backends { - r := table.Row{b.ID, b.Name, b.Provider, b.Default} + r := table.Row{b.ID, b.Location, b.Provider, b.Description, b.Default} if full { r = append(r, b.ValidationStatus, b.CreatedAt.Format(time.RFC822), diff --git a/app/cli/internal/action/casbackend_add_oci.go b/app/cli/internal/action/casbackend_add_oci.go new file mode 100644 index 000000000..f9832e06c --- /dev/null +++ b/app/cli/internal/action/casbackend_add_oci.go @@ -0,0 +1,63 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package action + +import ( + "context" + "fmt" + + pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" + "google.golang.org/protobuf/types/known/structpb" +) + +type CASBackendAddOCI struct { + cfg *ActionsOpts +} + +type NewCASBackendOCIAddOpts struct { + Repo, Username, Password string + Description string + Default bool +} + +func NewCASBackendAddOCI(cfg *ActionsOpts) *CASBackendAddOCI { + return &CASBackendAddOCI{cfg} +} + +func (action *CASBackendAddOCI) Run(opts *NewCASBackendOCIAddOpts) (*CASBackendItem, error) { + // Custom configuration for OCI + credentials, err := structpb.NewStruct(map[string]any{ + "username": opts.Username, + "password": opts.Password, + }) + if err != nil { + return nil, fmt.Errorf("failed to parse arguments: %w", err) + } + + client := pb.NewCASBackendServiceClient(action.cfg.CPConnection) + resp, err := client.Create(context.Background(), &pb.CASBackendServiceCreateRequest{ + Location: opts.Repo, + Provider: "OCI", + Description: opts.Description, + Default: opts.Default, + Credentials: credentials, + }) + if err != nil { + return nil, err + } + + return pbCASBackendItemToAction(resp.Result), nil +} diff --git a/app/cli/internal/action/casbackend_list.go b/app/cli/internal/action/casbackend_list.go index f6d034626..d592a94f7 100644 --- a/app/cli/internal/action/casbackend_list.go +++ b/app/cli/internal/action/casbackend_list.go @@ -28,7 +28,8 @@ type CASBackendList struct { type CASBackendItem struct { ID string `json:"id"` - Name string `json:"name"` + Location string `json:"location"` + Description string `json:"description"` Provider string `json:"provider"` Default bool `json:"default"` ValidationStatus ValidationStatus `json:"validationStatus"` @@ -70,7 +71,8 @@ func pbCASBackendItemToAction(in *pb.CASBackendItem) *CASBackendItem { b := &CASBackendItem{ ID: in.Id, - Name: in.Name, + Location: in.Location, + Description: in.Description, Provider: in.Provider, Default: in.Default, CreatedAt: toTimePtr(in.CreatedAt.AsTime()), diff --git a/app/controlplane/api/controlplane/v1/cas_backends.pb.go b/app/controlplane/api/controlplane/v1/cas_backends.pb.go index 2f5258ce6..ba6da5f7f 100644 --- a/app/controlplane/api/controlplane/v1/cas_backends.pb.go +++ b/app/controlplane/api/controlplane/v1/cas_backends.pb.go @@ -22,8 +22,10 @@ package v1 import ( + _ "github.com/envoyproxy/protoc-gen-validate/validate" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" ) @@ -120,6 +122,137 @@ func (x *CASBackendServiceListResponse) GetResult() []*CASBackendItem { return nil } +type CASBackendServiceCreateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Location, e.g. bucket name, OCI bucket name, ... + Location string `protobuf:"bytes,1,opt,name=location,proto3" json:"location,omitempty"` + // Type of the backend, OCI, S3, ... + Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"` + // Descriptive name + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // Set as default in your organization + Default bool `protobuf:"varint,4,opt,name=default,proto3" json:"default,omitempty"` + // Arbitrary configuration for the integration + Credentials *structpb.Struct `protobuf:"bytes,5,opt,name=credentials,proto3" json:"credentials,omitempty"` +} + +func (x *CASBackendServiceCreateRequest) Reset() { + *x = CASBackendServiceCreateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_cas_backends_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CASBackendServiceCreateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CASBackendServiceCreateRequest) ProtoMessage() {} + +func (x *CASBackendServiceCreateRequest) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_cas_backends_proto_msgTypes[2] + 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 CASBackendServiceCreateRequest.ProtoReflect.Descriptor instead. +func (*CASBackendServiceCreateRequest) Descriptor() ([]byte, []int) { + return file_controlplane_v1_cas_backends_proto_rawDescGZIP(), []int{2} +} + +func (x *CASBackendServiceCreateRequest) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *CASBackendServiceCreateRequest) GetProvider() string { + if x != nil { + return x.Provider + } + return "" +} + +func (x *CASBackendServiceCreateRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *CASBackendServiceCreateRequest) GetDefault() bool { + if x != nil { + return x.Default + } + return false +} + +func (x *CASBackendServiceCreateRequest) GetCredentials() *structpb.Struct { + if x != nil { + return x.Credentials + } + return nil +} + +type CASBackendServiceCreateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *CASBackendItem `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` +} + +func (x *CASBackendServiceCreateResponse) Reset() { + *x = CASBackendServiceCreateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_cas_backends_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CASBackendServiceCreateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CASBackendServiceCreateResponse) ProtoMessage() {} + +func (x *CASBackendServiceCreateResponse) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_cas_backends_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 CASBackendServiceCreateResponse.ProtoReflect.Descriptor instead. +func (*CASBackendServiceCreateResponse) Descriptor() ([]byte, []int) { + return file_controlplane_v1_cas_backends_proto_rawDescGZIP(), []int{3} +} + +func (x *CASBackendServiceCreateResponse) GetResult() *CASBackendItem { + if x != nil { + return x.Result + } + return nil +} + var File_controlplane_v1_cas_backends_proto protoreflect.FileDescriptor var file_controlplane_v1_cas_backends_proto_rawDesc = []byte{ @@ -128,28 +261,59 @@ var file_controlplane_v1_cas_backends_proto_rawDesc = []byte{ 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e, - 0x0a, 0x1c, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x58, - 0x0a, 0x1d, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x37, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x03, 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, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0x7a, 0x0a, 0x11, 0x43, 0x41, 0x53, 0x42, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x65, 0x0a, - 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2d, 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, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 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, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 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, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e, 0x0a, 0x1c, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, + 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x58, 0x0a, 0x1d, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, + 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x18, 0x01, 0x20, 0x03, 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, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0xeb, 0x01, 0x0a, 0x1e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x23, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, + 0x10, 0x01, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x43, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x5a, 0x0a, + 0x1f, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x37, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 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, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0xe7, 0x01, 0x0a, 0x11, 0x43, 0x41, + 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x65, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2d, 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, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 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, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x12, 0x2f, 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, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 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, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 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 ( @@ -164,21 +328,28 @@ func file_controlplane_v1_cas_backends_proto_rawDescGZIP() []byte { return file_controlplane_v1_cas_backends_proto_rawDescData } -var file_controlplane_v1_cas_backends_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_controlplane_v1_cas_backends_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_controlplane_v1_cas_backends_proto_goTypes = []interface{}{ - (*CASBackendServiceListRequest)(nil), // 0: controlplane.v1.CASBackendServiceListRequest - (*CASBackendServiceListResponse)(nil), // 1: controlplane.v1.CASBackendServiceListResponse - (*CASBackendItem)(nil), // 2: controlplane.v1.CASBackendItem + (*CASBackendServiceListRequest)(nil), // 0: controlplane.v1.CASBackendServiceListRequest + (*CASBackendServiceListResponse)(nil), // 1: controlplane.v1.CASBackendServiceListResponse + (*CASBackendServiceCreateRequest)(nil), // 2: controlplane.v1.CASBackendServiceCreateRequest + (*CASBackendServiceCreateResponse)(nil), // 3: controlplane.v1.CASBackendServiceCreateResponse + (*CASBackendItem)(nil), // 4: controlplane.v1.CASBackendItem + (*structpb.Struct)(nil), // 5: google.protobuf.Struct } var file_controlplane_v1_cas_backends_proto_depIdxs = []int32{ - 2, // 0: controlplane.v1.CASBackendServiceListResponse.result:type_name -> controlplane.v1.CASBackendItem - 0, // 1: controlplane.v1.CASBackendService.List:input_type -> controlplane.v1.CASBackendServiceListRequest - 1, // 2: controlplane.v1.CASBackendService.List:output_type -> controlplane.v1.CASBackendServiceListResponse - 2, // [2:3] is the sub-list for method output_type - 1, // [1:2] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 4, // 0: controlplane.v1.CASBackendServiceListResponse.result:type_name -> controlplane.v1.CASBackendItem + 5, // 1: controlplane.v1.CASBackendServiceCreateRequest.credentials:type_name -> google.protobuf.Struct + 4, // 2: controlplane.v1.CASBackendServiceCreateResponse.result:type_name -> controlplane.v1.CASBackendItem + 0, // 3: controlplane.v1.CASBackendService.List:input_type -> controlplane.v1.CASBackendServiceListRequest + 2, // 4: controlplane.v1.CASBackendService.Create:input_type -> controlplane.v1.CASBackendServiceCreateRequest + 1, // 5: controlplane.v1.CASBackendService.List:output_type -> controlplane.v1.CASBackendServiceListResponse + 3, // 6: controlplane.v1.CASBackendService.Create:output_type -> controlplane.v1.CASBackendServiceCreateResponse + 5, // [5:7] is the sub-list for method output_type + 3, // [3:5] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_controlplane_v1_cas_backends_proto_init() } @@ -212,6 +383,30 @@ func file_controlplane_v1_cas_backends_proto_init() { return nil } } + file_controlplane_v1_cas_backends_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CASBackendServiceCreateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_cas_backends_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CASBackendServiceCreateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -219,7 +414,7 @@ func file_controlplane_v1_cas_backends_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controlplane_v1_cas_backends_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 1, }, diff --git a/app/controlplane/api/controlplane/v1/cas_backends.pb.validate.go b/app/controlplane/api/controlplane/v1/cas_backends.pb.validate.go index 5146d4455..5ecf1fa71 100644 --- a/app/controlplane/api/controlplane/v1/cas_backends.pb.validate.go +++ b/app/controlplane/api/controlplane/v1/cas_backends.pb.validate.go @@ -274,3 +274,304 @@ var _ interface { Cause() error ErrorName() string } = CASBackendServiceListResponseValidationError{} + +// Validate checks the field values on CASBackendServiceCreateRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *CASBackendServiceCreateRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on CASBackendServiceCreateRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// CASBackendServiceCreateRequestMultiError, or nil if none found. +func (m *CASBackendServiceCreateRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *CASBackendServiceCreateRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetLocation()) < 1 { + err := CASBackendServiceCreateRequestValidationError{ + field: "Location", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if utf8.RuneCountInString(m.GetProvider()) < 1 { + err := CASBackendServiceCreateRequestValidationError{ + field: "Provider", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + // no validation rules for Description + + // no validation rules for Default + + if m.GetCredentials() == nil { + err := CASBackendServiceCreateRequestValidationError{ + field: "Credentials", + reason: "value is required", + } + if !all { + return err + } + errors = append(errors, err) + } + + if all { + switch v := interface{}(m.GetCredentials()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CASBackendServiceCreateRequestValidationError{ + field: "Credentials", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CASBackendServiceCreateRequestValidationError{ + field: "Credentials", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCredentials()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CASBackendServiceCreateRequestValidationError{ + field: "Credentials", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return CASBackendServiceCreateRequestMultiError(errors) + } + + return nil +} + +// CASBackendServiceCreateRequestMultiError is an error wrapping multiple +// validation errors returned by CASBackendServiceCreateRequest.ValidateAll() +// if the designated constraints aren't met. +type CASBackendServiceCreateRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m CASBackendServiceCreateRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m CASBackendServiceCreateRequestMultiError) AllErrors() []error { return m } + +// CASBackendServiceCreateRequestValidationError is the validation error +// returned by CASBackendServiceCreateRequest.Validate if the designated +// constraints aren't met. +type CASBackendServiceCreateRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e CASBackendServiceCreateRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e CASBackendServiceCreateRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e CASBackendServiceCreateRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e CASBackendServiceCreateRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e CASBackendServiceCreateRequestValidationError) ErrorName() string { + return "CASBackendServiceCreateRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e CASBackendServiceCreateRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCASBackendServiceCreateRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = CASBackendServiceCreateRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = CASBackendServiceCreateRequestValidationError{} + +// Validate checks the field values on CASBackendServiceCreateResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *CASBackendServiceCreateResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on CASBackendServiceCreateResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// CASBackendServiceCreateResponseMultiError, or nil if none found. +func (m *CASBackendServiceCreateResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *CASBackendServiceCreateResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetResult()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CASBackendServiceCreateResponseValidationError{ + field: "Result", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CASBackendServiceCreateResponseValidationError{ + field: "Result", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetResult()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CASBackendServiceCreateResponseValidationError{ + field: "Result", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return CASBackendServiceCreateResponseMultiError(errors) + } + + return nil +} + +// CASBackendServiceCreateResponseMultiError is an error wrapping multiple +// validation errors returned by CASBackendServiceCreateResponse.ValidateAll() +// if the designated constraints aren't met. +type CASBackendServiceCreateResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m CASBackendServiceCreateResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m CASBackendServiceCreateResponseMultiError) AllErrors() []error { return m } + +// CASBackendServiceCreateResponseValidationError is the validation error +// returned by CASBackendServiceCreateResponse.Validate if the designated +// constraints aren't met. +type CASBackendServiceCreateResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e CASBackendServiceCreateResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e CASBackendServiceCreateResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e CASBackendServiceCreateResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e CASBackendServiceCreateResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e CASBackendServiceCreateResponseValidationError) ErrorName() string { + return "CASBackendServiceCreateResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e CASBackendServiceCreateResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCASBackendServiceCreateResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = CASBackendServiceCreateResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = CASBackendServiceCreateResponseValidationError{} diff --git a/app/controlplane/api/controlplane/v1/cas_backends.proto b/app/controlplane/api/controlplane/v1/cas_backends.proto index 957fac516..8f45e31e9 100644 --- a/app/controlplane/api/controlplane/v1/cas_backends.proto +++ b/app/controlplane/api/controlplane/v1/cas_backends.proto @@ -20,13 +20,33 @@ package controlplane.v1; option go_package = "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1;v1"; import "controlplane/v1/response_messages.proto"; +import "validate/validate.proto"; +import "google/protobuf/struct.proto"; service CASBackendService { rpc List (CASBackendServiceListRequest) returns (CASBackendServiceListResponse); + rpc Create (CASBackendServiceCreateRequest) returns (CASBackendServiceCreateResponse); } message CASBackendServiceListRequest {} message CASBackendServiceListResponse { repeated CASBackendItem result = 1; +} + +message CASBackendServiceCreateRequest { + // Location, e.g. bucket name, OCI bucket name, ... + string location = 1 [(validate.rules).string.min_len = 1]; + // Type of the backend, OCI, S3, ... + string provider = 2 [(validate.rules).string.min_len = 1]; + // Descriptive name + string description = 3; + // Set as default in your organization + bool default = 4; + // Arbitrary configuration for the integration + google.protobuf.Struct credentials = 5 [(validate.rules).message.required = true]; +} + +message CASBackendServiceCreateResponse { + CASBackendItem result = 1; } \ No newline at end of file diff --git a/app/controlplane/api/controlplane/v1/cas_backends_grpc.pb.go b/app/controlplane/api/controlplane/v1/cas_backends_grpc.pb.go index 9dcda5a72..7ce731e2a 100644 --- a/app/controlplane/api/controlplane/v1/cas_backends_grpc.pb.go +++ b/app/controlplane/api/controlplane/v1/cas_backends_grpc.pb.go @@ -34,7 +34,8 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - CASBackendService_List_FullMethodName = "/controlplane.v1.CASBackendService/List" + CASBackendService_List_FullMethodName = "/controlplane.v1.CASBackendService/List" + CASBackendService_Create_FullMethodName = "/controlplane.v1.CASBackendService/Create" ) // CASBackendServiceClient is the client API for CASBackendService service. @@ -42,6 +43,7 @@ const ( // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type CASBackendServiceClient interface { List(ctx context.Context, in *CASBackendServiceListRequest, opts ...grpc.CallOption) (*CASBackendServiceListResponse, error) + Create(ctx context.Context, in *CASBackendServiceCreateRequest, opts ...grpc.CallOption) (*CASBackendServiceCreateResponse, error) } type cASBackendServiceClient struct { @@ -61,11 +63,21 @@ func (c *cASBackendServiceClient) List(ctx context.Context, in *CASBackendServic return out, nil } +func (c *cASBackendServiceClient) Create(ctx context.Context, in *CASBackendServiceCreateRequest, opts ...grpc.CallOption) (*CASBackendServiceCreateResponse, error) { + out := new(CASBackendServiceCreateResponse) + err := c.cc.Invoke(ctx, CASBackendService_Create_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // CASBackendServiceServer is the server API for CASBackendService service. // All implementations must embed UnimplementedCASBackendServiceServer // for forward compatibility type CASBackendServiceServer interface { List(context.Context, *CASBackendServiceListRequest) (*CASBackendServiceListResponse, error) + Create(context.Context, *CASBackendServiceCreateRequest) (*CASBackendServiceCreateResponse, error) mustEmbedUnimplementedCASBackendServiceServer() } @@ -76,6 +88,9 @@ type UnimplementedCASBackendServiceServer struct { func (UnimplementedCASBackendServiceServer) List(context.Context, *CASBackendServiceListRequest) (*CASBackendServiceListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method List not implemented") } +func (UnimplementedCASBackendServiceServer) Create(context.Context, *CASBackendServiceCreateRequest) (*CASBackendServiceCreateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} func (UnimplementedCASBackendServiceServer) mustEmbedUnimplementedCASBackendServiceServer() {} // UnsafeCASBackendServiceServer may be embedded to opt out of forward compatibility for this service. @@ -107,6 +122,24 @@ func _CASBackendService_List_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _CASBackendService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CASBackendServiceCreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CASBackendServiceServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CASBackendService_Create_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CASBackendServiceServer).Create(ctx, req.(*CASBackendServiceCreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // CASBackendService_ServiceDesc is the grpc.ServiceDesc for CASBackendService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -118,6 +151,10 @@ var CASBackendService_ServiceDesc = grpc.ServiceDesc{ MethodName: "List", Handler: _CASBackendService_List_Handler, }, + { + MethodName: "Create", + Handler: _CASBackendService_Create_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "controlplane/v1/cas_backends.proto", diff --git a/app/controlplane/api/controlplane/v1/response_messages.pb.go b/app/controlplane/api/controlplane/v1/response_messages.pb.go index cb9dbadd1..0e575fe42 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.pb.go +++ b/app/controlplane/api/controlplane/v1/response_messages.pb.go @@ -931,15 +931,17 @@ type CASBackendItem struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - ValidatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=validated_at,json=validatedAt,proto3" json:"validated_at,omitempty"` - ValidationStatus CASBackendItem_ValidationStatus `protobuf:"varint,5,opt,name=validation_status,json=validationStatus,proto3,enum=controlplane.v1.CASBackendItem_ValidationStatus" json:"validation_status,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // e.g. myregistry.io/myrepo s3 bucket and so on + Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + ValidatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=validated_at,json=validatedAt,proto3" json:"validated_at,omitempty"` + ValidationStatus CASBackendItem_ValidationStatus `protobuf:"varint,6,opt,name=validation_status,json=validationStatus,proto3,enum=controlplane.v1.CASBackendItem_ValidationStatus" json:"validation_status,omitempty"` // OCI, S3, ... - Provider string `protobuf:"bytes,6,opt,name=provider,proto3" json:"provider,omitempty"` + Provider string `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"` // Wether it's the default backend in the organization - Default bool `protobuf:"varint,7,opt,name=default,proto3" json:"default,omitempty"` + Default bool `protobuf:"varint,8,opt,name=default,proto3" json:"default,omitempty"` } func (x *CASBackendItem) Reset() { @@ -981,9 +983,16 @@ func (x *CASBackendItem) GetId() string { return "" } -func (x *CASBackendItem) GetName() string { +func (x *CASBackendItem) GetLocation() string { if x != nil { - return x.Name + return x.Location + } + return "" +} + +func (x *CASBackendItem) GetDescription() string { + if x != nil { + return x.Description } return "" } @@ -1298,46 +1307,49 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xb3, + 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xdd, 0x03, 0x0a, 0x0e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x5d, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 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, 0x2e, 0x56, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x10, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x22, 0x6e, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x41, 0x4c, 0x49, - 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, - 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, - 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, - 0x49, 0x44, 0x10, 0x02, 0x2a, 0x60, 0x0a, 0x0e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, - 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, - 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x26, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, - 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, - 0x5f, 0x49, 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x1a, 0x04, 0xb0, 0x45, 0x93, 0x03, - 0x1a, 0x04, 0xa8, 0x45, 0xf4, 0x03, 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, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x5d, 0x0a, 0x11, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 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, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x6e, + 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, + 0x1d, 0x0a, 0x19, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x2a, 0x60, + 0x0a, 0x0e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x26, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4c, 0x49, + 0x53, 0x54, 0x10, 0x01, 0x1a, 0x04, 0xb0, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa8, 0x45, 0xf4, 0x03, + 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 ( diff --git a/app/controlplane/api/controlplane/v1/response_messages.pb.validate.go b/app/controlplane/api/controlplane/v1/response_messages.pb.validate.go index f4574c3da..d0ff02c21 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.pb.validate.go +++ b/app/controlplane/api/controlplane/v1/response_messages.pb.validate.go @@ -1570,7 +1570,9 @@ func (m *CASBackendItem) validate(all bool) error { // no validation rules for Id - // no validation rules for Name + // no validation rules for Location + + // no validation rules for Description if all { switch v := interface{}(m.GetCreatedAt()).(type) { diff --git a/app/controlplane/api/controlplane/v1/response_messages.proto b/app/controlplane/api/controlplane/v1/response_messages.proto index 1dd537f71..79e8e2637 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.proto +++ b/app/controlplane/api/controlplane/v1/response_messages.proto @@ -126,14 +126,16 @@ message OCIRepositoryItem { message CASBackendItem { string id = 1; - string name = 2; - google.protobuf.Timestamp created_at = 3; - google.protobuf.Timestamp validated_at = 4; - ValidationStatus validation_status = 5; + // e.g. myregistry.io/myrepo s3 bucket and so on + string location = 2; + string description = 3; + google.protobuf.Timestamp created_at = 4; + google.protobuf.Timestamp validated_at = 5; + ValidationStatus validation_status = 6; // OCI, S3, ... - string provider = 6; + string provider = 7; // Wether it's the default backend in the organization - bool default = 7; + bool default = 8; enum ValidationStatus { VALIDATION_STATUS_UNSPECIFIED = 0; diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/cas_backends.ts b/app/controlplane/api/gen/frontend/controlplane/v1/cas_backends.ts index eaaf777e3..bf148ad33 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/cas_backends.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/cas_backends.ts @@ -2,6 +2,7 @@ import { grpc } from "@improbable-eng/grpc-web"; import { BrowserHeaders } from "browser-headers"; import _m0 from "protobufjs/minimal"; +import { Struct } from "../../google/protobuf/struct"; import { CASBackendItem } from "./response_messages"; export const protobufPackage = "controlplane.v1"; @@ -13,6 +14,23 @@ export interface CASBackendServiceListResponse { result: CASBackendItem[]; } +export interface CASBackendServiceCreateRequest { + /** Location, e.g. bucket name, OCI bucket name, ... */ + location: string; + /** Type of the backend, OCI, S3, ... */ + provider: string; + /** Descriptive name */ + description: string; + /** Set as default in your organization */ + default: boolean; + /** Arbitrary configuration for the integration */ + credentials?: { [key: string]: any }; +} + +export interface CASBackendServiceCreateResponse { + result?: CASBackendItem; +} + function createBaseCASBackendServiceListRequest(): CASBackendServiceListRequest { return {}; } @@ -119,11 +137,187 @@ export const CASBackendServiceListResponse = { }, }; +function createBaseCASBackendServiceCreateRequest(): CASBackendServiceCreateRequest { + return { location: "", provider: "", description: "", default: false, credentials: undefined }; +} + +export const CASBackendServiceCreateRequest = { + encode(message: CASBackendServiceCreateRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.location !== "") { + writer.uint32(10).string(message.location); + } + if (message.provider !== "") { + writer.uint32(18).string(message.provider); + } + if (message.description !== "") { + writer.uint32(26).string(message.description); + } + if (message.default === true) { + writer.uint32(32).bool(message.default); + } + if (message.credentials !== undefined) { + Struct.encode(Struct.wrap(message.credentials), writer.uint32(42).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): CASBackendServiceCreateRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseCASBackendServiceCreateRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.location = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.provider = reader.string(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.description = reader.string(); + continue; + case 4: + if (tag !== 32) { + break; + } + + message.default = reader.bool(); + continue; + case 5: + if (tag !== 42) { + break; + } + + message.credentials = Struct.unwrap(Struct.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): CASBackendServiceCreateRequest { + return { + location: isSet(object.location) ? String(object.location) : "", + provider: isSet(object.provider) ? String(object.provider) : "", + description: isSet(object.description) ? String(object.description) : "", + default: isSet(object.default) ? Boolean(object.default) : false, + credentials: isObject(object.credentials) ? object.credentials : undefined, + }; + }, + + toJSON(message: CASBackendServiceCreateRequest): unknown { + const obj: any = {}; + message.location !== undefined && (obj.location = message.location); + message.provider !== undefined && (obj.provider = message.provider); + message.description !== undefined && (obj.description = message.description); + message.default !== undefined && (obj.default = message.default); + message.credentials !== undefined && (obj.credentials = message.credentials); + return obj; + }, + + create, I>>(base?: I): CASBackendServiceCreateRequest { + return CASBackendServiceCreateRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): CASBackendServiceCreateRequest { + const message = createBaseCASBackendServiceCreateRequest(); + message.location = object.location ?? ""; + message.provider = object.provider ?? ""; + message.description = object.description ?? ""; + message.default = object.default ?? false; + message.credentials = object.credentials ?? undefined; + return message; + }, +}; + +function createBaseCASBackendServiceCreateResponse(): CASBackendServiceCreateResponse { + return { result: undefined }; +} + +export const CASBackendServiceCreateResponse = { + encode(message: CASBackendServiceCreateResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.result !== undefined) { + CASBackendItem.encode(message.result, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): CASBackendServiceCreateResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseCASBackendServiceCreateResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.result = CASBackendItem.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): CASBackendServiceCreateResponse { + return { result: isSet(object.result) ? CASBackendItem.fromJSON(object.result) : undefined }; + }, + + toJSON(message: CASBackendServiceCreateResponse): unknown { + const obj: any = {}; + message.result !== undefined && (obj.result = message.result ? CASBackendItem.toJSON(message.result) : undefined); + return obj; + }, + + create, I>>(base?: I): CASBackendServiceCreateResponse { + return CASBackendServiceCreateResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): CASBackendServiceCreateResponse { + const message = createBaseCASBackendServiceCreateResponse(); + message.result = (object.result !== undefined && object.result !== null) + ? CASBackendItem.fromPartial(object.result) + : undefined; + return message; + }, +}; + export interface CASBackendService { List( request: DeepPartial, metadata?: grpc.Metadata, ): Promise; + Create( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise; } export class CASBackendServiceClientImpl implements CASBackendService { @@ -132,6 +326,7 @@ export class CASBackendServiceClientImpl implements CASBackendService { constructor(rpc: Rpc) { this.rpc = rpc; this.List = this.List.bind(this); + this.Create = this.Create.bind(this); } List( @@ -140,6 +335,13 @@ export class CASBackendServiceClientImpl implements CASBackendService { ): Promise { return this.rpc.unary(CASBackendServiceListDesc, CASBackendServiceListRequest.fromPartial(request), metadata); } + + Create( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise { + return this.rpc.unary(CASBackendServiceCreateDesc, CASBackendServiceCreateRequest.fromPartial(request), metadata); + } } export const CASBackendServiceDesc = { serviceName: "controlplane.v1.CASBackendService" }; @@ -167,6 +369,29 @@ export const CASBackendServiceListDesc: UnaryMethodDefinitionish = { } as any, }; +export const CASBackendServiceCreateDesc: UnaryMethodDefinitionish = { + methodName: "Create", + service: CASBackendServiceDesc, + requestStream: false, + responseStream: false, + requestType: { + serializeBinary() { + return CASBackendServiceCreateRequest.encode(this).finish(); + }, + } as any, + responseType: { + deserializeBinary(data: Uint8Array) { + const value = CASBackendServiceCreateResponse.decode(data); + return { + ...value, + toObject() { + return value; + }, + }; + }, + } as any, +}; + interface UnaryMethodDefinitionishR extends grpc.UnaryMethodDefinition { requestStream: any; responseStream: any; @@ -265,6 +490,14 @@ type KeysOfUnion = T extends T ? keyof T : never; export type Exact = P extends Builtin ? P : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; +function isObject(value: any): boolean { + return typeof value === "object" && value !== null; +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + export class GrpcWebError extends tsProtoGlobalThis.Error { constructor(message: string, public code: grpc.Code, public metadata: grpc.Metadata) { super(message); diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts index f87da0170..5e850e426 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts @@ -174,7 +174,9 @@ export function oCIRepositoryItem_ValidationStatusToJSON(object: OCIRepositoryIt export interface CASBackendItem { id: string; - name: string; + /** e.g. myregistry.io/myrepo s3 bucket and so on */ + location: string; + description: string; createdAt?: Date; validatedAt?: Date; validationStatus: CASBackendItem_ValidationStatus; @@ -1435,7 +1437,8 @@ export const OCIRepositoryItem = { function createBaseCASBackendItem(): CASBackendItem { return { id: "", - name: "", + location: "", + description: "", createdAt: undefined, validatedAt: undefined, validationStatus: 0, @@ -1449,23 +1452,26 @@ export const CASBackendItem = { if (message.id !== "") { writer.uint32(10).string(message.id); } - if (message.name !== "") { - writer.uint32(18).string(message.name); + if (message.location !== "") { + writer.uint32(18).string(message.location); + } + if (message.description !== "") { + writer.uint32(26).string(message.description); } if (message.createdAt !== undefined) { - Timestamp.encode(toTimestamp(message.createdAt), writer.uint32(26).fork()).ldelim(); + Timestamp.encode(toTimestamp(message.createdAt), writer.uint32(34).fork()).ldelim(); } if (message.validatedAt !== undefined) { - Timestamp.encode(toTimestamp(message.validatedAt), writer.uint32(34).fork()).ldelim(); + Timestamp.encode(toTimestamp(message.validatedAt), writer.uint32(42).fork()).ldelim(); } if (message.validationStatus !== 0) { - writer.uint32(40).int32(message.validationStatus); + writer.uint32(48).int32(message.validationStatus); } if (message.provider !== "") { - writer.uint32(50).string(message.provider); + writer.uint32(58).string(message.provider); } if (message.default === true) { - writer.uint32(56).bool(message.default); + writer.uint32(64).bool(message.default); } return writer; }, @@ -1489,38 +1495,45 @@ export const CASBackendItem = { break; } - message.name = reader.string(); + message.location = reader.string(); continue; case 3: if (tag !== 26) { break; } - message.createdAt = fromTimestamp(Timestamp.decode(reader, reader.uint32())); + message.description = reader.string(); continue; case 4: if (tag !== 34) { break; } - message.validatedAt = fromTimestamp(Timestamp.decode(reader, reader.uint32())); + message.createdAt = fromTimestamp(Timestamp.decode(reader, reader.uint32())); continue; case 5: - if (tag !== 40) { + if (tag !== 42) { break; } - message.validationStatus = reader.int32() as any; + message.validatedAt = fromTimestamp(Timestamp.decode(reader, reader.uint32())); continue; case 6: - if (tag !== 50) { + if (tag !== 48) { break; } - message.provider = reader.string(); + message.validationStatus = reader.int32() as any; continue; case 7: - if (tag !== 56) { + if (tag !== 58) { + break; + } + + message.provider = reader.string(); + continue; + case 8: + if (tag !== 64) { break; } @@ -1538,7 +1551,8 @@ export const CASBackendItem = { fromJSON(object: any): CASBackendItem { return { id: isSet(object.id) ? String(object.id) : "", - name: isSet(object.name) ? String(object.name) : "", + location: isSet(object.location) ? String(object.location) : "", + description: isSet(object.description) ? String(object.description) : "", createdAt: isSet(object.createdAt) ? fromJsonTimestamp(object.createdAt) : undefined, validatedAt: isSet(object.validatedAt) ? fromJsonTimestamp(object.validatedAt) : undefined, validationStatus: isSet(object.validationStatus) @@ -1552,7 +1566,8 @@ export const CASBackendItem = { toJSON(message: CASBackendItem): unknown { const obj: any = {}; message.id !== undefined && (obj.id = message.id); - message.name !== undefined && (obj.name = message.name); + message.location !== undefined && (obj.location = message.location); + message.description !== undefined && (obj.description = message.description); message.createdAt !== undefined && (obj.createdAt = message.createdAt.toISOString()); message.validatedAt !== undefined && (obj.validatedAt = message.validatedAt.toISOString()); message.validationStatus !== undefined && @@ -1569,7 +1584,8 @@ export const CASBackendItem = { fromPartial, I>>(object: I): CASBackendItem { const message = createBaseCASBackendItem(); message.id = object.id ?? ""; - message.name = object.name ?? ""; + message.location = object.location ?? ""; + message.description = object.description ?? ""; message.createdAt = object.createdAt ?? undefined; message.validatedAt = object.validatedAt ?? undefined; message.validationStatus = object.validationStatus ?? 0; diff --git a/app/controlplane/cmd/main.go b/app/controlplane/cmd/main.go index 66638bf98..575657a44 100644 --- a/app/controlplane/cmd/main.go +++ b/app/controlplane/cmd/main.go @@ -149,6 +149,8 @@ func filterSensitiveArgs(_ log.Level, keyvals ...interface{}) bool { maskArgs(keyvals) case "/controlplane.v1.IntegrationsService/Register", "/controlplane.v1.IntegrationsService/Attach": maskArgs(keyvals) + case "/controlplane.v1.CASBackendService/Create", "/controlplane.v1.CASBackendService/Update": + maskArgs(keyvals) } } } diff --git a/app/controlplane/internal/biz/casbackend.go b/app/controlplane/internal/biz/casbackend.go index 572a572ed..a299f768c 100644 --- a/app/controlplane/internal/biz/casbackend.go +++ b/app/controlplane/internal/biz/casbackend.go @@ -17,12 +17,16 @@ package biz import ( "context" + "encoding/json" + "errors" "fmt" "io" "time" backend "github.com/chainloop-dev/chainloop/internal/blobmanager" + "github.com/chainloop-dev/chainloop/internal/blobmanager/oci" "github.com/chainloop-dev/chainloop/internal/credentials" + "github.com/chainloop-dev/chainloop/internal/ociauth" "github.com/chainloop-dev/chainloop/internal/servicelogger" "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" @@ -40,11 +44,11 @@ var CASBackendValidationOK CASBackendValidationStatus = "OK" var CASBackendValidationFailed CASBackendValidationStatus = "Invalid" type CASBackend struct { - ID uuid.UUID - Name, SecretName string - CreatedAt, ValidatedAt *time.Time - OrganizationID string - ValidationStatus CASBackendValidationStatus + ID uuid.UUID + Location, Description, SecretName string + CreatedAt, ValidatedAt *time.Time + OrganizationID string + ValidationStatus CASBackendValidationStatus // OCI, S3, ... Provider CASBackendProvider // Wether this is the default cas backend for the organization @@ -52,9 +56,9 @@ type CASBackend struct { } type CASBackendOpts struct { - Name, Username, Password, SecretName string - Provider CASBackendProvider - Default bool + Location, SecretName, Description string + Provider CASBackendProvider + Default bool } type CASBackendCreateOpts struct { @@ -132,6 +136,63 @@ func (uc *CASBackendUseCase) FindByID(ctx context.Context, id string) (*CASBacke return backend, nil } +func (uc *CASBackendUseCase) Create(ctx context.Context, orgID, location, description string, provider CASBackendProvider, configJSON []byte, defaultB bool) (*CASBackend, error) { + orgUUID, err := uuid.Parse(orgID) + if err != nil { + return nil, NewErrInvalidUUID(err) + } + + // TODO: (miguel) this logic (marshalling from struct + validation) will be moved to the actual backend implementation + // This endpoint will support other backends in the future + if provider != CASBackendOCI { + return nil, NewErrValidation(errors.New("unsupported provider")) + } + + var ociConfig = struct { + Password string `json:"password"` + Username string `json:"username"` + }{} + + if err := json.Unmarshal(configJSON, &ociConfig); err != nil { + return nil, NewErrValidation(err) + } + + // Create and validate credentials + k, err := ociauth.NewCredentials(location, ociConfig.Username, ociConfig.Password) + if err != nil { + return nil, NewErrValidation(err) + } + + // Check credentials + b, err := oci.NewBackend(location, &oci.RegistryOptions{Keychain: k}) + if err != nil { + return nil, fmt.Errorf("checking credentials: %w", err) + } + + if err := b.CheckWritePermissions(context.TODO()); err != nil { + return nil, NewErrValidation(fmt.Errorf("wrong credentials: %w", err)) + } + + // Validate and store the secret in the external secrets manager + creds := &credentials.OCIKeypair{Repo: location, Username: ociConfig.Username, Password: ociConfig.Password} + if err := creds.Validate(); err != nil { + return nil, NewErrValidation(err) + } + + secretName, err := uc.credsRW.SaveCredentials(ctx, orgID, creds) + if err != nil { + return nil, fmt.Errorf("storing the credentials: %w", err) + } + + return uc.repo.Create(ctx, &CASBackendCreateOpts{ + OrgID: orgUUID, + CASBackendOpts: &CASBackendOpts{ + Location: location, SecretName: secretName, Provider: provider, Default: defaultB, + Description: description, + }, + }) +} + // TODO(miguel): we need to think about the update mechanism and add some guardrails // for example, we might only allow updating credentials but not the repository itself or the provider func (uc *CASBackendUseCase) CreateOrUpdate(ctx context.Context, orgID, name, username, password string, provider CASBackendProvider, defaultB bool) (*CASBackend, error) { @@ -161,7 +222,7 @@ func (uc *CASBackendUseCase) CreateOrUpdate(ctx context.Context, orgID, name, us if backend != nil { return uc.repo.Update(ctx, &CASBackendUpdateOpts{ CASBackendOpts: &CASBackendOpts{ - Name: name, Username: username, Password: password, SecretName: secretName, Provider: provider, Default: defaultB, + Location: name, SecretName: secretName, Provider: provider, Default: defaultB, }, ID: backend.ID, }) @@ -170,7 +231,7 @@ func (uc *CASBackendUseCase) CreateOrUpdate(ctx context.Context, orgID, name, us return uc.repo.Create(ctx, &CASBackendCreateOpts{ OrgID: orgUUID, CASBackendOpts: &CASBackendOpts{ - Name: name, Username: username, Password: password, SecretName: secretName, Provider: provider, + Location: name, SecretName: secretName, Provider: provider, Default: defaultB, }, }) diff --git a/app/controlplane/internal/biz/casbackend_test.go b/app/controlplane/internal/biz/casbackend_test.go index 13c8f8bb7..ac4032a4b 100644 --- a/app/controlplane/internal/biz/casbackend_test.go +++ b/app/controlplane/internal/biz/casbackend_test.go @@ -89,7 +89,7 @@ func (s *casBackendTestSuite) TestSaveDefaultBackendAlreadyExist() { s.repo.On("Update", ctx, &biz.CASBackendUpdateOpts{ ID: s.validUUID, CASBackendOpts: &biz.CASBackendOpts{ - Name: repoName, Username: username, Password: password, SecretName: "secret-key", Default: true, Provider: biz.CASBackendOCI, + Location: repoName, SecretName: "secret-key", Default: true, Provider: biz.CASBackendOCI, }, }).Return(r, nil) @@ -111,7 +111,7 @@ func (s *casBackendTestSuite) TestSaveDefaultBackendOk() { s.repo.On("Create", ctx, &biz.CASBackendCreateOpts{ OrgID: s.validUUID, CASBackendOpts: &biz.CASBackendOpts{ - Name: repo, Username: username, Password: password, SecretName: "secret-key", Default: true, Provider: biz.CASBackendOCI, + Location: repo, SecretName: "secret-key", Default: true, Provider: biz.CASBackendOCI, }, }).Return(newRepo, nil) diff --git a/app/controlplane/internal/data/casbackend.go b/app/controlplane/internal/data/casbackend.go index 864c1d631..dd78a8b97 100644 --- a/app/controlplane/internal/data/casbackend.go +++ b/app/controlplane/internal/data/casbackend.go @@ -23,6 +23,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/casbackend" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" ) @@ -40,7 +41,9 @@ func NewCASBackendRepo(data *Data, logger log.Logger) biz.CASBackendRepo { } func (r *CASBackendRepo) List(ctx context.Context, orgID uuid.UUID) ([]*biz.CASBackend, error) { - backends, err := orgScopedQuery(r.data.db, orgID).QueryCasBackends().WithOrganization().All(ctx) + backends, err := orgScopedQuery(r.data.db, orgID).QueryCasBackends().WithOrganization(). + Order(ent.Desc(casbackend.FieldCreatedAt)). + All(ctx) if err != nil { return nil, fmt.Errorf("failed to list cas backends: %w", err) } @@ -62,26 +65,50 @@ func (r *CASBackendRepo) FindDefaultBackend(ctx context.Context, orgID uuid.UUID return entCASBackendToBiz(backend), nil } +// Create creates a new CAS backend in the given organization +// If it's set as default, it will unset the previous default backend func (r *CASBackendRepo) Create(ctx context.Context, opts *biz.CASBackendCreateOpts) (*biz.CASBackend, error) { - backend, err := r.data.db.CASBackend.Create(). + tx, err := r.data.db.Tx(ctx) + if err != nil { + return nil, fmt.Errorf("failed to create transaction: %w", err) + } + + // 1 - unset default backend for all the other backends in the org + if opts.Default { + if err := tx.CASBackend.Update(). + Where(casbackend.HasOrganizationWith(organization.ID(opts.OrgID))). + Where(casbackend.Default(true)). + SetDefault(false). + Exec(ctx); err != nil { + return nil, fmt.Errorf("failed to clear previous default backend: %w", err) + } + } + + // 2 - create the new backend and set it as default if needed + backend, err := tx.CASBackend.Create(). SetOrganizationID(opts.OrgID). - SetName(opts.Name). + SetLocation(opts.Location). + SetDescription(opts.Description). SetProvider(opts.Provider). SetDefault(opts.Default). SetSecretName(opts.SecretName). Save(ctx) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create backend: %w", err) + } + + // 3 - commit the transaction + if err := tx.Commit(); err != nil { + return nil, fmt.Errorf("failed to commit transaction: %w", err) } - // Return the backend from the DB to have consistent timestamp data + // Return the backend from the DB to have consistent marshalled object return r.FindByID(ctx, backend.ID) } func (r *CASBackendRepo) Update(ctx context.Context, opts *biz.CASBackendUpdateOpts) (*biz.CASBackend, error) { backend, err := r.data.db.CASBackend.UpdateOneID(opts.ID). - SetName(opts.Name). - SetProvider(opts.Provider). + SetDescription(opts.Description). SetDefault(opts.Default). SetSecretName(opts.SecretName). Save(ctx) @@ -124,7 +151,8 @@ func entCASBackendToBiz(backend *ent.CASBackend) *biz.CASBackend { r := &biz.CASBackend{ ID: backend.ID, - Name: backend.Name, + Location: backend.Location, + Description: backend.Description, SecretName: backend.SecretName, CreatedAt: toTimePtr(backend.CreatedAt), ValidatedAt: toTimePtr(backend.ValidatedAt), diff --git a/app/controlplane/internal/data/casbackend_test.go b/app/controlplane/internal/data/casbackend_test.go index 1eb5c9210..cab4353fa 100644 --- a/app/controlplane/internal/data/casbackend_test.go +++ b/app/controlplane/internal/data/casbackend_test.go @@ -27,12 +27,13 @@ import ( func TestEntCASBackendTo(t *testing.T) { testRepo := &ent.CASBackend{ - ID: uuid.New(), - Name: "test-repo", - Provider: "test-provider", - SecretName: "test-secret", - CreatedAt: time.Now(), - Default: true, + ID: uuid.New(), + Location: "test-repo", + Provider: "test-provider", + SecretName: "test-secret", + Description: "test-description", + CreatedAt: time.Now(), + Default: true, } tests := []struct { @@ -41,12 +42,13 @@ func TestEntCASBackendTo(t *testing.T) { }{ {nil, nil}, {testRepo, &biz.CASBackend{ - ID: testRepo.ID, - Name: testRepo.Name, - SecretName: testRepo.SecretName, - CreatedAt: toTimePtr(testRepo.CreatedAt), - Provider: testRepo.Provider, - Default: true, + ID: testRepo.ID, + Location: testRepo.Location, + SecretName: testRepo.SecretName, + Description: testRepo.Description, + CreatedAt: toTimePtr(testRepo.CreatedAt), + Provider: testRepo.Provider, + Default: true, }}, } diff --git a/app/controlplane/internal/data/ent/casbackend.go b/app/controlplane/internal/data/ent/casbackend.go index 2194bb2f6..122c3c8a1 100644 --- a/app/controlplane/internal/data/ent/casbackend.go +++ b/app/controlplane/internal/data/ent/casbackend.go @@ -20,8 +20,12 @@ type CASBackend struct { config `json:"-"` // ID of the ent. ID uuid.UUID `json:"id,omitempty"` - // Name holds the value of the "name" field. - Name string `json:"name,omitempty"` + // Location holds the value of the "location" field. + Location string `json:"location,omitempty"` + // Provider holds the value of the "provider" field. + Provider biz.CASBackendProvider `json:"provider,omitempty"` + // Description holds the value of the "description" field. + Description string `json:"description,omitempty"` // SecretName holds the value of the "secret_name" field. SecretName string `json:"secret_name,omitempty"` // CreatedAt holds the value of the "created_at" field. @@ -30,8 +34,6 @@ type CASBackend struct { ValidationStatus biz.CASBackendValidationStatus `json:"validation_status,omitempty"` // ValidatedAt holds the value of the "validated_at" field. ValidatedAt time.Time `json:"validated_at,omitempty"` - // Provider holds the value of the "provider" field. - Provider biz.CASBackendProvider `json:"provider,omitempty"` // Default holds the value of the "default" field. Default bool `json:"default,omitempty"` // Edges holds the relations/edges for other nodes in the graph. @@ -81,7 +83,7 @@ func (*CASBackend) scanValues(columns []string) ([]any, error) { switch columns[i] { case casbackend.FieldDefault: values[i] = new(sql.NullBool) - case casbackend.FieldName, casbackend.FieldSecretName, casbackend.FieldValidationStatus, casbackend.FieldProvider: + case casbackend.FieldLocation, casbackend.FieldProvider, casbackend.FieldDescription, casbackend.FieldSecretName, casbackend.FieldValidationStatus: values[i] = new(sql.NullString) case casbackend.FieldCreatedAt, casbackend.FieldValidatedAt: values[i] = new(sql.NullTime) @@ -110,11 +112,23 @@ func (cb *CASBackend) assignValues(columns []string, values []any) error { } else if value != nil { cb.ID = *value } - case casbackend.FieldName: + case casbackend.FieldLocation: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field location", values[i]) + } else if value.Valid { + cb.Location = value.String + } + case casbackend.FieldProvider: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field provider", values[i]) + } else if value.Valid { + cb.Provider = biz.CASBackendProvider(value.String) + } + case casbackend.FieldDescription: if value, ok := values[i].(*sql.NullString); !ok { - return fmt.Errorf("unexpected type %T for field name", values[i]) + return fmt.Errorf("unexpected type %T for field description", values[i]) } else if value.Valid { - cb.Name = value.String + cb.Description = value.String } case casbackend.FieldSecretName: if value, ok := values[i].(*sql.NullString); !ok { @@ -140,12 +154,6 @@ func (cb *CASBackend) assignValues(columns []string, values []any) error { } else if value.Valid { cb.ValidatedAt = value.Time } - case casbackend.FieldProvider: - if value, ok := values[i].(*sql.NullString); !ok { - return fmt.Errorf("unexpected type %T for field provider", values[i]) - } else if value.Valid { - cb.Provider = biz.CASBackendProvider(value.String) - } case casbackend.FieldDefault: if value, ok := values[i].(*sql.NullBool); !ok { return fmt.Errorf("unexpected type %T for field default", values[i]) @@ -205,8 +213,14 @@ func (cb *CASBackend) String() string { var builder strings.Builder builder.WriteString("CASBackend(") builder.WriteString(fmt.Sprintf("id=%v, ", cb.ID)) - builder.WriteString("name=") - builder.WriteString(cb.Name) + builder.WriteString("location=") + builder.WriteString(cb.Location) + builder.WriteString(", ") + builder.WriteString("provider=") + builder.WriteString(fmt.Sprintf("%v", cb.Provider)) + builder.WriteString(", ") + builder.WriteString("description=") + builder.WriteString(cb.Description) builder.WriteString(", ") builder.WriteString("secret_name=") builder.WriteString(cb.SecretName) @@ -220,9 +234,6 @@ func (cb *CASBackend) String() string { builder.WriteString("validated_at=") builder.WriteString(cb.ValidatedAt.Format(time.ANSIC)) builder.WriteString(", ") - builder.WriteString("provider=") - builder.WriteString(fmt.Sprintf("%v", cb.Provider)) - builder.WriteString(", ") builder.WriteString("default=") builder.WriteString(fmt.Sprintf("%v", cb.Default)) builder.WriteByte(')') diff --git a/app/controlplane/internal/data/ent/casbackend/casbackend.go b/app/controlplane/internal/data/ent/casbackend/casbackend.go index 7cd2ad7ce..61eaf17f7 100644 --- a/app/controlplane/internal/data/ent/casbackend/casbackend.go +++ b/app/controlplane/internal/data/ent/casbackend/casbackend.go @@ -17,8 +17,12 @@ const ( Label = "cas_backend" // FieldID holds the string denoting the id field in the database. FieldID = "id" - // FieldName holds the string denoting the name field in the database. - FieldName = "name" + // FieldLocation holds the string denoting the location field in the database. + FieldLocation = "location" + // FieldProvider holds the string denoting the provider field in the database. + FieldProvider = "provider" + // FieldDescription holds the string denoting the description field in the database. + FieldDescription = "description" // FieldSecretName holds the string denoting the secret_name field in the database. FieldSecretName = "secret_name" // FieldCreatedAt holds the string denoting the created_at field in the database. @@ -27,8 +31,6 @@ const ( FieldValidationStatus = "validation_status" // FieldValidatedAt holds the string denoting the validated_at field in the database. FieldValidatedAt = "validated_at" - // FieldProvider holds the string denoting the provider field in the database. - FieldProvider = "provider" // FieldDefault holds the string denoting the default field in the database. FieldDefault = "default" // EdgeOrganization holds the string denoting the organization edge name in mutations. @@ -54,12 +56,13 @@ const ( // Columns holds all SQL columns for casbackend fields. var Columns = []string{ FieldID, - FieldName, + FieldLocation, + FieldProvider, + FieldDescription, FieldSecretName, FieldCreatedAt, FieldValidationStatus, FieldValidatedAt, - FieldProvider, FieldDefault, } @@ -101,6 +104,16 @@ var ( DefaultID func() uuid.UUID ) +// ProviderValidator is a validator for the "provider" field enum values. It is called by the builders before save. +func ProviderValidator(pr biz.CASBackendProvider) error { + switch pr { + case "OCI": + return nil + default: + return fmt.Errorf("casbackend: invalid enum value for provider field: %q", pr) + } +} + const DefaultValidationStatus biz.CASBackendValidationStatus = "OK" // ValidationStatusValidator is a validator for the "validation_status" field enum values. It is called by the builders before save. @@ -113,16 +126,6 @@ func ValidationStatusValidator(vs biz.CASBackendValidationStatus) error { } } -// ProviderValidator is a validator for the "provider" field enum values. It is called by the builders before save. -func ProviderValidator(pr biz.CASBackendProvider) error { - switch pr { - case "OCI": - return nil - default: - return fmt.Errorf("casbackend: invalid enum value for provider field: %q", pr) - } -} - // OrderOption defines the ordering options for the CASBackend queries. type OrderOption func(*sql.Selector) @@ -131,9 +134,19 @@ func ByID(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldID, opts...).ToFunc() } -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() +// ByLocation orders the results by the location field. +func ByLocation(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldLocation, opts...).ToFunc() +} + +// ByProvider orders the results by the provider field. +func ByProvider(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldProvider, opts...).ToFunc() +} + +// ByDescription orders the results by the description field. +func ByDescription(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDescription, opts...).ToFunc() } // BySecretName orders the results by the secret_name field. @@ -156,11 +169,6 @@ func ByValidatedAt(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldValidatedAt, opts...).ToFunc() } -// ByProvider orders the results by the provider field. -func ByProvider(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldProvider, opts...).ToFunc() -} - // ByDefault orders the results by the default field. func ByDefault(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldDefault, opts...).ToFunc() diff --git a/app/controlplane/internal/data/ent/casbackend/where.go b/app/controlplane/internal/data/ent/casbackend/where.go index b5d6b4486..cb985ea2e 100644 --- a/app/controlplane/internal/data/ent/casbackend/where.go +++ b/app/controlplane/internal/data/ent/casbackend/where.go @@ -57,9 +57,14 @@ func IDLTE(id uuid.UUID) predicate.CASBackend { return predicate.CASBackend(sql.FieldLTE(FieldID, id)) } -// Name applies equality check predicate on the "name" field. It's identical to NameEQ. -func Name(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldEQ(FieldName, v)) +// Location applies equality check predicate on the "location" field. It's identical to LocationEQ. +func Location(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldEQ(FieldLocation, v)) +} + +// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ. +func Description(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldEQ(FieldDescription, v)) } // SecretName applies equality check predicate on the "secret_name" field. It's identical to SecretNameEQ. @@ -82,69 +87,174 @@ func Default(v bool) predicate.CASBackend { return predicate.CASBackend(sql.FieldEQ(FieldDefault, v)) } -// NameEQ applies the EQ predicate on the "name" field. -func NameEQ(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldEQ(FieldName, v)) +// LocationEQ applies the EQ predicate on the "location" field. +func LocationEQ(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldEQ(FieldLocation, v)) +} + +// LocationNEQ applies the NEQ predicate on the "location" field. +func LocationNEQ(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldNEQ(FieldLocation, v)) +} + +// LocationIn applies the In predicate on the "location" field. +func LocationIn(vs ...string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldIn(FieldLocation, vs...)) +} + +// LocationNotIn applies the NotIn predicate on the "location" field. +func LocationNotIn(vs ...string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldNotIn(FieldLocation, vs...)) +} + +// LocationGT applies the GT predicate on the "location" field. +func LocationGT(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldGT(FieldLocation, v)) +} + +// LocationGTE applies the GTE predicate on the "location" field. +func LocationGTE(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldGTE(FieldLocation, v)) +} + +// LocationLT applies the LT predicate on the "location" field. +func LocationLT(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldLT(FieldLocation, v)) +} + +// LocationLTE applies the LTE predicate on the "location" field. +func LocationLTE(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldLTE(FieldLocation, v)) +} + +// LocationContains applies the Contains predicate on the "location" field. +func LocationContains(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldContains(FieldLocation, v)) +} + +// LocationHasPrefix applies the HasPrefix predicate on the "location" field. +func LocationHasPrefix(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldHasPrefix(FieldLocation, v)) +} + +// LocationHasSuffix applies the HasSuffix predicate on the "location" field. +func LocationHasSuffix(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldHasSuffix(FieldLocation, v)) +} + +// LocationEqualFold applies the EqualFold predicate on the "location" field. +func LocationEqualFold(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldEqualFold(FieldLocation, v)) +} + +// LocationContainsFold applies the ContainsFold predicate on the "location" field. +func LocationContainsFold(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldContainsFold(FieldLocation, v)) +} + +// ProviderEQ applies the EQ predicate on the "provider" field. +func ProviderEQ(v biz.CASBackendProvider) predicate.CASBackend { + vc := v + return predicate.CASBackend(sql.FieldEQ(FieldProvider, vc)) +} + +// ProviderNEQ applies the NEQ predicate on the "provider" field. +func ProviderNEQ(v biz.CASBackendProvider) predicate.CASBackend { + vc := v + return predicate.CASBackend(sql.FieldNEQ(FieldProvider, vc)) +} + +// ProviderIn applies the In predicate on the "provider" field. +func ProviderIn(vs ...biz.CASBackendProvider) predicate.CASBackend { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.CASBackend(sql.FieldIn(FieldProvider, v...)) +} + +// ProviderNotIn applies the NotIn predicate on the "provider" field. +func ProviderNotIn(vs ...biz.CASBackendProvider) predicate.CASBackend { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.CASBackend(sql.FieldNotIn(FieldProvider, v...)) +} + +// DescriptionEQ applies the EQ predicate on the "description" field. +func DescriptionEQ(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldEQ(FieldDescription, v)) } -// NameNEQ applies the NEQ predicate on the "name" field. -func NameNEQ(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldNEQ(FieldName, v)) +// DescriptionNEQ applies the NEQ predicate on the "description" field. +func DescriptionNEQ(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldNEQ(FieldDescription, v)) } -// NameIn applies the In predicate on the "name" field. -func NameIn(vs ...string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldIn(FieldName, vs...)) +// DescriptionIn applies the In predicate on the "description" field. +func DescriptionIn(vs ...string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldIn(FieldDescription, vs...)) } -// NameNotIn applies the NotIn predicate on the "name" field. -func NameNotIn(vs ...string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldNotIn(FieldName, vs...)) +// DescriptionNotIn applies the NotIn predicate on the "description" field. +func DescriptionNotIn(vs ...string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldNotIn(FieldDescription, vs...)) } -// NameGT applies the GT predicate on the "name" field. -func NameGT(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldGT(FieldName, v)) +// DescriptionGT applies the GT predicate on the "description" field. +func DescriptionGT(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldGT(FieldDescription, v)) } -// NameGTE applies the GTE predicate on the "name" field. -func NameGTE(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldGTE(FieldName, v)) +// DescriptionGTE applies the GTE predicate on the "description" field. +func DescriptionGTE(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldGTE(FieldDescription, v)) } -// NameLT applies the LT predicate on the "name" field. -func NameLT(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldLT(FieldName, v)) +// DescriptionLT applies the LT predicate on the "description" field. +func DescriptionLT(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldLT(FieldDescription, v)) } -// NameLTE applies the LTE predicate on the "name" field. -func NameLTE(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldLTE(FieldName, v)) +// DescriptionLTE applies the LTE predicate on the "description" field. +func DescriptionLTE(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldLTE(FieldDescription, v)) } -// NameContains applies the Contains predicate on the "name" field. -func NameContains(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldContains(FieldName, v)) +// DescriptionContains applies the Contains predicate on the "description" field. +func DescriptionContains(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldContains(FieldDescription, v)) } -// NameHasPrefix applies the HasPrefix predicate on the "name" field. -func NameHasPrefix(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldHasPrefix(FieldName, v)) +// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field. +func DescriptionHasPrefix(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldHasPrefix(FieldDescription, v)) } -// NameHasSuffix applies the HasSuffix predicate on the "name" field. -func NameHasSuffix(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldHasSuffix(FieldName, v)) +// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field. +func DescriptionHasSuffix(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldHasSuffix(FieldDescription, v)) } -// NameEqualFold applies the EqualFold predicate on the "name" field. -func NameEqualFold(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldEqualFold(FieldName, v)) +// DescriptionIsNil applies the IsNil predicate on the "description" field. +func DescriptionIsNil() predicate.CASBackend { + return predicate.CASBackend(sql.FieldIsNull(FieldDescription)) } -// NameContainsFold applies the ContainsFold predicate on the "name" field. -func NameContainsFold(v string) predicate.CASBackend { - return predicate.CASBackend(sql.FieldContainsFold(FieldName, v)) +// DescriptionNotNil applies the NotNil predicate on the "description" field. +func DescriptionNotNil() predicate.CASBackend { + return predicate.CASBackend(sql.FieldNotNull(FieldDescription)) +} + +// DescriptionEqualFold applies the EqualFold predicate on the "description" field. +func DescriptionEqualFold(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldEqualFold(FieldDescription, v)) +} + +// DescriptionContainsFold applies the ContainsFold predicate on the "description" field. +func DescriptionContainsFold(v string) predicate.CASBackend { + return predicate.CASBackend(sql.FieldContainsFold(FieldDescription, v)) } // SecretNameEQ applies the EQ predicate on the "secret_name" field. @@ -322,36 +432,6 @@ func ValidatedAtLTE(v time.Time) predicate.CASBackend { return predicate.CASBackend(sql.FieldLTE(FieldValidatedAt, v)) } -// ProviderEQ applies the EQ predicate on the "provider" field. -func ProviderEQ(v biz.CASBackendProvider) predicate.CASBackend { - vc := v - return predicate.CASBackend(sql.FieldEQ(FieldProvider, vc)) -} - -// ProviderNEQ applies the NEQ predicate on the "provider" field. -func ProviderNEQ(v biz.CASBackendProvider) predicate.CASBackend { - vc := v - return predicate.CASBackend(sql.FieldNEQ(FieldProvider, vc)) -} - -// ProviderIn applies the In predicate on the "provider" field. -func ProviderIn(vs ...biz.CASBackendProvider) predicate.CASBackend { - v := make([]any, len(vs)) - for i := range v { - v[i] = vs[i] - } - return predicate.CASBackend(sql.FieldIn(FieldProvider, v...)) -} - -// ProviderNotIn applies the NotIn predicate on the "provider" field. -func ProviderNotIn(vs ...biz.CASBackendProvider) predicate.CASBackend { - v := make([]any, len(vs)) - for i := range v { - v[i] = vs[i] - } - return predicate.CASBackend(sql.FieldNotIn(FieldProvider, v...)) -} - // DefaultEQ applies the EQ predicate on the "default" field. func DefaultEQ(v bool) predicate.CASBackend { return predicate.CASBackend(sql.FieldEQ(FieldDefault, v)) diff --git a/app/controlplane/internal/data/ent/casbackend_create.go b/app/controlplane/internal/data/ent/casbackend_create.go index dd3f34130..da4a58a2c 100644 --- a/app/controlplane/internal/data/ent/casbackend_create.go +++ b/app/controlplane/internal/data/ent/casbackend_create.go @@ -24,9 +24,29 @@ type CASBackendCreate struct { hooks []Hook } -// SetName sets the "name" field. -func (cbc *CASBackendCreate) SetName(s string) *CASBackendCreate { - cbc.mutation.SetName(s) +// SetLocation sets the "location" field. +func (cbc *CASBackendCreate) SetLocation(s string) *CASBackendCreate { + cbc.mutation.SetLocation(s) + return cbc +} + +// SetProvider sets the "provider" field. +func (cbc *CASBackendCreate) SetProvider(bbp biz.CASBackendProvider) *CASBackendCreate { + cbc.mutation.SetProvider(bbp) + return cbc +} + +// SetDescription sets the "description" field. +func (cbc *CASBackendCreate) SetDescription(s string) *CASBackendCreate { + cbc.mutation.SetDescription(s) + return cbc +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (cbc *CASBackendCreate) SetNillableDescription(s *string) *CASBackendCreate { + if s != nil { + cbc.SetDescription(*s) + } return cbc } @@ -78,12 +98,6 @@ func (cbc *CASBackendCreate) SetNillableValidatedAt(t *time.Time) *CASBackendCre return cbc } -// SetProvider sets the "provider" field. -func (cbc *CASBackendCreate) SetProvider(bbp biz.CASBackendProvider) *CASBackendCreate { - cbc.mutation.SetProvider(bbp) - return cbc -} - // SetDefault sets the "default" field. func (cbc *CASBackendCreate) SetDefault(b bool) *CASBackendCreate { cbc.mutation.SetDefault(b) @@ -197,8 +211,16 @@ func (cbc *CASBackendCreate) defaults() { // check runs all checks and user-defined validators on the builder. func (cbc *CASBackendCreate) check() error { - if _, ok := cbc.mutation.Name(); !ok { - return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "CASBackend.name"`)} + if _, ok := cbc.mutation.Location(); !ok { + return &ValidationError{Name: "location", err: errors.New(`ent: missing required field "CASBackend.location"`)} + } + if _, ok := cbc.mutation.Provider(); !ok { + return &ValidationError{Name: "provider", err: errors.New(`ent: missing required field "CASBackend.provider"`)} + } + if v, ok := cbc.mutation.Provider(); ok { + if err := casbackend.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "CASBackend.provider": %w`, err)} + } } if _, ok := cbc.mutation.SecretName(); !ok { return &ValidationError{Name: "secret_name", err: errors.New(`ent: missing required field "CASBackend.secret_name"`)} @@ -217,14 +239,6 @@ func (cbc *CASBackendCreate) check() error { if _, ok := cbc.mutation.ValidatedAt(); !ok { return &ValidationError{Name: "validated_at", err: errors.New(`ent: missing required field "CASBackend.validated_at"`)} } - if _, ok := cbc.mutation.Provider(); !ok { - return &ValidationError{Name: "provider", err: errors.New(`ent: missing required field "CASBackend.provider"`)} - } - if v, ok := cbc.mutation.Provider(); ok { - if err := casbackend.ProviderValidator(v); err != nil { - return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "CASBackend.provider": %w`, err)} - } - } if _, ok := cbc.mutation.Default(); !ok { return &ValidationError{Name: "default", err: errors.New(`ent: missing required field "CASBackend.default"`)} } @@ -266,9 +280,17 @@ func (cbc *CASBackendCreate) createSpec() (*CASBackend, *sqlgraph.CreateSpec) { _node.ID = id _spec.ID.Value = &id } - if value, ok := cbc.mutation.Name(); ok { - _spec.SetField(casbackend.FieldName, field.TypeString, value) - _node.Name = value + if value, ok := cbc.mutation.Location(); ok { + _spec.SetField(casbackend.FieldLocation, field.TypeString, value) + _node.Location = value + } + if value, ok := cbc.mutation.Provider(); ok { + _spec.SetField(casbackend.FieldProvider, field.TypeEnum, value) + _node.Provider = value + } + if value, ok := cbc.mutation.Description(); ok { + _spec.SetField(casbackend.FieldDescription, field.TypeString, value) + _node.Description = value } if value, ok := cbc.mutation.SecretName(); ok { _spec.SetField(casbackend.FieldSecretName, field.TypeString, value) @@ -286,10 +308,6 @@ func (cbc *CASBackendCreate) createSpec() (*CASBackend, *sqlgraph.CreateSpec) { _spec.SetField(casbackend.FieldValidatedAt, field.TypeTime, value) _node.ValidatedAt = value } - if value, ok := cbc.mutation.Provider(); ok { - _spec.SetField(casbackend.FieldProvider, field.TypeEnum, value) - _node.Provider = value - } if value, ok := cbc.mutation.Default(); ok { _spec.SetField(casbackend.FieldDefault, field.TypeBool, value) _node.Default = value diff --git a/app/controlplane/internal/data/ent/casbackend_query.go b/app/controlplane/internal/data/ent/casbackend_query.go index 1665006fc..efaaab179 100644 --- a/app/controlplane/internal/data/ent/casbackend_query.go +++ b/app/controlplane/internal/data/ent/casbackend_query.go @@ -336,12 +336,12 @@ func (cbq *CASBackendQuery) WithWorkflowRun(opts ...func(*WorkflowRunQuery)) *CA // Example: // // var v []struct { -// Name string `json:"name,omitempty"` +// Location string `json:"location,omitempty"` // Count int `json:"count,omitempty"` // } // // client.CASBackend.Query(). -// GroupBy(casbackend.FieldName). +// GroupBy(casbackend.FieldLocation). // Aggregate(ent.Count()). // Scan(ctx, &v) func (cbq *CASBackendQuery) GroupBy(field string, fields ...string) *CASBackendGroupBy { @@ -359,11 +359,11 @@ func (cbq *CASBackendQuery) GroupBy(field string, fields ...string) *CASBackendG // Example: // // var v []struct { -// Name string `json:"name,omitempty"` +// Location string `json:"location,omitempty"` // } // // client.CASBackend.Query(). -// Select(casbackend.FieldName). +// Select(casbackend.FieldLocation). // Scan(ctx, &v) func (cbq *CASBackendQuery) Select(fields ...string) *CASBackendSelect { cbq.ctx.Fields = append(cbq.ctx.Fields, fields...) diff --git a/app/controlplane/internal/data/ent/casbackend_update.go b/app/controlplane/internal/data/ent/casbackend_update.go index effc0d477..38dbcfdb8 100644 --- a/app/controlplane/internal/data/ent/casbackend_update.go +++ b/app/controlplane/internal/data/ent/casbackend_update.go @@ -32,9 +32,23 @@ func (cbu *CASBackendUpdate) Where(ps ...predicate.CASBackend) *CASBackendUpdate return cbu } -// SetName sets the "name" field. -func (cbu *CASBackendUpdate) SetName(s string) *CASBackendUpdate { - cbu.mutation.SetName(s) +// SetDescription sets the "description" field. +func (cbu *CASBackendUpdate) SetDescription(s string) *CASBackendUpdate { + cbu.mutation.SetDescription(s) + return cbu +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (cbu *CASBackendUpdate) SetNillableDescription(s *string) *CASBackendUpdate { + if s != nil { + cbu.SetDescription(*s) + } + return cbu +} + +// ClearDescription clears the value of the "description" field. +func (cbu *CASBackendUpdate) ClearDescription() *CASBackendUpdate { + cbu.mutation.ClearDescription() return cbu } @@ -72,12 +86,6 @@ func (cbu *CASBackendUpdate) SetNillableValidatedAt(t *time.Time) *CASBackendUpd return cbu } -// SetProvider sets the "provider" field. -func (cbu *CASBackendUpdate) SetProvider(bbp biz.CASBackendProvider) *CASBackendUpdate { - cbu.mutation.SetProvider(bbp) - return cbu -} - // SetDefault sets the "default" field. func (cbu *CASBackendUpdate) SetDefault(b bool) *CASBackendUpdate { cbu.mutation.SetDefault(b) @@ -184,11 +192,6 @@ func (cbu *CASBackendUpdate) check() error { return &ValidationError{Name: "validation_status", err: fmt.Errorf(`ent: validator failed for field "CASBackend.validation_status": %w`, err)} } } - if v, ok := cbu.mutation.Provider(); ok { - if err := casbackend.ProviderValidator(v); err != nil { - return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "CASBackend.provider": %w`, err)} - } - } if _, ok := cbu.mutation.OrganizationID(); cbu.mutation.OrganizationCleared() && !ok { return errors.New(`ent: clearing a required unique edge "CASBackend.organization"`) } @@ -207,8 +210,11 @@ func (cbu *CASBackendUpdate) sqlSave(ctx context.Context) (n int, err error) { } } } - if value, ok := cbu.mutation.Name(); ok { - _spec.SetField(casbackend.FieldName, field.TypeString, value) + if value, ok := cbu.mutation.Description(); ok { + _spec.SetField(casbackend.FieldDescription, field.TypeString, value) + } + if cbu.mutation.DescriptionCleared() { + _spec.ClearField(casbackend.FieldDescription, field.TypeString) } if value, ok := cbu.mutation.SecretName(); ok { _spec.SetField(casbackend.FieldSecretName, field.TypeString, value) @@ -219,9 +225,6 @@ func (cbu *CASBackendUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := cbu.mutation.ValidatedAt(); ok { _spec.SetField(casbackend.FieldValidatedAt, field.TypeTime, value) } - if value, ok := cbu.mutation.Provider(); ok { - _spec.SetField(casbackend.FieldProvider, field.TypeEnum, value) - } if value, ok := cbu.mutation.Default(); ok { _spec.SetField(casbackend.FieldDefault, field.TypeBool, value) } @@ -319,9 +322,23 @@ type CASBackendUpdateOne struct { mutation *CASBackendMutation } -// SetName sets the "name" field. -func (cbuo *CASBackendUpdateOne) SetName(s string) *CASBackendUpdateOne { - cbuo.mutation.SetName(s) +// SetDescription sets the "description" field. +func (cbuo *CASBackendUpdateOne) SetDescription(s string) *CASBackendUpdateOne { + cbuo.mutation.SetDescription(s) + return cbuo +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (cbuo *CASBackendUpdateOne) SetNillableDescription(s *string) *CASBackendUpdateOne { + if s != nil { + cbuo.SetDescription(*s) + } + return cbuo +} + +// ClearDescription clears the value of the "description" field. +func (cbuo *CASBackendUpdateOne) ClearDescription() *CASBackendUpdateOne { + cbuo.mutation.ClearDescription() return cbuo } @@ -359,12 +376,6 @@ func (cbuo *CASBackendUpdateOne) SetNillableValidatedAt(t *time.Time) *CASBacken return cbuo } -// SetProvider sets the "provider" field. -func (cbuo *CASBackendUpdateOne) SetProvider(bbp biz.CASBackendProvider) *CASBackendUpdateOne { - cbuo.mutation.SetProvider(bbp) - return cbuo -} - // SetDefault sets the "default" field. func (cbuo *CASBackendUpdateOne) SetDefault(b bool) *CASBackendUpdateOne { cbuo.mutation.SetDefault(b) @@ -484,11 +495,6 @@ func (cbuo *CASBackendUpdateOne) check() error { return &ValidationError{Name: "validation_status", err: fmt.Errorf(`ent: validator failed for field "CASBackend.validation_status": %w`, err)} } } - if v, ok := cbuo.mutation.Provider(); ok { - if err := casbackend.ProviderValidator(v); err != nil { - return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "CASBackend.provider": %w`, err)} - } - } if _, ok := cbuo.mutation.OrganizationID(); cbuo.mutation.OrganizationCleared() && !ok { return errors.New(`ent: clearing a required unique edge "CASBackend.organization"`) } @@ -524,8 +530,11 @@ func (cbuo *CASBackendUpdateOne) sqlSave(ctx context.Context) (_node *CASBackend } } } - if value, ok := cbuo.mutation.Name(); ok { - _spec.SetField(casbackend.FieldName, field.TypeString, value) + if value, ok := cbuo.mutation.Description(); ok { + _spec.SetField(casbackend.FieldDescription, field.TypeString, value) + } + if cbuo.mutation.DescriptionCleared() { + _spec.ClearField(casbackend.FieldDescription, field.TypeString) } if value, ok := cbuo.mutation.SecretName(); ok { _spec.SetField(casbackend.FieldSecretName, field.TypeString, value) @@ -536,9 +545,6 @@ func (cbuo *CASBackendUpdateOne) sqlSave(ctx context.Context) (_node *CASBackend if value, ok := cbuo.mutation.ValidatedAt(); ok { _spec.SetField(casbackend.FieldValidatedAt, field.TypeTime, value) } - if value, ok := cbuo.mutation.Provider(); ok { - _spec.SetField(casbackend.FieldProvider, field.TypeEnum, value) - } if value, ok := cbuo.mutation.Default(); ok { _spec.SetField(casbackend.FieldDefault, field.TypeBool, value) } diff --git a/app/controlplane/internal/data/ent/migrate/migrations/20230713112216-description.sql b/app/controlplane/internal/data/ent/migrate/migrations/20230713112216-description.sql new file mode 100644 index 000000000..02d67601a --- /dev/null +++ b/app/controlplane/internal/data/ent/migrate/migrations/20230713112216-description.sql @@ -0,0 +1,3 @@ +-- Modify "cas_backends" table +ALTER TABLE "cas_backends" ADD COLUMN "description" character varying NULL; +ALTER TABLE "cas_backends" RENAME COLUMN "name" TO "location"; \ No newline at end of file diff --git a/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum b/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum index 49b35ec19..7674bf6c1 100644 --- a/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum @@ -1,4 +1,5 @@ -h1:e4CgPohg8kN/8glnfHfPYXGcYJ/RNiqdD0WzyY06mh8= +h1:Hu0VtkIyLR0K/3CiXJ5L/DhWEu5gOW0n4mDQNoVsJ7Y= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= +20230713112216-description.sql h1:jTxi1Gnp5oiqu3qAf4N7RaNfV0NbjupN2fIld+HcTTQ= diff --git a/app/controlplane/internal/data/ent/migrate/schema.go b/app/controlplane/internal/data/ent/migrate/schema.go index 62855df78..efd713d94 100644 --- a/app/controlplane/internal/data/ent/migrate/schema.go +++ b/app/controlplane/internal/data/ent/migrate/schema.go @@ -11,12 +11,13 @@ var ( // CasBackendsColumns holds the columns for the "cas_backends" table. CasBackendsColumns = []*schema.Column{ {Name: "id", Type: field.TypeUUID, Unique: true}, - {Name: "name", Type: field.TypeString}, + {Name: "location", Type: field.TypeString}, + {Name: "provider", Type: field.TypeEnum, Enums: []string{"OCI"}}, + {Name: "description", Type: field.TypeString, Nullable: true}, {Name: "secret_name", Type: field.TypeString}, {Name: "created_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, {Name: "validation_status", Type: field.TypeEnum, Enums: []string{"OK", "Invalid"}, Default: "OK"}, {Name: "validated_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, - {Name: "provider", Type: field.TypeEnum, Enums: []string{"OCI"}}, {Name: "default", Type: field.TypeBool, Default: false}, {Name: "organization_cas_backends", Type: field.TypeUUID}, } @@ -28,7 +29,7 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "cas_backends_organizations_cas_backends", - Columns: []*schema.Column{CasBackendsColumns[8]}, + Columns: []*schema.Column{CasBackendsColumns[9]}, RefColumns: []*schema.Column{OrganizationsColumns[0]}, OnDelete: schema.Cascade, }, diff --git a/app/controlplane/internal/data/ent/mutation.go b/app/controlplane/internal/data/ent/mutation.go index 5ea3819d2..ee040bc54 100644 --- a/app/controlplane/internal/data/ent/mutation.go +++ b/app/controlplane/internal/data/ent/mutation.go @@ -56,12 +56,13 @@ type CASBackendMutation struct { op Op typ string id *uuid.UUID - name *string + location *string + provider *biz.CASBackendProvider + description *string secret_name *string created_at *time.Time validation_status *biz.CASBackendValidationStatus validated_at *time.Time - provider *biz.CASBackendProvider _default *bool clearedFields map[string]struct{} organization *uuid.UUID @@ -178,40 +179,125 @@ func (m *CASBackendMutation) IDs(ctx context.Context) ([]uuid.UUID, error) { } } -// SetName sets the "name" field. -func (m *CASBackendMutation) SetName(s string) { - m.name = &s +// SetLocation sets the "location" field. +func (m *CASBackendMutation) SetLocation(s string) { + m.location = &s } -// Name returns the value of the "name" field in the mutation. -func (m *CASBackendMutation) Name() (r string, exists bool) { - v := m.name +// Location returns the value of the "location" field in the mutation. +func (m *CASBackendMutation) Location() (r string, exists bool) { + v := m.location if v == nil { return } return *v, true } -// OldName returns the old "name" field's value of the CASBackend entity. +// OldLocation returns the old "location" field's value of the CASBackend entity. // If the CASBackend object wasn't provided to the builder, the object is fetched from the database. // An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *CASBackendMutation) OldName(ctx context.Context) (v string, err error) { +func (m *CASBackendMutation) OldLocation(ctx context.Context) (v string, err error) { if !m.op.Is(OpUpdateOne) { - return v, errors.New("OldName is only allowed on UpdateOne operations") + return v, errors.New("OldLocation is only allowed on UpdateOne operations") } if m.id == nil || m.oldValue == nil { - return v, errors.New("OldName requires an ID field in the mutation") + return v, errors.New("OldLocation requires an ID field in the mutation") } oldValue, err := m.oldValue(ctx) if err != nil { - return v, fmt.Errorf("querying old value for OldName: %w", err) + return v, fmt.Errorf("querying old value for OldLocation: %w", err) } - return oldValue.Name, nil + return oldValue.Location, nil } -// ResetName resets all changes to the "name" field. -func (m *CASBackendMutation) ResetName() { - m.name = nil +// ResetLocation resets all changes to the "location" field. +func (m *CASBackendMutation) ResetLocation() { + m.location = nil +} + +// SetProvider sets the "provider" field. +func (m *CASBackendMutation) SetProvider(bbp biz.CASBackendProvider) { + m.provider = &bbp +} + +// Provider returns the value of the "provider" field in the mutation. +func (m *CASBackendMutation) Provider() (r biz.CASBackendProvider, exists bool) { + v := m.provider + if v == nil { + return + } + return *v, true +} + +// OldProvider returns the old "provider" field's value of the CASBackend entity. +// If the CASBackend object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *CASBackendMutation) OldProvider(ctx context.Context) (v biz.CASBackendProvider, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProvider is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProvider requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProvider: %w", err) + } + return oldValue.Provider, nil +} + +// ResetProvider resets all changes to the "provider" field. +func (m *CASBackendMutation) ResetProvider() { + m.provider = nil +} + +// SetDescription sets the "description" field. +func (m *CASBackendMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *CASBackendMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" field's value of the CASBackend entity. +// If the CASBackend object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *CASBackendMutation) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ClearDescription clears the value of the "description" field. +func (m *CASBackendMutation) ClearDescription() { + m.description = nil + m.clearedFields[casbackend.FieldDescription] = struct{}{} +} + +// DescriptionCleared returns if the "description" field was cleared in this mutation. +func (m *CASBackendMutation) DescriptionCleared() bool { + _, ok := m.clearedFields[casbackend.FieldDescription] + return ok +} + +// ResetDescription resets all changes to the "description" field. +func (m *CASBackendMutation) ResetDescription() { + m.description = nil + delete(m.clearedFields, casbackend.FieldDescription) } // SetSecretName sets the "secret_name" field. @@ -358,42 +444,6 @@ func (m *CASBackendMutation) ResetValidatedAt() { m.validated_at = nil } -// SetProvider sets the "provider" field. -func (m *CASBackendMutation) SetProvider(bbp biz.CASBackendProvider) { - m.provider = &bbp -} - -// Provider returns the value of the "provider" field in the mutation. -func (m *CASBackendMutation) Provider() (r biz.CASBackendProvider, exists bool) { - v := m.provider - if v == nil { - return - } - return *v, true -} - -// OldProvider returns the old "provider" field's value of the CASBackend entity. -// If the CASBackend object wasn't provided to the builder, the object is fetched from the database. -// An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *CASBackendMutation) OldProvider(ctx context.Context) (v biz.CASBackendProvider, err error) { - if !m.op.Is(OpUpdateOne) { - return v, errors.New("OldProvider is only allowed on UpdateOne operations") - } - if m.id == nil || m.oldValue == nil { - return v, errors.New("OldProvider requires an ID field in the mutation") - } - oldValue, err := m.oldValue(ctx) - if err != nil { - return v, fmt.Errorf("querying old value for OldProvider: %w", err) - } - return oldValue.Provider, nil -} - -// ResetProvider resets all changes to the "provider" field. -func (m *CASBackendMutation) ResetProvider() { - m.provider = nil -} - // SetDefault sets the "default" field. func (m *CASBackendMutation) SetDefault(b bool) { m._default = &b @@ -557,9 +607,15 @@ func (m *CASBackendMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *CASBackendMutation) Fields() []string { - fields := make([]string, 0, 7) - if m.name != nil { - fields = append(fields, casbackend.FieldName) + fields := make([]string, 0, 8) + if m.location != nil { + fields = append(fields, casbackend.FieldLocation) + } + if m.provider != nil { + fields = append(fields, casbackend.FieldProvider) + } + if m.description != nil { + fields = append(fields, casbackend.FieldDescription) } if m.secret_name != nil { fields = append(fields, casbackend.FieldSecretName) @@ -573,9 +629,6 @@ func (m *CASBackendMutation) Fields() []string { if m.validated_at != nil { fields = append(fields, casbackend.FieldValidatedAt) } - if m.provider != nil { - fields = append(fields, casbackend.FieldProvider) - } if m._default != nil { fields = append(fields, casbackend.FieldDefault) } @@ -587,8 +640,12 @@ func (m *CASBackendMutation) Fields() []string { // schema. func (m *CASBackendMutation) Field(name string) (ent.Value, bool) { switch name { - case casbackend.FieldName: - return m.Name() + case casbackend.FieldLocation: + return m.Location() + case casbackend.FieldProvider: + return m.Provider() + case casbackend.FieldDescription: + return m.Description() case casbackend.FieldSecretName: return m.SecretName() case casbackend.FieldCreatedAt: @@ -597,8 +654,6 @@ func (m *CASBackendMutation) Field(name string) (ent.Value, bool) { return m.ValidationStatus() case casbackend.FieldValidatedAt: return m.ValidatedAt() - case casbackend.FieldProvider: - return m.Provider() case casbackend.FieldDefault: return m.Default() } @@ -610,8 +665,12 @@ func (m *CASBackendMutation) Field(name string) (ent.Value, bool) { // database failed. func (m *CASBackendMutation) OldField(ctx context.Context, name string) (ent.Value, error) { switch name { - case casbackend.FieldName: - return m.OldName(ctx) + case casbackend.FieldLocation: + return m.OldLocation(ctx) + case casbackend.FieldProvider: + return m.OldProvider(ctx) + case casbackend.FieldDescription: + return m.OldDescription(ctx) case casbackend.FieldSecretName: return m.OldSecretName(ctx) case casbackend.FieldCreatedAt: @@ -620,8 +679,6 @@ func (m *CASBackendMutation) OldField(ctx context.Context, name string) (ent.Val return m.OldValidationStatus(ctx) case casbackend.FieldValidatedAt: return m.OldValidatedAt(ctx) - case casbackend.FieldProvider: - return m.OldProvider(ctx) case casbackend.FieldDefault: return m.OldDefault(ctx) } @@ -633,12 +690,26 @@ func (m *CASBackendMutation) OldField(ctx context.Context, name string) (ent.Val // type. func (m *CASBackendMutation) SetField(name string, value ent.Value) error { switch name { - case casbackend.FieldName: + case casbackend.FieldLocation: v, ok := value.(string) if !ok { return fmt.Errorf("unexpected type %T for field %s", value, name) } - m.SetName(v) + m.SetLocation(v) + return nil + case casbackend.FieldProvider: + v, ok := value.(biz.CASBackendProvider) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProvider(v) + return nil + case casbackend.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) return nil case casbackend.FieldSecretName: v, ok := value.(string) @@ -668,13 +739,6 @@ func (m *CASBackendMutation) SetField(name string, value ent.Value) error { } m.SetValidatedAt(v) return nil - case casbackend.FieldProvider: - v, ok := value.(biz.CASBackendProvider) - if !ok { - return fmt.Errorf("unexpected type %T for field %s", value, name) - } - m.SetProvider(v) - return nil case casbackend.FieldDefault: v, ok := value.(bool) if !ok { @@ -711,7 +775,11 @@ func (m *CASBackendMutation) AddField(name string, value ent.Value) error { // ClearedFields returns all nullable fields that were cleared during this // mutation. func (m *CASBackendMutation) ClearedFields() []string { - return nil + var fields []string + if m.FieldCleared(casbackend.FieldDescription) { + fields = append(fields, casbackend.FieldDescription) + } + return fields } // FieldCleared returns a boolean indicating if a field with the given name was @@ -724,6 +792,11 @@ func (m *CASBackendMutation) FieldCleared(name string) bool { // ClearField clears the value of the field with the given name. It returns an // error if the field is not defined in the schema. func (m *CASBackendMutation) ClearField(name string) error { + switch name { + case casbackend.FieldDescription: + m.ClearDescription() + return nil + } return fmt.Errorf("unknown CASBackend nullable field %s", name) } @@ -731,8 +804,14 @@ func (m *CASBackendMutation) ClearField(name string) error { // It returns an error if the field is not defined in the schema. func (m *CASBackendMutation) ResetField(name string) error { switch name { - case casbackend.FieldName: - m.ResetName() + case casbackend.FieldLocation: + m.ResetLocation() + return nil + case casbackend.FieldProvider: + m.ResetProvider() + return nil + case casbackend.FieldDescription: + m.ResetDescription() return nil case casbackend.FieldSecretName: m.ResetSecretName() @@ -746,9 +825,6 @@ func (m *CASBackendMutation) ResetField(name string) error { case casbackend.FieldValidatedAt: m.ResetValidatedAt() return nil - case casbackend.FieldProvider: - m.ResetProvider() - return nil case casbackend.FieldDefault: m.ResetDefault() return nil diff --git a/app/controlplane/internal/data/ent/runtime.go b/app/controlplane/internal/data/ent/runtime.go index 8c776c567..7a7bc953f 100644 --- a/app/controlplane/internal/data/ent/runtime.go +++ b/app/controlplane/internal/data/ent/runtime.go @@ -27,15 +27,15 @@ func init() { casbackendFields := schema.CASBackend{}.Fields() _ = casbackendFields // casbackendDescCreatedAt is the schema descriptor for created_at field. - casbackendDescCreatedAt := casbackendFields[3].Descriptor() + casbackendDescCreatedAt := casbackendFields[5].Descriptor() // casbackend.DefaultCreatedAt holds the default value on creation for the created_at field. casbackend.DefaultCreatedAt = casbackendDescCreatedAt.Default.(func() time.Time) // casbackendDescValidatedAt is the schema descriptor for validated_at field. - casbackendDescValidatedAt := casbackendFields[5].Descriptor() + casbackendDescValidatedAt := casbackendFields[7].Descriptor() // casbackend.DefaultValidatedAt holds the default value on creation for the validated_at field. casbackend.DefaultValidatedAt = casbackendDescValidatedAt.Default.(func() time.Time) // casbackendDescDefault is the schema descriptor for default field. - casbackendDescDefault := casbackendFields[7].Descriptor() + casbackendDescDefault := casbackendFields[8].Descriptor() // casbackend.DefaultDefault holds the default value on creation for the default field. casbackend.DefaultDefault = casbackendDescDefault.Default.(bool) // casbackendDescID is the schema descriptor for id field. diff --git a/app/controlplane/internal/data/ent/schema-viz.html b/app/controlplane/internal/data/ent/schema-viz.html index cda3ec3aa..8132086af 100644 --- a/app/controlplane/internal/data/ent/schema-viz.html +++ b/app/controlplane/internal/data/ent/schema-viz.html @@ -70,7 +70,7 @@ } - const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"default\",\"type\":\"bool\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"}]}],\"edges\":[{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"RobotAccount\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"}]}"); + const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"}]}],\"edges\":[{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"RobotAccount\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"}]}"); const nodes = new vis.DataSet((entGraph.nodes || []).map(n => ({ id: n.id, diff --git a/app/controlplane/internal/data/ent/schema/casbackend.go b/app/controlplane/internal/data/ent/schema/casbackend.go index 18e26782d..e0ce284d6 100644 --- a/app/controlplane/internal/data/ent/schema/casbackend.go +++ b/app/controlplane/internal/data/ent/schema/casbackend.go @@ -34,7 +34,11 @@ type CASBackend struct { func (CASBackend) Fields() []ent.Field { return []ent.Field{ field.UUID("id", uuid.UUID{}).Default(uuid.New).Unique(), - field.String("name"), + // NOTE: neither the location nor the provider can be updated + // CAS backend location, i.e S3 bucket name, OCI repository name + field.String("location").Immutable(), + field.Enum("provider").GoType(biz.CASBackendProvider("")).Immutable(), + field.String("description").Optional(), field.String("secret_name"), field.Time("created_at"). Default(time.Now). @@ -45,7 +49,6 @@ func (CASBackend) Fields() []ent.Field { Default(string(biz.CASBackendValidationOK)), field.Time("validated_at").Default(time.Now). Annotations(&entsql.Annotation{Default: "CURRENT_TIMESTAMP"}), - field.Enum("provider").GoType(biz.CASBackendProvider("")), field.Bool("default").Default(false), } } diff --git a/app/controlplane/internal/server/grpc.go b/app/controlplane/internal/server/grpc.go index 1f97add7f..95c90244a 100644 --- a/app/controlplane/internal/server/grpc.go +++ b/app/controlplane/internal/server/grpc.go @@ -180,7 +180,7 @@ func requireCurrentUserMatcher() selector.MatchFunc { func requireFullyConfiguredOrgMatcher() selector.MatchFunc { // We do not need to remove other endpoints since this matcher is called once the requireCurrentUserMatcher one has passed - const skipRegexp = "controlplane.v1.OCIRepositoryService/.*|controlplane.v1.ContextService/Current|/controlplane.v1.OrganizationService/.*|/controlplane.v1.AuthService/DeleteAccount" + const skipRegexp = "controlplane.v1.OCIRepositoryService/.*|controlplane.v1.ContextService/Current|/controlplane.v1.OrganizationService/.*|/controlplane.v1.AuthService/DeleteAccount|controlplane.v1.CASBackendService/.*" return func(ctx context.Context, operation string) bool { r := regexp.MustCompile(skipRegexp) diff --git a/app/controlplane/internal/server/grpc_test.go b/app/controlplane/internal/server/grpc_test.go index 18dc6c386..80e49f00a 100644 --- a/app/controlplane/internal/server/grpc_test.go +++ b/app/controlplane/internal/server/grpc_test.go @@ -51,6 +51,8 @@ func TestRequireFullyConfiguredOrgMatcher(t *testing.T) { {"/controlplane.v1.OCIRepositoryService/Save", false}, {"/controlplane.v1.OrganizationService/ListMemberships", false}, {"/controlplane.v1.OrganizationService/SetCurrent", false}, + {"/controlplane.v1.CASBackendService/List", false}, + {"/controlplane.v1.CASBackendService/Add", false}, } matchFunc := requireFullyConfiguredOrgMatcher() diff --git a/app/controlplane/internal/service/attestation.go b/app/controlplane/internal/service/attestation.go index 1caef6821..c1d3b0598 100644 --- a/app/controlplane/internal/service/attestation.go +++ b/app/controlplane/internal/service/attestation.go @@ -270,7 +270,7 @@ func (s *AttestationService) GetUploadCreds(ctx context.Context, req *cpAPI.Atte return nil, errors.NotFound("not found", "workflow run has no CAS backend") } - s.log.Infow("msg", "generating upload credentials for CAS backend", "ID", wRun.CASBackends[0].ID, "name", wRun.CASBackends[0].Name, "workflowRun", req.WorkflowRunId) + s.log.Infow("msg", "generating upload credentials for CAS backend", "ID", wRun.CASBackends[0].ID, "name", wRun.CASBackends[0].Location, "workflowRun", req.WorkflowRunId) secretName = wRun.CASBackends[0].SecretName } diff --git a/app/controlplane/internal/service/casbackend.go b/app/controlplane/internal/service/casbackend.go index a96bd3181..e05b85123 100644 --- a/app/controlplane/internal/service/casbackend.go +++ b/app/controlplane/internal/service/casbackend.go @@ -21,6 +21,7 @@ import ( pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" sl "github.com/chainloop-dev/chainloop/internal/servicelogger" + "github.com/go-kratos/kratos/v2/errors" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -57,16 +58,42 @@ func (s *CASBackendService) List(ctx context.Context, _ *pb.CASBackendServiceLis return &pb.CASBackendServiceListResponse{Result: res}, nil } -func bizOCASBackendToPb(repo *biz.CASBackend) *pb.CASBackendItem { +func (s *CASBackendService) Create(ctx context.Context, req *pb.CASBackendServiceCreateRequest) (*pb.CASBackendServiceCreateResponse, error) { + _, currentOrg, err := loadCurrentUserAndOrg(ctx) + if err != nil { + return nil, err + } + + if err := req.ValidateAll(); err != nil { + return nil, errors.BadRequest("invalid config", err.Error()) + } + + credsJSON, err := req.Credentials.MarshalJSON() + if err != nil { + return nil, errors.BadRequest("invalid config", "config is invalid") + } + + // For now we only support one backend which is set as default + res, err := s.uc.Create(ctx, currentOrg.ID, req.Location, req.Description, biz.CASBackendOCI, credsJSON, req.Default) + if err != nil && biz.IsErrValidation(err) { + return nil, errors.BadRequest("invalid CAS backend", err.Error()) + } else if err != nil { + return nil, sl.LogAndMaskErr(err, s.log) + } + + return &pb.CASBackendServiceCreateResponse{Result: bizOCASBackendToPb(res)}, nil +} + +func bizOCASBackendToPb(in *biz.CASBackend) *pb.CASBackendItem { r := &pb.CASBackendItem{ - Id: repo.ID.String(), Name: repo.Name, - CreatedAt: timestamppb.New(*repo.CreatedAt), - ValidatedAt: timestamppb.New(*repo.ValidatedAt), - Provider: string(repo.Provider), - Default: repo.Default, + Id: in.ID.String(), Location: in.Location, Description: in.Description, + CreatedAt: timestamppb.New(*in.CreatedAt), + ValidatedAt: timestamppb.New(*in.ValidatedAt), + Provider: string(in.Provider), + Default: in.Default, } - switch repo.ValidationStatus { + switch in.ValidationStatus { case biz.CASBackendValidationOK: r.ValidationStatus = pb.CASBackendItem_VALIDATION_STATUS_OK case biz.CASBackendValidationFailed: diff --git a/app/controlplane/internal/service/ocirepository.go b/app/controlplane/internal/service/ocirepository.go index dc474c5e9..607e94729 100644 --- a/app/controlplane/internal/service/ocirepository.go +++ b/app/controlplane/internal/service/ocirepository.go @@ -78,7 +78,7 @@ func (s *OCIRepositoryService) Save(ctx context.Context, req *pb.OCIRepositorySe func bizOCIRepoToPb(repo *biz.CASBackend) *pb.OCIRepositoryItem { r := &pb.OCIRepositoryItem{ - Id: repo.ID.String(), Repo: repo.Name, CreatedAt: timestamppb.New(*repo.CreatedAt), + Id: repo.ID.String(), Repo: repo.Location, CreatedAt: timestamppb.New(*repo.CreatedAt), } switch repo.ValidationStatus {