From f83d34025f474e6570c949bee78dfd73d63732c3 Mon Sep 17 00:00:00 2001 From: Javier Rodriguez Date: Thu, 13 Jun 2024 18:40:40 +0200 Subject: [PATCH 1/4] feat(auto-onboarding): Allow auto-onboarding on organizations Signed-off-by: Javier Rodriguez --- Makefile | 2 +- app/controlplane/cmd/wire.go | 2 +- app/controlplane/cmd/wire_gen.go | 3 +- app/controlplane/configs/config.devel.yaml | 5 + .../conf/controlplane/config/v1/conf.pb.go | 493 ++++++++++++------ .../conf/controlplane/config/v1/conf.proto | 17 + app/controlplane/internal/service/auth.go | 69 ++- .../internal/service/auth_test.go | 106 ++++ .../pkg/biz/mocks/OrganizationRepo.go | 57 +- app/controlplane/pkg/biz/organization.go | 27 + app/controlplane/pkg/data/organization.go | 13 + 11 files changed, 618 insertions(+), 176 deletions(-) diff --git a/Makefile b/Makefile index 232875402..bd0f3d39c 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ api: .PHONY: config # generate config proto config: - cd ./internal/credentials/api && buf generate + cd ./pkg/credentials/api && buf generate make -C ./app/controlplane config make -C ./app/artifact-cas config diff --git a/app/controlplane/cmd/wire.go b/app/controlplane/cmd/wire.go index 296a6b98d..776c9c631 100644 --- a/app/controlplane/cmd/wire.go +++ b/app/controlplane/cmd/wire.go @@ -48,7 +48,7 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.Availabl wire.Bind(new(biz.CASClient), new(*biz.CASClientUseCase)), serviceOpts, wire.Value([]biz.CASClientOpts{}), - wire.FieldsOf(new(*conf.Bootstrap), "Server", "Auth", "Data", "CasServer", "ReferrerSharedIndex"), + wire.FieldsOf(new(*conf.Bootstrap), "Server", "Auth", "Data", "CasServer", "ReferrerSharedIndex", "Onboarding"), wire.FieldsOf(new(*conf.Data), "Database"), dispatcher.New, authz.NewDatabaseEnforcer, diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index 383ff3b80..c1aeb76fb 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -97,8 +97,9 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l cleanup() return nil, nil, err } + onboardingSpec := bootstrap.Onboarding confServer := bootstrap.Server - authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, confServer, v2...) + authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, onboardingSpec, confServer, v2...) if err != nil { cleanup() return nil, nil, err diff --git a/app/controlplane/configs/config.devel.yaml b/app/controlplane/configs/config.devel.yaml index 49b5c379a..32db799a2 100644 --- a/app/controlplane/configs/config.devel.yaml +++ b/app/controlplane/configs/config.devel.yaml @@ -58,3 +58,8 @@ auth: # enabled: true # allowed_orgs: # - deadbeef + +onboarding: + auto_onboard_organizations: + - name: "read-only-demo" + role: "viewer" diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go index 4f0a6a605..efe8a08f9 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go @@ -57,6 +57,8 @@ type Bootstrap struct { ReferrerSharedIndex *ReferrerSharedIndex `protobuf:"bytes,8,opt,name=referrer_shared_index,json=referrerSharedIndex,proto3" json:"referrer_shared_index,omitempty"` // The certificate authority used for keyless signing CertificateAuthority *CA `protobuf:"bytes,9,opt,name=certificate_authority,json=certificateAuthority,proto3" json:"certificate_authority,omitempty"` + // Configuration for onboarding users in organizations with specific roles + Onboarding *OnboardingSpec `protobuf:"bytes,10,opt,name=onboarding,proto3" json:"onboarding,omitempty"` } func (x *Bootstrap) Reset() { @@ -154,6 +156,13 @@ func (x *Bootstrap) GetCertificateAuthority() *CA { return nil } +func (x *Bootstrap) GetOnboarding() *OnboardingSpec { + if x != nil { + return x.Onboarding + } + return nil +} + // Configuration used to enable a shared index API endpoint that can be used to discover metadata referrers // To populate the shared index you need to enable the feature and configure the allowed orgs // The reason to have an org allowList is to avoid leaking metadata from other organizations and set the stage for a trusted publisher model @@ -467,6 +476,113 @@ type CA_FileCa struct { func (*CA_FileCa) isCA_Ca() {} +// OnboardingSpec is a configuration to automatically onboard users in organizations with specific roles +type OnboardingSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // auto_onboard_organizations is a list of organizations to automatically onboard users with specific roles + AutoOnboardOrganizations []*AutoOnboardOrganization `protobuf:"bytes,1,rep,name=auto_onboard_organizations,json=autoOnboardOrganizations,proto3" json:"auto_onboard_organizations,omitempty"` +} + +func (x *OnboardingSpec) Reset() { + *x = OnboardingSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_config_v1_conf_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OnboardingSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OnboardingSpec) ProtoMessage() {} + +func (x *OnboardingSpec) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_config_v1_conf_proto_msgTypes[6] + 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 OnboardingSpec.ProtoReflect.Descriptor instead. +func (*OnboardingSpec) Descriptor() ([]byte, []int) { + return file_controlplane_config_v1_conf_proto_rawDescGZIP(), []int{6} +} + +func (x *OnboardingSpec) GetAutoOnboardOrganizations() []*AutoOnboardOrganization { + if x != nil { + return x.AutoOnboardOrganizations + } + return nil +} + +// AutoOnboardOrganization is a configuration to automatically onboard an organization with a specific role +type AutoOnboardOrganization struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // name is the name of the organization + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // role is the role to assign to the user. For the moment, only "viewer" is supported + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` +} + +func (x *AutoOnboardOrganization) Reset() { + *x = AutoOnboardOrganization{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AutoOnboardOrganization) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AutoOnboardOrganization) ProtoMessage() {} + +func (x *AutoOnboardOrganization) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] + 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 AutoOnboardOrganization.ProtoReflect.Descriptor instead. +func (*AutoOnboardOrganization) Descriptor() ([]byte, []int) { + return file_controlplane_config_v1_conf_proto_rawDescGZIP(), []int{7} +} + +func (x *AutoOnboardOrganization) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AutoOnboardOrganization) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + type Bootstrap_Observability struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -478,7 +594,7 @@ type Bootstrap_Observability struct { func (x *Bootstrap_Observability) Reset() { *x = Bootstrap_Observability{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[6] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -491,7 +607,7 @@ func (x *Bootstrap_Observability) String() string { func (*Bootstrap_Observability) ProtoMessage() {} func (x *Bootstrap_Observability) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[6] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -532,7 +648,7 @@ type Bootstrap_CASServer struct { func (x *Bootstrap_CASServer) Reset() { *x = Bootstrap_CASServer{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -545,7 +661,7 @@ func (x *Bootstrap_CASServer) String() string { func (*Bootstrap_CASServer) ProtoMessage() {} func (x *Bootstrap_CASServer) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -594,7 +710,7 @@ type Bootstrap_Observability_Sentry struct { func (x *Bootstrap_Observability_Sentry) Reset() { *x = Bootstrap_Observability_Sentry{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -607,7 +723,7 @@ func (x *Bootstrap_Observability_Sentry) String() string { func (*Bootstrap_Observability_Sentry) ProtoMessage() {} func (x *Bootstrap_Observability_Sentry) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -653,7 +769,7 @@ type Server_HTTP struct { func (x *Server_HTTP) Reset() { *x = Server_HTTP{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -666,7 +782,7 @@ func (x *Server_HTTP) String() string { func (*Server_HTTP) ProtoMessage() {} func (x *Server_HTTP) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -723,7 +839,7 @@ type Server_TLS struct { func (x *Server_TLS) Reset() { *x = Server_TLS{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -736,7 +852,7 @@ func (x *Server_TLS) String() string { func (*Server_TLS) ProtoMessage() {} func (x *Server_TLS) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -780,7 +896,7 @@ type Server_GRPC struct { func (x *Server_GRPC) Reset() { *x = Server_GRPC{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -793,7 +909,7 @@ func (x *Server_GRPC) String() string { func (*Server_GRPC) ProtoMessage() {} func (x *Server_GRPC) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -849,7 +965,7 @@ type Data_Database struct { func (x *Data_Database) Reset() { *x = Data_Database{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -862,7 +978,7 @@ func (x *Data_Database) String() string { func (*Data_Database) ProtoMessage() {} func (x *Data_Database) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -906,7 +1022,7 @@ type Auth_OIDC struct { func (x *Auth_OIDC) Reset() { *x = Auth_OIDC{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -919,7 +1035,7 @@ func (x *Auth_OIDC) String() string { func (*Auth_OIDC) ProtoMessage() {} func (x *Auth_OIDC) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -976,7 +1092,7 @@ type CA_FileCA struct { func (x *CA_FileCA) Reset() { *x = CA_FileCA{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -989,7 +1105,7 @@ func (x *CA_FileCA) String() string { func (*CA_FileCA) ProtoMessage() {} func (x *CA_FileCA) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1038,7 +1154,7 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x99, 0x07, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x07, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x12, 0x36, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, @@ -1077,117 +1193,134 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x52, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x1a, 0x9d, 0x01, 0x0a, 0x0d, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x4e, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, - 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x42, - 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x73, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x1a, 0x3c, 0x0a, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, - 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x1a, 0x8b, 0x01, 0x0a, 0x09, 0x43, 0x41, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x3f, 0x0a, 0x04, 0x67, 0x72, 0x70, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x69, 0x74, 0x79, 0x12, 0x46, 0x0a, 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, + 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, + 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x1a, 0x9d, 0x01, 0x0a, 0x0d, + 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x4e, 0x0a, + 0x06, 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, + 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x53, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x1a, 0x3c, 0x0a, + 0x06, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x8b, 0x01, 0x0a, 0x09, + 0x43, 0x41, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x04, 0x67, 0x72, 0x70, + 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x42, 0x06, 0xba, 0x48, + 0x03, 0xc8, 0x01, 0x01, 0x52, 0x04, 0x67, 0x72, 0x70, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x22, 0x52, 0x0a, 0x13, 0x52, 0x65, 0x66, + 0x65, 0x72, 0x72, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x6f, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x4f, 0x72, 0x67, 0x73, 0x22, 0xd3, 0x04, + 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x04, 0x68, 0x74, 0x74, + 0x70, 0x12, 0x37, 0x0a, 0x04, 0x67, 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x47, 0x52, 0x50, 0x43, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x04, 0x67, 0x72, - 0x70, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x21, - 0x0a, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, - 0x6c, 0x22, 0x52, 0x0a, 0x13, 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x53, 0x68, 0x61, - 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x6f, 0x72, - 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, - 0x64, 0x4f, 0x72, 0x67, 0x73, 0x22, 0xd3, 0x04, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x12, 0x37, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x47, 0x52, 0x50, 0x43, 0x52, 0x04, 0x67, 0x72, 0x70, 0x63, 0x12, 0x46, 0x0a, 0x0c, 0x68, 0x74, + 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x1a, 0x8c, 0x01, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x18, 0x0a, 0x07, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x55, 0x72, 0x6c, 0x12, 0x33, 0x0a, 0x07, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x1a, 0x48, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x1a, 0xb5, 0x01, 0x0a, 0x04, + 0x47, 0x52, 0x50, 0x43, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1b, + 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, + 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x12, 0x41, 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x4c, 0x53, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x22, 0x85, 0x01, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, - 0x54, 0x54, 0x50, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x37, 0x0a, 0x04, 0x67, 0x72, 0x70, - 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x1a, + 0x3a, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, + 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xf5, 0x02, 0x0a, 0x04, + 0x41, 0x75, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x19, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x6a, 0x77, 0x73, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x64, 0x4a, 0x77, 0x73, 0x48, 0x6d, 0x61, 0x63, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, + 0x1d, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, + 0x0a, 0x22, 0x63, 0x61, 0x73, 0x5f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x63, 0x61, 0x73, 0x52, + 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x35, 0x0a, 0x04, 0x6f, 0x69, 0x64, + 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x04, 0x67, 0x72, - 0x70, 0x63, 0x12, 0x46, 0x0a, 0x0c, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x0b, 0x68, - 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x8c, 0x01, 0x0a, 0x04, 0x48, - 0x54, 0x54, 0x50, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, - 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, - 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x55, 0x72, 0x6c, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x1a, 0x48, 0x0a, 0x03, 0x54, 0x4c, 0x53, - 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, - 0x4b, 0x65, 0x79, 0x1a, 0xb5, 0x01, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x12, 0x18, 0x0a, 0x07, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1b, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x61, - 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x41, 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x4c, 0x53, - 0x52, 0x09, 0x74, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x85, 0x01, 0x0a, 0x04, - 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x1a, 0x3a, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x22, 0xf5, 0x02, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x19, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6a, 0x77, 0x73, 0x5f, 0x68, 0x6d, - 0x61, 0x63, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x16, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4a, 0x77, 0x73, 0x48, 0x6d, 0x61, - 0x63, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x6c, - 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x22, 0x63, 0x61, 0x73, 0x5f, 0x72, 0x6f, - 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x76, - 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x1d, 0x63, 0x61, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, - 0x68, 0x12, 0x35, 0x0a, 0x04, 0x6f, 0x69, 0x64, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x4f, 0x49, - 0x44, 0x43, 0x52, 0x04, 0x6f, 0x69, 0x64, 0x63, 0x1a, 0x90, 0x01, 0x0a, 0x04, 0x4f, 0x49, 0x44, - 0x43, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x72, - 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x02, - 0x43, 0x41, 0x12, 0x3c, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x2e, - 0x46, 0x69, 0x6c, 0x65, 0x43, 0x41, 0x48, 0x00, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, - 0x1a, 0x5b, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x41, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, - 0x72, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, - 0x65, 0x72, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, - 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, - 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, 0x0a, - 0x02, 0x63, 0x61, 0x42, 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x3b, - 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x04, 0x6f, 0x69, 0x64, 0x63, + 0x1a, 0x90, 0x01, 0x0a, 0x04, 0x4f, 0x49, 0x44, 0x43, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, + 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x02, 0x43, 0x41, 0x12, 0x3c, 0x0a, 0x07, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x41, 0x48, 0x00, + 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x1a, 0x5b, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x65, + 0x43, 0x41, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, + 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, + 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, + 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, 0x0a, 0x02, 0x63, 0x61, 0x22, 0x7f, 0x0a, 0x0e, 0x4f, + 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x6d, 0x0a, + 0x1a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x6f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x4f, + 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x18, 0x61, 0x75, 0x74, 0x6f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x41, 0x0a, 0x17, + 0x41, 0x75, 0x74, 0x6f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, + 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, + 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, + 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1202,7 +1335,7 @@ func file_controlplane_config_v1_conf_proto_rawDescGZIP() []byte { return file_controlplane_config_v1_conf_proto_rawDescData } -var file_controlplane_config_v1_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_controlplane_config_v1_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_controlplane_config_v1_conf_proto_goTypes = []interface{}{ (*Bootstrap)(nil), // 0: controlplane.config.v1.Bootstrap (*ReferrerSharedIndex)(nil), // 1: controlplane.config.v1.ReferrerSharedIndex @@ -1210,43 +1343,47 @@ var file_controlplane_config_v1_conf_proto_goTypes = []interface{}{ (*Data)(nil), // 3: controlplane.config.v1.Data (*Auth)(nil), // 4: controlplane.config.v1.Auth (*CA)(nil), // 5: controlplane.config.v1.CA - (*Bootstrap_Observability)(nil), // 6: controlplane.config.v1.Bootstrap.Observability - (*Bootstrap_CASServer)(nil), // 7: controlplane.config.v1.Bootstrap.CASServer - (*Bootstrap_Observability_Sentry)(nil), // 8: controlplane.config.v1.Bootstrap.Observability.Sentry - (*Server_HTTP)(nil), // 9: controlplane.config.v1.Server.HTTP - (*Server_TLS)(nil), // 10: controlplane.config.v1.Server.TLS - (*Server_GRPC)(nil), // 11: controlplane.config.v1.Server.GRPC - (*Data_Database)(nil), // 12: controlplane.config.v1.Data.Database - (*Auth_OIDC)(nil), // 13: controlplane.config.v1.Auth.OIDC - (*CA_FileCA)(nil), // 14: controlplane.config.v1.CA.FileCA - (*v1.Credentials)(nil), // 15: credentials.v1.Credentials - (*durationpb.Duration)(nil), // 16: google.protobuf.Duration + (*OnboardingSpec)(nil), // 6: controlplane.config.v1.OnboardingSpec + (*AutoOnboardOrganization)(nil), // 7: controlplane.config.v1.AutoOnboardOrganization + (*Bootstrap_Observability)(nil), // 8: controlplane.config.v1.Bootstrap.Observability + (*Bootstrap_CASServer)(nil), // 9: controlplane.config.v1.Bootstrap.CASServer + (*Bootstrap_Observability_Sentry)(nil), // 10: controlplane.config.v1.Bootstrap.Observability.Sentry + (*Server_HTTP)(nil), // 11: controlplane.config.v1.Server.HTTP + (*Server_TLS)(nil), // 12: controlplane.config.v1.Server.TLS + (*Server_GRPC)(nil), // 13: controlplane.config.v1.Server.GRPC + (*Data_Database)(nil), // 14: controlplane.config.v1.Data.Database + (*Auth_OIDC)(nil), // 15: controlplane.config.v1.Auth.OIDC + (*CA_FileCA)(nil), // 16: controlplane.config.v1.CA.FileCA + (*v1.Credentials)(nil), // 17: credentials.v1.Credentials + (*durationpb.Duration)(nil), // 18: google.protobuf.Duration } var file_controlplane_config_v1_conf_proto_depIdxs = []int32{ 2, // 0: controlplane.config.v1.Bootstrap.server:type_name -> controlplane.config.v1.Server 3, // 1: controlplane.config.v1.Bootstrap.data:type_name -> controlplane.config.v1.Data 4, // 2: controlplane.config.v1.Bootstrap.auth:type_name -> controlplane.config.v1.Auth - 6, // 3: controlplane.config.v1.Bootstrap.observability:type_name -> controlplane.config.v1.Bootstrap.Observability - 15, // 4: controlplane.config.v1.Bootstrap.credentials_service:type_name -> credentials.v1.Credentials - 7, // 5: controlplane.config.v1.Bootstrap.cas_server:type_name -> controlplane.config.v1.Bootstrap.CASServer + 8, // 3: controlplane.config.v1.Bootstrap.observability:type_name -> controlplane.config.v1.Bootstrap.Observability + 17, // 4: controlplane.config.v1.Bootstrap.credentials_service:type_name -> credentials.v1.Credentials + 9, // 5: controlplane.config.v1.Bootstrap.cas_server:type_name -> controlplane.config.v1.Bootstrap.CASServer 1, // 6: controlplane.config.v1.Bootstrap.referrer_shared_index:type_name -> controlplane.config.v1.ReferrerSharedIndex 5, // 7: controlplane.config.v1.Bootstrap.certificate_authority:type_name -> controlplane.config.v1.CA - 9, // 8: controlplane.config.v1.Server.http:type_name -> controlplane.config.v1.Server.HTTP - 11, // 9: controlplane.config.v1.Server.grpc:type_name -> controlplane.config.v1.Server.GRPC - 9, // 10: controlplane.config.v1.Server.http_metrics:type_name -> controlplane.config.v1.Server.HTTP - 12, // 11: controlplane.config.v1.Data.database:type_name -> controlplane.config.v1.Data.Database - 13, // 12: controlplane.config.v1.Auth.oidc:type_name -> controlplane.config.v1.Auth.OIDC - 14, // 13: controlplane.config.v1.CA.file_ca:type_name -> controlplane.config.v1.CA.FileCA - 8, // 14: controlplane.config.v1.Bootstrap.Observability.sentry:type_name -> controlplane.config.v1.Bootstrap.Observability.Sentry - 11, // 15: controlplane.config.v1.Bootstrap.CASServer.grpc:type_name -> controlplane.config.v1.Server.GRPC - 16, // 16: controlplane.config.v1.Server.HTTP.timeout:type_name -> google.protobuf.Duration - 16, // 17: controlplane.config.v1.Server.GRPC.timeout:type_name -> google.protobuf.Duration - 10, // 18: controlplane.config.v1.Server.GRPC.tls_config:type_name -> controlplane.config.v1.Server.TLS - 19, // [19:19] is the sub-list for method output_type - 19, // [19:19] is the sub-list for method input_type - 19, // [19:19] is the sub-list for extension type_name - 19, // [19:19] is the sub-list for extension extendee - 0, // [0:19] is the sub-list for field type_name + 6, // 8: controlplane.config.v1.Bootstrap.onboarding:type_name -> controlplane.config.v1.OnboardingSpec + 11, // 9: controlplane.config.v1.Server.http:type_name -> controlplane.config.v1.Server.HTTP + 13, // 10: controlplane.config.v1.Server.grpc:type_name -> controlplane.config.v1.Server.GRPC + 11, // 11: controlplane.config.v1.Server.http_metrics:type_name -> controlplane.config.v1.Server.HTTP + 14, // 12: controlplane.config.v1.Data.database:type_name -> controlplane.config.v1.Data.Database + 15, // 13: controlplane.config.v1.Auth.oidc:type_name -> controlplane.config.v1.Auth.OIDC + 16, // 14: controlplane.config.v1.CA.file_ca:type_name -> controlplane.config.v1.CA.FileCA + 7, // 15: controlplane.config.v1.OnboardingSpec.auto_onboard_organizations:type_name -> controlplane.config.v1.AutoOnboardOrganization + 10, // 16: controlplane.config.v1.Bootstrap.Observability.sentry:type_name -> controlplane.config.v1.Bootstrap.Observability.Sentry + 13, // 17: controlplane.config.v1.Bootstrap.CASServer.grpc:type_name -> controlplane.config.v1.Server.GRPC + 18, // 18: controlplane.config.v1.Server.HTTP.timeout:type_name -> google.protobuf.Duration + 18, // 19: controlplane.config.v1.Server.GRPC.timeout:type_name -> google.protobuf.Duration + 12, // 20: controlplane.config.v1.Server.GRPC.tls_config:type_name -> controlplane.config.v1.Server.TLS + 21, // [21:21] is the sub-list for method output_type + 21, // [21:21] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_controlplane_config_v1_conf_proto_init() } @@ -1328,7 +1465,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Bootstrap_Observability); i { + switch v := v.(*OnboardingSpec); i { case 0: return &v.state case 1: @@ -1340,7 +1477,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Bootstrap_CASServer); i { + switch v := v.(*AutoOnboardOrganization); i { case 0: return &v.state case 1: @@ -1352,7 +1489,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Bootstrap_Observability_Sentry); i { + switch v := v.(*Bootstrap_Observability); i { case 0: return &v.state case 1: @@ -1364,7 +1501,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Server_HTTP); i { + switch v := v.(*Bootstrap_CASServer); i { case 0: return &v.state case 1: @@ -1376,7 +1513,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Server_TLS); i { + switch v := v.(*Bootstrap_Observability_Sentry); i { case 0: return &v.state case 1: @@ -1388,7 +1525,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Server_GRPC); i { + switch v := v.(*Server_HTTP); i { case 0: return &v.state case 1: @@ -1400,7 +1537,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Data_Database); i { + switch v := v.(*Server_TLS); i { case 0: return &v.state case 1: @@ -1412,7 +1549,7 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Auth_OIDC); i { + switch v := v.(*Server_GRPC); i { case 0: return &v.state case 1: @@ -1424,6 +1561,30 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Data_Database); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_config_v1_conf_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Auth_OIDC); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_config_v1_conf_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CA_FileCA); i { case 0: return &v.state @@ -1445,7 +1606,7 @@ func file_controlplane_config_v1_conf_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controlplane_config_v1_conf_proto_rawDesc, NumEnums: 0, - NumMessages: 15, + NumMessages: 17, NumExtensions: 0, NumServices: 0, }, diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto index a3f0eb740..8ba774462 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto @@ -58,6 +58,9 @@ message Bootstrap { // https://github.com/chainloop-dev/chainloop/blob/126f47b6c0803eac844b8e3e1a21d582f00e4dc6/app/artifact-cas/internal/service/download.go#L34 string download_url = 3; } + + // Configuration for onboarding users in organizations with specific roles + OnboardingSpec onboarding = 10; } // Configuration used to enable a shared index API endpoint that can be used to discover metadata referrers @@ -135,3 +138,17 @@ message CA { string key_pass = 3; } } + +// OnboardingSpec is a configuration to automatically onboard users in organizations with specific roles +message OnboardingSpec { + // auto_onboard_organizations is a list of organizations to automatically onboard users with specific roles + repeated AutoOnboardOrganization auto_onboard_organizations = 1; +} + +// AutoOnboardOrganization is a configuration to automatically onboard an organization with a specific role +message AutoOnboardOrganization { + // name is the name of the organization + string name = 1; + // role is the role to assign to the user. For the moment, only "viewer" is supported + string role = 2; +} \ No newline at end of file diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index 56994de08..d69e86a11 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -54,6 +54,11 @@ const ( shortLivedDuration = 10 * time.Second // opt-in logLivedDuration = 24 * time.Hour + + // AutoOnboarding roles for the organizations + AutoOnboardingViewerRole = "viewer" + AutoOnboardingAdminRole = "admin" + AutoOnboardingOwnerRole = "owner" ) type oauthHandler struct { @@ -72,9 +77,10 @@ type AuthService struct { membershipUseCase *biz.MembershipUseCase orgInvitesUseCase *biz.OrgInvitationUseCase AuthURLs *AuthURLs + onboardingConfig *conf.OnboardingSpec } -func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { +func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, onboardingConfig *conf.OnboardingSpec, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { oidcConfig := authConfig.GetOidc() if oidcConfig == nil { return nil, errors.New("oauth configuration missing") @@ -100,6 +106,7 @@ func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC AuthURLs: authURLs, membershipUseCase: mUC, orgInvitesUseCase: inviteUC, + onboardingConfig: onboardingConfig, }, nil } @@ -242,6 +249,11 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) ( svc.log.Infow("msg", "new user associated to an org", "org_id", currentOrg.ID, "user_id", u.ID) } + // Auto onboard the user to the organizations specified in the config + if err := autoOnboardOnOrganizations(ctx, svc, u); err != nil { + return http.StatusInternalServerError, sl.LogAndMaskErr(err, svc.log) + } + // Accept any pending invites if err := svc.orgInvitesUseCase.AcceptPendingInvitations(ctx, u.Email); err != nil { return http.StatusInternalServerError, sl.LogAndMaskErr(err, svc.log) @@ -289,6 +301,61 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) ( return http.StatusTemporaryRedirect, nil } +// autoOnboardOnOrganizations onboards the user to the organizations specified in the config +// If the organization does not exist, it will be created with an inline CAS backend +// If the user is not already a member of the organization, a membership will be created with the role specified in the config +func autoOnboardOnOrganizations(ctx context.Context, svc *AuthService, u *biz.User) error { + for _, spec := range svc.onboardingConfig.GetAutoOnboardOrganizations() { + // Ensure the organization exists or create it if it doesn't + org, err := svc.orgUseCase.FindOrCreate(ctx, spec.GetName()) + if err != nil { + return sl.LogAndMaskErr(err, svc.log) + } + + // Determine the role to be assigned based on the config + role := determineRole(spec.GetRole()) + + // Ensures the user is a member of the organization with the specified role + if err := ensureMembership(ctx, svc, org.ID, u.ID, role); err != nil { + return sl.LogAndMaskErr(err, svc.log) + } + } + return nil +} + +// determineRole maps the config role to the appropriate authz.Role +func determineRole(configRole string) authz.Role { + switch configRole { + case AutoOnboardingAdminRole: + return authz.RoleAdmin + case AutoOnboardingViewerRole: + return authz.RoleViewer + case AutoOnboardingOwnerRole: + return authz.RoleOwner + default: + return authz.RoleViewer + } +} + +// ensureMembership ensures the user is a member of the organization with the specified role +func ensureMembership(ctx context.Context, svc *AuthService, orgID, userID string, role authz.Role) error { + m, err := svc.membershipUseCase.FindByOrgAndUser(ctx, orgID, userID) + if err != nil && !errors.As(err, &biz.ErrNotFound{}) { + return err + } + + // If there is a membership, we don't need to do anything + // Don't compare the role, as the user might have a different role, and we cannot update it + // because the user might have been assigned a different role by an admin + if m != nil { + return nil + } + + // Create the membership with the proper role if it doesn't exist + _, err = svc.membershipUseCase.Create(ctx, orgID, userID, biz.WithCurrentMembership(), biz.WithMembershipRole(role)) + return err +} + func crafCallbackURL(callback, userToken string) (string, error) { callbackURL, err := url.Parse(callback) if err != nil { diff --git a/app/controlplane/internal/service/auth_test.go b/app/controlplane/internal/service/auth_test.go index 4345d1323..78a648a34 100644 --- a/app/controlplane/internal/service/auth_test.go +++ b/app/controlplane/internal/service/auth_test.go @@ -16,10 +16,15 @@ package service import ( + "context" "testing" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/authz" conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/testhelpers" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" ) func TestGetAuthURLs(t *testing.T) { @@ -74,3 +79,104 @@ func TestGetAuthURLs(t *testing.T) { }) } } + +func TestAuthOnboarding(t *testing.T) { + suite.Run(t, new(authOnboardingTestSuite)) +} + +type authOnboardingTestSuite struct { + testhelpers.UseCasesEachTestSuite + usr, usr1 *biz.User + org *biz.Organization + m *biz.Membership +} + +func (s *authOnboardingTestSuite) SetupTest() { + t := s.T() + assert := assert.New(t) + ctx := context.Background() + + s.TestingUseCases = testhelpers.NewTestingUseCases(t) + + s.setupUsersAndOrganization(ctx, assert) + s.setupMembership(ctx, assert) +} + +func (s *authOnboardingTestSuite) setupUsersAndOrganization(ctx context.Context, assert *assert.Assertions) { + var err error + s.usr, err = s.User.FindOrCreateByEmail(ctx, "foo@bar") + assert.NoError(err) + + s.org, err = s.Organization.Create(ctx, "onboarded-org") + assert.NoError(err) + + s.usr1, err = s.User.FindOrCreateByEmail(ctx, "bar@foo") + assert.NoError(err) +} + +func (s *authOnboardingTestSuite) setupMembership(ctx context.Context, assert *assert.Assertions) { + var err error + s.m, err = s.Membership.Create(ctx, s.org.ID, s.usr1.ID, biz.WithMembershipRole(authz.RoleViewer)) + assert.NoError(err) +} + +func (s *authOnboardingTestSuite) TestAutoOnboardOrganizations() { + ctx := context.Background() + t := s.T() + assert := assert.New(t) + + svc := s.newAuthService("testing-org", "viewer") + + org, err := s.Organization.FindByName(ctx, "testing-org") + assert.Error(err) + assert.Nil(org) + + err = autoOnboardOnOrganizations(ctx, svc, s.usr) + assert.NoError(err) + + org, err = s.Organization.FindByName(ctx, "testing-org") + assert.NoError(err) + assert.NotNil(org) + + m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr.ID) + assert.NoError(err) + assert.NotNil(m) +} + +func (s *authOnboardingTestSuite) TestAutoOnboardWithExistingMemberships() { + ctx := context.Background() + t := s.T() + assert := assert.New(t) + + svc := s.newAuthService(s.org.Name, string(s.m.Role)) + + org, err := s.Organization.FindByName(ctx, s.org.Name) + assert.NoError(err) + assert.NotNil(org) + + m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) + assert.NoError(err) + assert.NotNil(m) + assert.Equal(s.m.Role, m.Role) + + err = autoOnboardOnOrganizations(ctx, svc, s.usr1) + assert.NoError(err) + + newM, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) + assert.NoError(err) + assert.NotNil(newM) + assert.Equal(s.m.Role, newM.Role) +} + +func (s *authOnboardingTestSuite) newAuthService(orgName, role string) *AuthService { + return &AuthService{ + onboardingConfig: &conf.OnboardingSpec{ + AutoOnboardOrganizations: []*conf.AutoOnboardOrganization{ + {Name: orgName, Role: role}, + }, + }, + userUseCase: s.TestingUseCases.User, + orgUseCase: s.TestingUseCases.Organization, + membershipUseCase: s.TestingUseCases.Membership, + } +} diff --git a/app/controlplane/pkg/biz/mocks/OrganizationRepo.go b/app/controlplane/pkg/biz/mocks/OrganizationRepo.go index 1c7f314f2..47f537512 100644 --- a/app/controlplane/pkg/biz/mocks/OrganizationRepo.go +++ b/app/controlplane/pkg/biz/mocks/OrganizationRepo.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type OrganizationRepo struct { func (_m *OrganizationRepo) Create(ctx context.Context, name string) (*biz.Organization, error) { ret := _m.Called(ctx, name) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 *biz.Organization var r1 error if rf, ok := ret.Get(0).(func(context.Context, string) (*biz.Organization, error)); ok { @@ -47,6 +51,10 @@ func (_m *OrganizationRepo) Create(ctx context.Context, name string) (*biz.Organ func (_m *OrganizationRepo) Delete(ctx context.Context, ID uuid.UUID) error { ret := _m.Called(ctx, ID) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) error); ok { r0 = rf(ctx, ID) @@ -61,6 +69,10 @@ func (_m *OrganizationRepo) Delete(ctx context.Context, ID uuid.UUID) error { func (_m *OrganizationRepo) FindByID(ctx context.Context, orgID uuid.UUID) (*biz.Organization, error) { ret := _m.Called(ctx, orgID) + if len(ret) == 0 { + panic("no return value specified for FindByID") + } + var r0 *biz.Organization var r1 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) (*biz.Organization, error)); ok { @@ -83,10 +95,44 @@ func (_m *OrganizationRepo) FindByID(ctx context.Context, orgID uuid.UUID) (*biz return r0, r1 } +// FindByName provides a mock function with given fields: ctx, name +func (_m *OrganizationRepo) FindByName(ctx context.Context, name string) (*biz.Organization, error) { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for FindByName") + } + + var r0 *biz.Organization + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*biz.Organization, error)); ok { + return rf(ctx, name) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *biz.Organization); ok { + r0 = rf(ctx, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*biz.Organization) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Update provides a mock function with given fields: ctx, id, name func (_m *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, name *string) (*biz.Organization, error) { ret := _m.Called(ctx, id, name) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 *biz.Organization var r1 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *string) (*biz.Organization, error)); ok { @@ -109,13 +155,12 @@ func (_m *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, name *stri return r0, r1 } -type mockConstructorTestingTNewOrganizationRepo interface { +// NewOrganizationRepo creates a new instance of OrganizationRepo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewOrganizationRepo(t interface { mock.TestingT Cleanup(func()) -} - -// NewOrganizationRepo creates a new instance of OrganizationRepo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewOrganizationRepo(t mockConstructorTestingTNewOrganizationRepo) *OrganizationRepo { +}) *OrganizationRepo { mock := &OrganizationRepo{} mock.Mock.Test(t) diff --git a/app/controlplane/pkg/biz/organization.go b/app/controlplane/pkg/biz/organization.go index 9f27b635e..957f6e7db 100644 --- a/app/controlplane/pkg/biz/organization.go +++ b/app/controlplane/pkg/biz/organization.go @@ -33,6 +33,7 @@ type Organization struct { type OrganizationRepo interface { FindByID(ctx context.Context, orgID uuid.UUID) (*Organization, error) + FindByName(ctx context.Context, name string) (*Organization, error) Create(ctx context.Context, name string) (*Organization, error) Update(ctx context.Context, id uuid.UUID, name *string) (*Organization, error) Delete(ctx context.Context, ID uuid.UUID) error @@ -197,6 +198,32 @@ func (uc *OrganizationUseCase) FindByID(ctx context.Context, id string) (*Organi return org, nil } +// FindByName finds an organization by name. +func (uc *OrganizationUseCase) FindByName(ctx context.Context, name string) (*Organization, error) { + if err := ValidateIsDNS1123(name); err != nil { + return nil, NewErrValidation(errOrgName) + } + + org, err := uc.orgRepo.FindByName(ctx, name) + if err != nil { + return nil, fmt.Errorf("failed to find organization: %w", err) + } else if org == nil { + return nil, NewErrNotFound("organization") + } + + return org, nil +} + +// FindOrCreate finds an organization by name, or creates it if it doesn't exist. +func (uc *OrganizationUseCase) FindOrCreate(ctx context.Context, name string) (*Organization, error) { + org, err := uc.FindByName(ctx, name) + if err != nil && errors.As(err, &ErrNotFound{}) { + org, err = uc.Create(ctx, name, WithCreateInlineBackend()) + } + + return org, err +} + // Delete deletes an organization and all relevant data // This includes: // - The organization diff --git a/app/controlplane/pkg/data/organization.go b/app/controlplane/pkg/data/organization.go index f090318c3..b6a236e5c 100644 --- a/app/controlplane/pkg/data/organization.go +++ b/app/controlplane/pkg/data/organization.go @@ -21,6 +21,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" ) @@ -63,6 +64,18 @@ func (r *OrganizationRepo) FindByID(ctx context.Context, id uuid.UUID) (*biz.Org return entOrgToBizOrg(org), nil } +// FindByName finds an organization by name. +func (r *OrganizationRepo) FindByName(ctx context.Context, name string) (*biz.Organization, error) { + org, err := r.data.DB.Organization.Query().Where(organization.NameEQ(name)).Only(ctx) + if err != nil && !ent.IsNotFound(err) { + return nil, err + } else if org == nil { + return nil, nil + } + + return entOrgToBizOrg(org), nil +} + func (r *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, name *string) (*biz.Organization, error) { req := r.data.DB.Organization.UpdateOneID(id) if name != nil && *name != "" { From c42e65563848721c6617c30fecfb60413d7fa242 Mon Sep 17 00:00:00 2001 From: Javier Rodriguez Date: Fri, 14 Jun 2024 10:27:04 +0200 Subject: [PATCH 2/4] Flatten onboarding configuration Signed-off-by: Javier Rodriguez --- app/controlplane/cmd/wire_gen.go | 4 +- app/controlplane/configs/config.devel.yaml | 7 +- .../conf/controlplane/config/v1/conf.pb.go | 228 ++++++------------ .../conf/controlplane/config/v1/conf.proto | 10 +- app/controlplane/internal/service/auth.go | 6 +- .../internal/service/auth_test.go | 6 +- .../api/credentials/v1/config.pb.go | 10 +- 7 files changed, 96 insertions(+), 175 deletions(-) diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index c1aeb76fb..cca83c3c7 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -97,9 +97,9 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l cleanup() return nil, nil, err } - onboardingSpec := bootstrap.Onboarding + v3 := bootstrap.Onboarding confServer := bootstrap.Server - authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, onboardingSpec, confServer, v2...) + authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, v3, confServer, v2...) if err != nil { cleanup() return nil, nil, err diff --git a/app/controlplane/configs/config.devel.yaml b/app/controlplane/configs/config.devel.yaml index 32db799a2..df8ab7502 100644 --- a/app/controlplane/configs/config.devel.yaml +++ b/app/controlplane/configs/config.devel.yaml @@ -60,6 +60,7 @@ auth: # - deadbeef onboarding: - auto_onboard_organizations: - - name: "read-only-demo" - role: "viewer" + - name: "read-only-demo" + role: "viewer" + - name: "read-write-demo" + role: "owner" diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go index efe8a08f9..d5c38267f 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go @@ -58,7 +58,7 @@ type Bootstrap struct { // The certificate authority used for keyless signing CertificateAuthority *CA `protobuf:"bytes,9,opt,name=certificate_authority,json=certificateAuthority,proto3" json:"certificate_authority,omitempty"` // Configuration for onboarding users in organizations with specific roles - Onboarding *OnboardingSpec `protobuf:"bytes,10,opt,name=onboarding,proto3" json:"onboarding,omitempty"` + Onboarding []*OnboardingSpec `protobuf:"bytes,10,rep,name=onboarding,proto3" json:"onboarding,omitempty"` } func (x *Bootstrap) Reset() { @@ -156,7 +156,7 @@ func (x *Bootstrap) GetCertificateAuthority() *CA { return nil } -func (x *Bootstrap) GetOnboarding() *OnboardingSpec { +func (x *Bootstrap) GetOnboarding() []*OnboardingSpec { if x != nil { return x.Onboarding } @@ -482,8 +482,10 @@ type OnboardingSpec struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // auto_onboard_organizations is a list of organizations to automatically onboard users with specific roles - AutoOnboardOrganizations []*AutoOnboardOrganization `protobuf:"bytes,1,rep,name=auto_onboard_organizations,json=autoOnboardOrganizations,proto3" json:"auto_onboard_organizations,omitempty"` + // name is the name of the organization + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // role is the role to assign to the user. For the moment, only "viewer" is supported + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` } func (x *OnboardingSpec) Reset() { @@ -518,65 +520,14 @@ func (*OnboardingSpec) Descriptor() ([]byte, []int) { return file_controlplane_config_v1_conf_proto_rawDescGZIP(), []int{6} } -func (x *OnboardingSpec) GetAutoOnboardOrganizations() []*AutoOnboardOrganization { - if x != nil { - return x.AutoOnboardOrganizations - } - return nil -} - -// AutoOnboardOrganization is a configuration to automatically onboard an organization with a specific role -type AutoOnboardOrganization struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // name is the name of the organization - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // role is the role to assign to the user. For the moment, only "viewer" is supported - Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` -} - -func (x *AutoOnboardOrganization) Reset() { - *x = AutoOnboardOrganization{} - if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AutoOnboardOrganization) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AutoOnboardOrganization) ProtoMessage() {} - -func (x *AutoOnboardOrganization) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] - 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 AutoOnboardOrganization.ProtoReflect.Descriptor instead. -func (*AutoOnboardOrganization) Descriptor() ([]byte, []int) { - return file_controlplane_config_v1_conf_proto_rawDescGZIP(), []int{7} -} - -func (x *AutoOnboardOrganization) GetName() string { +func (x *OnboardingSpec) GetName() string { if x != nil { return x.Name } return "" } -func (x *AutoOnboardOrganization) GetRole() string { +func (x *OnboardingSpec) GetRole() string { if x != nil { return x.Role } @@ -594,7 +545,7 @@ type Bootstrap_Observability struct { func (x *Bootstrap_Observability) Reset() { *x = Bootstrap_Observability{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -607,7 +558,7 @@ func (x *Bootstrap_Observability) String() string { func (*Bootstrap_Observability) ProtoMessage() {} func (x *Bootstrap_Observability) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -648,7 +599,7 @@ type Bootstrap_CASServer struct { func (x *Bootstrap_CASServer) Reset() { *x = Bootstrap_CASServer{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -661,7 +612,7 @@ func (x *Bootstrap_CASServer) String() string { func (*Bootstrap_CASServer) ProtoMessage() {} func (x *Bootstrap_CASServer) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -710,7 +661,7 @@ type Bootstrap_Observability_Sentry struct { func (x *Bootstrap_Observability_Sentry) Reset() { *x = Bootstrap_Observability_Sentry{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -723,7 +674,7 @@ func (x *Bootstrap_Observability_Sentry) String() string { func (*Bootstrap_Observability_Sentry) ProtoMessage() {} func (x *Bootstrap_Observability_Sentry) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -769,7 +720,7 @@ type Server_HTTP struct { func (x *Server_HTTP) Reset() { *x = Server_HTTP{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -782,7 +733,7 @@ func (x *Server_HTTP) String() string { func (*Server_HTTP) ProtoMessage() {} func (x *Server_HTTP) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -839,7 +790,7 @@ type Server_TLS struct { func (x *Server_TLS) Reset() { *x = Server_TLS{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -852,7 +803,7 @@ func (x *Server_TLS) String() string { func (*Server_TLS) ProtoMessage() {} func (x *Server_TLS) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -896,7 +847,7 @@ type Server_GRPC struct { func (x *Server_GRPC) Reset() { *x = Server_GRPC{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -909,7 +860,7 @@ func (x *Server_GRPC) String() string { func (*Server_GRPC) ProtoMessage() {} func (x *Server_GRPC) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -965,7 +916,7 @@ type Data_Database struct { func (x *Data_Database) Reset() { *x = Data_Database{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -978,7 +929,7 @@ func (x *Data_Database) String() string { func (*Data_Database) ProtoMessage() {} func (x *Data_Database) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1022,7 +973,7 @@ type Auth_OIDC struct { func (x *Auth_OIDC) Reset() { *x = Auth_OIDC{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[15] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1035,7 +986,7 @@ func (x *Auth_OIDC) String() string { func (*Auth_OIDC) ProtoMessage() {} func (x *Auth_OIDC) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[15] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1092,7 +1043,7 @@ type CA_FileCA struct { func (x *CA_FileCA) Reset() { *x = CA_FileCA{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[16] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1105,7 +1056,7 @@ func (x *CA_FileCA) String() string { func (*CA_FileCA) ProtoMessage() {} func (x *CA_FileCA) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_config_v1_conf_proto_msgTypes[16] + mi := &file_controlplane_config_v1_conf_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1194,7 +1145,7 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x52, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x46, 0x0a, 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x67, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x1a, 0x9d, 0x01, 0x0a, 0x0d, @@ -1301,26 +1252,17 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, - 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, 0x0a, 0x02, 0x63, 0x61, 0x22, 0x7f, 0x0a, 0x0e, 0x4f, - 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x6d, 0x0a, - 0x1a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x6f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x4f, - 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x18, 0x61, 0x75, 0x74, 0x6f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x41, 0x0a, 0x17, - 0x41, 0x75, 0x74, 0x6f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, - 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, - 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, - 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, 0x0a, 0x02, 0x63, 0x61, 0x22, 0x38, 0x0a, 0x0e, 0x4f, + 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, + 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1335,7 +1277,7 @@ func file_controlplane_config_v1_conf_proto_rawDescGZIP() []byte { return file_controlplane_config_v1_conf_proto_rawDescData } -var file_controlplane_config_v1_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_controlplane_config_v1_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_controlplane_config_v1_conf_proto_goTypes = []interface{}{ (*Bootstrap)(nil), // 0: controlplane.config.v1.Bootstrap (*ReferrerSharedIndex)(nil), // 1: controlplane.config.v1.ReferrerSharedIndex @@ -1344,46 +1286,44 @@ var file_controlplane_config_v1_conf_proto_goTypes = []interface{}{ (*Auth)(nil), // 4: controlplane.config.v1.Auth (*CA)(nil), // 5: controlplane.config.v1.CA (*OnboardingSpec)(nil), // 6: controlplane.config.v1.OnboardingSpec - (*AutoOnboardOrganization)(nil), // 7: controlplane.config.v1.AutoOnboardOrganization - (*Bootstrap_Observability)(nil), // 8: controlplane.config.v1.Bootstrap.Observability - (*Bootstrap_CASServer)(nil), // 9: controlplane.config.v1.Bootstrap.CASServer - (*Bootstrap_Observability_Sentry)(nil), // 10: controlplane.config.v1.Bootstrap.Observability.Sentry - (*Server_HTTP)(nil), // 11: controlplane.config.v1.Server.HTTP - (*Server_TLS)(nil), // 12: controlplane.config.v1.Server.TLS - (*Server_GRPC)(nil), // 13: controlplane.config.v1.Server.GRPC - (*Data_Database)(nil), // 14: controlplane.config.v1.Data.Database - (*Auth_OIDC)(nil), // 15: controlplane.config.v1.Auth.OIDC - (*CA_FileCA)(nil), // 16: controlplane.config.v1.CA.FileCA - (*v1.Credentials)(nil), // 17: credentials.v1.Credentials - (*durationpb.Duration)(nil), // 18: google.protobuf.Duration + (*Bootstrap_Observability)(nil), // 7: controlplane.config.v1.Bootstrap.Observability + (*Bootstrap_CASServer)(nil), // 8: controlplane.config.v1.Bootstrap.CASServer + (*Bootstrap_Observability_Sentry)(nil), // 9: controlplane.config.v1.Bootstrap.Observability.Sentry + (*Server_HTTP)(nil), // 10: controlplane.config.v1.Server.HTTP + (*Server_TLS)(nil), // 11: controlplane.config.v1.Server.TLS + (*Server_GRPC)(nil), // 12: controlplane.config.v1.Server.GRPC + (*Data_Database)(nil), // 13: controlplane.config.v1.Data.Database + (*Auth_OIDC)(nil), // 14: controlplane.config.v1.Auth.OIDC + (*CA_FileCA)(nil), // 15: controlplane.config.v1.CA.FileCA + (*v1.Credentials)(nil), // 16: credentials.v1.Credentials + (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } var file_controlplane_config_v1_conf_proto_depIdxs = []int32{ 2, // 0: controlplane.config.v1.Bootstrap.server:type_name -> controlplane.config.v1.Server 3, // 1: controlplane.config.v1.Bootstrap.data:type_name -> controlplane.config.v1.Data 4, // 2: controlplane.config.v1.Bootstrap.auth:type_name -> controlplane.config.v1.Auth - 8, // 3: controlplane.config.v1.Bootstrap.observability:type_name -> controlplane.config.v1.Bootstrap.Observability - 17, // 4: controlplane.config.v1.Bootstrap.credentials_service:type_name -> credentials.v1.Credentials - 9, // 5: controlplane.config.v1.Bootstrap.cas_server:type_name -> controlplane.config.v1.Bootstrap.CASServer + 7, // 3: controlplane.config.v1.Bootstrap.observability:type_name -> controlplane.config.v1.Bootstrap.Observability + 16, // 4: controlplane.config.v1.Bootstrap.credentials_service:type_name -> credentials.v1.Credentials + 8, // 5: controlplane.config.v1.Bootstrap.cas_server:type_name -> controlplane.config.v1.Bootstrap.CASServer 1, // 6: controlplane.config.v1.Bootstrap.referrer_shared_index:type_name -> controlplane.config.v1.ReferrerSharedIndex 5, // 7: controlplane.config.v1.Bootstrap.certificate_authority:type_name -> controlplane.config.v1.CA 6, // 8: controlplane.config.v1.Bootstrap.onboarding:type_name -> controlplane.config.v1.OnboardingSpec - 11, // 9: controlplane.config.v1.Server.http:type_name -> controlplane.config.v1.Server.HTTP - 13, // 10: controlplane.config.v1.Server.grpc:type_name -> controlplane.config.v1.Server.GRPC - 11, // 11: controlplane.config.v1.Server.http_metrics:type_name -> controlplane.config.v1.Server.HTTP - 14, // 12: controlplane.config.v1.Data.database:type_name -> controlplane.config.v1.Data.Database - 15, // 13: controlplane.config.v1.Auth.oidc:type_name -> controlplane.config.v1.Auth.OIDC - 16, // 14: controlplane.config.v1.CA.file_ca:type_name -> controlplane.config.v1.CA.FileCA - 7, // 15: controlplane.config.v1.OnboardingSpec.auto_onboard_organizations:type_name -> controlplane.config.v1.AutoOnboardOrganization - 10, // 16: controlplane.config.v1.Bootstrap.Observability.sentry:type_name -> controlplane.config.v1.Bootstrap.Observability.Sentry - 13, // 17: controlplane.config.v1.Bootstrap.CASServer.grpc:type_name -> controlplane.config.v1.Server.GRPC - 18, // 18: controlplane.config.v1.Server.HTTP.timeout:type_name -> google.protobuf.Duration - 18, // 19: controlplane.config.v1.Server.GRPC.timeout:type_name -> google.protobuf.Duration - 12, // 20: controlplane.config.v1.Server.GRPC.tls_config:type_name -> controlplane.config.v1.Server.TLS - 21, // [21:21] is the sub-list for method output_type - 21, // [21:21] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 10, // 9: controlplane.config.v1.Server.http:type_name -> controlplane.config.v1.Server.HTTP + 12, // 10: controlplane.config.v1.Server.grpc:type_name -> controlplane.config.v1.Server.GRPC + 10, // 11: controlplane.config.v1.Server.http_metrics:type_name -> controlplane.config.v1.Server.HTTP + 13, // 12: controlplane.config.v1.Data.database:type_name -> controlplane.config.v1.Data.Database + 14, // 13: controlplane.config.v1.Auth.oidc:type_name -> controlplane.config.v1.Auth.OIDC + 15, // 14: controlplane.config.v1.CA.file_ca:type_name -> controlplane.config.v1.CA.FileCA + 9, // 15: controlplane.config.v1.Bootstrap.Observability.sentry:type_name -> controlplane.config.v1.Bootstrap.Observability.Sentry + 12, // 16: controlplane.config.v1.Bootstrap.CASServer.grpc:type_name -> controlplane.config.v1.Server.GRPC + 17, // 17: controlplane.config.v1.Server.HTTP.timeout:type_name -> google.protobuf.Duration + 17, // 18: controlplane.config.v1.Server.GRPC.timeout:type_name -> google.protobuf.Duration + 11, // 19: controlplane.config.v1.Server.GRPC.tls_config:type_name -> controlplane.config.v1.Server.TLS + 20, // [20:20] is the sub-list for method output_type + 20, // [20:20] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_controlplane_config_v1_conf_proto_init() } @@ -1477,18 +1417,6 @@ func file_controlplane_config_v1_conf_proto_init() { } } file_controlplane_config_v1_conf_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AutoOnboardOrganization); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_controlplane_config_v1_conf_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Bootstrap_Observability); i { case 0: return &v.state @@ -1500,7 +1428,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Bootstrap_CASServer); i { case 0: return &v.state @@ -1512,7 +1440,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Bootstrap_Observability_Sentry); i { case 0: return &v.state @@ -1524,7 +1452,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Server_HTTP); i { case 0: return &v.state @@ -1536,7 +1464,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Server_TLS); i { case 0: return &v.state @@ -1548,7 +1476,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Server_GRPC); i { case 0: return &v.state @@ -1560,7 +1488,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Data_Database); i { case 0: return &v.state @@ -1572,7 +1500,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Auth_OIDC); i { case 0: return &v.state @@ -1584,7 +1512,7 @@ func file_controlplane_config_v1_conf_proto_init() { return nil } } - file_controlplane_config_v1_conf_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_config_v1_conf_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CA_FileCA); i { case 0: return &v.state @@ -1606,7 +1534,7 @@ func file_controlplane_config_v1_conf_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controlplane_config_v1_conf_proto_rawDesc, NumEnums: 0, - NumMessages: 17, + NumMessages: 16, NumExtensions: 0, NumServices: 0, }, diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto index 8ba774462..4ad37f2d0 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto @@ -60,7 +60,7 @@ message Bootstrap { } // Configuration for onboarding users in organizations with specific roles - OnboardingSpec onboarding = 10; + repeated OnboardingSpec onboarding = 10; } // Configuration used to enable a shared index API endpoint that can be used to discover metadata referrers @@ -141,14 +141,8 @@ message CA { // OnboardingSpec is a configuration to automatically onboard users in organizations with specific roles message OnboardingSpec { - // auto_onboard_organizations is a list of organizations to automatically onboard users with specific roles - repeated AutoOnboardOrganization auto_onboard_organizations = 1; -} - -// AutoOnboardOrganization is a configuration to automatically onboard an organization with a specific role -message AutoOnboardOrganization { // name is the name of the organization string name = 1; // role is the role to assign to the user. For the moment, only "viewer" is supported string role = 2; -} \ No newline at end of file +} diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index d69e86a11..3a7c9341e 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -77,10 +77,10 @@ type AuthService struct { membershipUseCase *biz.MembershipUseCase orgInvitesUseCase *biz.OrgInvitationUseCase AuthURLs *AuthURLs - onboardingConfig *conf.OnboardingSpec + onboardingConfig []*conf.OnboardingSpec } -func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, onboardingConfig *conf.OnboardingSpec, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { +func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, onboardingConfig []*conf.OnboardingSpec, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { oidcConfig := authConfig.GetOidc() if oidcConfig == nil { return nil, errors.New("oauth configuration missing") @@ -305,7 +305,7 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) ( // If the organization does not exist, it will be created with an inline CAS backend // If the user is not already a member of the organization, a membership will be created with the role specified in the config func autoOnboardOnOrganizations(ctx context.Context, svc *AuthService, u *biz.User) error { - for _, spec := range svc.onboardingConfig.GetAutoOnboardOrganizations() { + for _, spec := range svc.onboardingConfig { // Ensure the organization exists or create it if it doesn't org, err := svc.orgUseCase.FindOrCreate(ctx, spec.GetName()) if err != nil { diff --git a/app/controlplane/internal/service/auth_test.go b/app/controlplane/internal/service/auth_test.go index 78a648a34..307d80293 100644 --- a/app/controlplane/internal/service/auth_test.go +++ b/app/controlplane/internal/service/auth_test.go @@ -170,10 +170,8 @@ func (s *authOnboardingTestSuite) TestAutoOnboardWithExistingMemberships() { func (s *authOnboardingTestSuite) newAuthService(orgName, role string) *AuthService { return &AuthService{ - onboardingConfig: &conf.OnboardingSpec{ - AutoOnboardOrganizations: []*conf.AutoOnboardOrganization{ - {Name: orgName, Role: role}, - }, + onboardingConfig: []*conf.OnboardingSpec{ + {Name: orgName, Role: role}, }, userUseCase: s.TestingUseCases.User, orgUseCase: s.TestingUseCases.Organization, diff --git a/pkg/credentials/api/credentials/v1/config.pb.go b/pkg/credentials/api/credentials/v1/config.pb.go index c12d5995c..8d5589ec1 100644 --- a/pkg/credentials/api/credentials/v1/config.pb.go +++ b/pkg/credentials/api/credentials/v1/config.pb.go @@ -536,12 +536,12 @@ var file_credentials_v1_config_proto_rawDesc = []byte{ 0x0a, 0x09, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x55, 0x72, 0x69, 0x42, 0x10, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, - 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x42, 0x4f, 0x5a, 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x12, 0x05, 0xba, 0x48, 0x02, 0x08, 0x01, 0x42, 0x4a, 0x5a, 0x48, 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, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x70, 0x6b, + 0x67, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x76, 0x31, + 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( From 2c0bfe152ce253f37625e63923733da0dc0f1124 Mon Sep 17 00:00:00 2001 From: Javier Rodriguez Date: Sun, 16 Jun 2024 09:40:32 +0200 Subject: [PATCH 3/4] Tackle feedback Signed-off-by: Javier Rodriguez --- app/controlplane/cmd/wire_gen.go | 49 +-- app/controlplane/configs/config.devel.yaml | 5 - app/controlplane/configs/samples/config.yaml | 8 +- app/controlplane/internal/conf/buf.lock | 8 +- app/controlplane/internal/conf/buf.yaml | 1 + .../conf/controlplane/config/v1/conf.pb.go | 344 +++++++++--------- .../conf/controlplane/config/v1/conf.proto | 7 +- app/controlplane/internal/service/auth.go | 69 +--- .../internal/service/auth_test.go | 104 ------ .../internal/service/organization.go | 2 +- .../internal/service/orginvitation.go | 2 +- app/controlplane/internal/service/user.go | 13 - .../usercontext/apitoken_middleware_test.go | 2 +- app/controlplane/pkg/biz/organization.go | 87 ++++- .../pkg/biz/organization_integration_test.go | 89 +++++ app/controlplane/pkg/biz/organization_test.go | 2 +- .../pkg/biz/testhelpers/database.go | 15 +- app/controlplane/pkg/biz/testhelpers/wire.go | 2 +- .../pkg/biz/testhelpers/wire_gen.go | 5 +- app/controlplane/pkg/biz/user.go | 39 +- 20 files changed, 442 insertions(+), 411 deletions(-) diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index cca83c3c7..e7f17e699 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -48,12 +48,14 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l Logger: logger, } integrationUseCase := biz.NewIntegrationUseCase(newIntegrationUseCaseOpts) - organizationUseCase := biz.NewOrganizationUseCase(organizationRepo, casBackendUseCase, integrationUseCase, membershipRepo, logger) + v := bootstrap.Onboarding + organizationUseCase := biz.NewOrganizationUseCase(organizationRepo, casBackendUseCase, integrationUseCase, membershipRepo, v, logger) membershipUseCase := biz.NewMembershipUseCase(membershipRepo, organizationUseCase, logger) newUserUseCaseParams := &biz.NewUserUseCaseParams{ UserRepo: userRepo, MembershipUseCase: membershipUseCase, OrganizationUseCase: organizationUseCase, + OnboardingConfig: v, Logger: logger, } userUseCase := biz.NewUserUseCase(newUserUseCaseParams) @@ -66,8 +68,8 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l return nil, nil, err } bootstrap_CASServer := bootstrap.CasServer - v := _wireValue - casClientUseCase := biz.NewCASClientUseCase(casCredentialsUseCase, bootstrap_CASServer, logger, v...) + v2 := _wireValue + casClientUseCase := biz.NewCASClientUseCase(casCredentialsUseCase, bootstrap_CASServer, logger, v2...) referrerRepo := data.NewReferrerRepo(dataData, workflowRepo, logger) referrerSharedIndex := bootstrap.ReferrerSharedIndex referrerUseCase, err := biz.NewReferrerUseCase(referrerRepo, workflowRepo, membershipRepo, referrerSharedIndex, logger) @@ -89,22 +91,21 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l workflowContractRepo := data.NewWorkflowContractRepo(dataData, logger) workflowContractUseCase := biz.NewWorkflowContractUseCase(workflowContractRepo, logger) workflowUseCase := biz.NewWorkflowUsecase(workflowRepo, workflowContractUseCase, logger) - v2 := serviceOpts(logger) - workflowService := service.NewWorkflowService(workflowUseCase, v2...) + v3 := serviceOpts(logger) + workflowService := service.NewWorkflowService(workflowUseCase, v3...) orgInvitationRepo := data.NewOrgInvitation(dataData, logger) orgInvitationUseCase, err := biz.NewOrgInvitationUseCase(orgInvitationRepo, membershipRepo, userRepo, logger) if err != nil { cleanup() return nil, nil, err } - v3 := bootstrap.Onboarding confServer := bootstrap.Server - authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, v3, confServer, v2...) + authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, confServer, v3...) if err != nil { cleanup() return nil, nil, err } - robotAccountService := service.NewRobotAccountService(robotAccountUseCase, v2...) + robotAccountService := service.NewRobotAccountService(robotAccountUseCase, v3...) workflowRunRepo := data.NewWorkflowRunRepo(dataData, logger) workflowRunUseCase, err := biz.NewWorkflowRunUseCase(workflowRunRepo, workflowRepo, logger) if err != nil { @@ -116,7 +117,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l WorkflowUC: workflowUseCase, WorkflowContractUC: workflowContractUseCase, CredsReader: readerWriter, - Opts: v2, + Opts: v3, } workflowRunService := service.NewWorkflowRunService(newWorkflowRunServiceOpts) attestationUseCase := biz.NewAttestationUseCase(casClientUseCase, logger) @@ -136,30 +137,30 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l CASMappingUseCase: casMappingUseCase, ReferrerUC: referrerUseCase, OrgUC: organizationUseCase, - Opts: v2, + Opts: v3, } attestationService := service.NewAttestationService(newAttestationServiceOpts) - workflowContractService := service.NewWorkflowSchemaService(workflowContractUseCase, v2...) - contextService := service.NewContextService(casBackendUseCase, userUseCase, v2...) - casCredentialsService := service.NewCASCredentialsService(casCredentialsUseCase, casMappingUseCase, casBackendUseCase, enforcer, v2...) + workflowContractService := service.NewWorkflowSchemaService(workflowContractUseCase, v3...) + contextService := service.NewContextService(casBackendUseCase, userUseCase, v3...) + casCredentialsService := service.NewCASCredentialsService(casCredentialsUseCase, casMappingUseCase, casBackendUseCase, enforcer, v3...) orgMetricsRepo := data.NewOrgMetricsRepo(dataData, logger) orgMetricsUseCase, err := biz.NewOrgMetricsUseCase(orgMetricsRepo, logger) if err != nil { cleanup() return nil, nil, err } - orgMetricsService := service.NewOrgMetricsService(orgMetricsUseCase, v2...) - integrationsService := service.NewIntegrationsService(integrationUseCase, workflowUseCase, availablePlugins, v2...) - organizationService := service.NewOrganizationService(membershipUseCase, organizationUseCase, v2...) - casBackendService := service.NewCASBackendService(casBackendUseCase, providers, v2...) - casRedirectService, err := service.NewCASRedirectService(casMappingUseCase, casCredentialsUseCase, bootstrap_CASServer, v2...) + orgMetricsService := service.NewOrgMetricsService(orgMetricsUseCase, v3...) + integrationsService := service.NewIntegrationsService(integrationUseCase, workflowUseCase, availablePlugins, v3...) + organizationService := service.NewOrganizationService(membershipUseCase, organizationUseCase, v3...) + casBackendService := service.NewCASBackendService(casBackendUseCase, providers, v3...) + casRedirectService, err := service.NewCASRedirectService(casMappingUseCase, casCredentialsUseCase, bootstrap_CASServer, v3...) if err != nil { cleanup() return nil, nil, err } - orgInvitationService := service.NewOrgInvitationService(orgInvitationUseCase, v2...) - referrerService := service.NewReferrerService(referrerUseCase, v2...) - apiTokenService := service.NewAPITokenService(apiTokenUseCase, v2...) + orgInvitationService := service.NewOrgInvitationService(orgInvitationUseCase, v3...) + referrerService := service.NewReferrerService(referrerUseCase, v3...) + apiTokenService := service.NewAPITokenService(apiTokenUseCase, v3...) attestationStateRepo := data.NewAttestationStateRepo(dataData, logger) attestationStateUseCase, err := biz.NewAttestationStateUseCase(attestationStateRepo, workflowRunRepo) if err != nil { @@ -170,12 +171,12 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l AttestationStateUseCase: attestationStateUseCase, WorkflowUseCase: workflowUseCase, WorkflowRunUseCase: workflowRunUseCase, - Opts: v2, + Opts: v3, } attestationStateService := service.NewAttestationStateService(newAttestationStateServiceOpt) - userService := service.NewUserService(membershipUseCase, organizationUseCase, v2...) + userService := service.NewUserService(membershipUseCase, organizationUseCase, v3...) signingUseCase := biz.NewChainloopSigningUseCase(certificateAuthority) - signingService := service.NewSigningService(signingUseCase, v2...) + signingService := service.NewSigningService(signingUseCase, v3...) validator, err := newProtoValidator() if err != nil { cleanup() diff --git a/app/controlplane/configs/config.devel.yaml b/app/controlplane/configs/config.devel.yaml index df8ab7502..9bcfedba0 100644 --- a/app/controlplane/configs/config.devel.yaml +++ b/app/controlplane/configs/config.devel.yaml @@ -59,8 +59,3 @@ auth: # allowed_orgs: # - deadbeef -onboarding: - - name: "read-only-demo" - role: "viewer" - - name: "read-write-demo" - role: "owner" diff --git a/app/controlplane/configs/samples/config.yaml b/app/controlplane/configs/samples/config.yaml index 7bcccfda4..d4121d2b1 100644 --- a/app/controlplane/configs/samples/config.yaml +++ b/app/controlplane/configs/samples/config.yaml @@ -56,4 +56,10 @@ credentials_service: referrer_shared_index: enabled: true allowed_orgs: - - deadbeef \ No newline at end of file + - deadbeef + +onboarding: + - name: "read-only-demo" + role: "viewer" + - name: "read-write-demo" + role: "owner" \ No newline at end of file diff --git a/app/controlplane/internal/conf/buf.lock b/app/controlplane/internal/conf/buf.lock index f1d8f9aa8..a55648428 100644 --- a/app/controlplane/internal/conf/buf.lock +++ b/app/controlplane/internal/conf/buf.lock @@ -4,8 +4,12 @@ deps: - remote: buf.build owner: bufbuild repository: protovalidate - commit: b983156c5e994cc9892e0ce3e64e17e0 + commit: 46a4cf4ba1094a34bcd89a6c67163b4b - remote: buf.build owner: googleapis repository: googleapis - commit: 7a6bc1e3207144b38e9066861e1de0ff + commit: f0e53af8f2fc4556b94f482688b57223 + - remote: buf.build + owner: kratos-go + repository: kratos + commit: e1d52e944e3845c6862a566db322432d diff --git a/app/controlplane/internal/conf/buf.yaml b/app/controlplane/internal/conf/buf.yaml index 097510831..c98a57a3d 100644 --- a/app/controlplane/internal/conf/buf.yaml +++ b/app/controlplane/internal/conf/buf.yaml @@ -5,6 +5,7 @@ breaking: deps: - buf.build/googleapis/googleapis - buf.build/bufbuild/protovalidate + - buf.build/kratos-go/kratos lint: use: - DEFAULT diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go index d5c38267f..e24fcb828 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go @@ -23,6 +23,7 @@ package conf import ( _ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" + v11 "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" v1 "github.com/chainloop-dev/chainloop/pkg/credentials/api/credentials/v1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" @@ -482,10 +483,10 @@ type OnboardingSpec struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // name is the name of the organization + // Name of the organization Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // role is the role to assign to the user. For the moment, only "viewer" is supported - Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` + // Role to assign to the user + Role v11.MembershipRole `protobuf:"varint,2,opt,name=role,proto3,enum=controlplane.v1.MembershipRole" json:"role,omitempty"` } func (x *OnboardingSpec) Reset() { @@ -527,11 +528,11 @@ func (x *OnboardingSpec) GetName() string { return "" } -func (x *OnboardingSpec) GetRole() string { +func (x *OnboardingSpec) GetRole() v11.MembershipRole { if x != nil { return x.Role } - return "" + return v11.MembershipRole(0) } type Bootstrap_Observability struct { @@ -1105,164 +1106,169 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x07, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, - 0x72, 0x61, 0x70, 0x12, 0x36, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 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, 0xe1, + 0x07, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x12, 0x36, 0x0a, 0x06, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x06, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, + 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, + 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x12, 0x55, 0x0a, 0x0d, 0x6f, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, + 0x61, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x52, 0x0d, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, + 0x4c, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x5f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, + 0x0a, 0x63, 0x61, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x73, + 0x74, 0x72, 0x61, 0x70, 0x2e, 0x43, 0x41, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x09, + 0x63, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x73, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x44, 0x69, 0x72, 0x12, 0x5f, 0x0a, 0x15, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, - 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x12, - 0x55, 0x0a, 0x0d, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, + 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4f, 0x0a, 0x15, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x52, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x46, 0x0a, 0x0a, + 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x1a, 0x9d, 0x01, 0x0a, 0x0d, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x4e, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, - 0x52, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x0a, 0x63, 0x61, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, - 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x43, 0x41, 0x53, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x09, 0x63, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x5f, 0x64, 0x69, 0x72, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x44, 0x69, - 0x72, 0x12, 0x5f, 0x0a, 0x15, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x5f, 0x73, 0x68, - 0x61, 0x72, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, - 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x13, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x4f, 0x0a, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x52, 0x14, 0x63, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x12, 0x46, 0x0a, 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, - 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, - 0x0a, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x1a, 0x9d, 0x01, 0x0a, 0x0d, - 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x4e, 0x0a, - 0x06, 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, - 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x53, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x1a, 0x3c, 0x0a, - 0x06, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x8b, 0x01, 0x0a, 0x09, - 0x43, 0x41, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x04, 0x67, 0x72, 0x70, - 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x42, 0x06, 0xba, 0x48, - 0x03, 0xc8, 0x01, 0x01, 0x52, 0x04, 0x67, 0x72, 0x70, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, - 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x22, 0x52, 0x0a, 0x13, 0x52, 0x65, 0x66, - 0x65, 0x72, 0x72, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x6f, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x4f, 0x72, 0x67, 0x73, 0x22, 0xd3, 0x04, - 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x04, 0x68, 0x74, 0x74, - 0x70, 0x12, 0x37, 0x0a, 0x04, 0x67, 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x47, 0x52, 0x50, 0x43, 0x52, 0x04, 0x67, 0x72, 0x70, 0x63, 0x12, 0x46, 0x0a, 0x0c, 0x68, 0x74, - 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, + 0x73, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x1a, 0x3c, 0x0a, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, + 0x73, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x8b, 0x01, 0x0a, 0x09, 0x43, 0x41, 0x53, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x04, 0x67, 0x72, 0x70, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x1a, 0x8c, 0x01, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x18, 0x0a, 0x07, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x55, 0x72, 0x6c, 0x12, 0x33, 0x0a, 0x07, - 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x1a, 0x48, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, - 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x1a, 0xb5, 0x01, 0x0a, 0x04, - 0x47, 0x52, 0x50, 0x43, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1b, - 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, - 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x12, 0x41, 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, - 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x4c, 0x53, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x22, 0x85, 0x01, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x1a, - 0x3a, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, - 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xf5, 0x02, 0x0a, 0x04, - 0x41, 0x75, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x19, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x6a, 0x77, 0x73, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x4a, 0x77, 0x73, 0x48, 0x6d, 0x61, 0x63, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, - 0x0a, 0x22, 0x63, 0x61, 0x73, 0x5f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x63, 0x61, 0x73, 0x52, - 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x35, 0x0a, 0x04, 0x6f, 0x69, 0x64, - 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x2e, 0x47, 0x52, 0x50, 0x43, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x04, 0x67, + 0x72, 0x70, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, + 0x72, 0x6c, 0x22, 0x52, 0x0a, 0x13, 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x53, 0x68, + 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x6f, + 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, + 0x65, 0x64, 0x4f, 0x72, 0x67, 0x73, 0x22, 0xd3, 0x04, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x12, 0x37, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x48, 0x54, 0x54, 0x50, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x37, 0x0a, 0x04, 0x67, 0x72, + 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x04, 0x67, + 0x72, 0x70, 0x63, 0x12, 0x46, 0x0a, 0x0c, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x0b, + 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x8c, 0x01, 0x0a, 0x04, + 0x48, 0x54, 0x54, 0x50, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, + 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, + 0x64, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x75, + 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x55, 0x72, 0x6c, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x1a, 0x48, 0x0a, 0x03, 0x54, 0x4c, + 0x53, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x4b, 0x65, 0x79, 0x1a, 0xb5, 0x01, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x12, 0x18, 0x0a, + 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1b, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, + 0x61, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x41, 0x0a, 0x0a, 0x74, 0x6c, 0x73, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x4c, + 0x53, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x85, 0x01, 0x0a, + 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x04, 0x6f, 0x69, 0x64, 0x63, - 0x1a, 0x90, 0x01, 0x0a, 0x04, 0x4f, 0x49, 0x44, 0x43, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, - 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, - 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, - 0x65, 0x6d, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x02, 0x43, 0x41, 0x12, 0x3c, 0x0a, 0x07, 0x66, 0x69, - 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x41, 0x48, 0x00, - 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x1a, 0x5b, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x65, - 0x43, 0x41, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, - 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, - 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, - 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, 0x0a, 0x02, 0x63, 0x61, 0x22, 0x38, 0x0a, 0x0e, 0x4f, - 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, - 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x1a, 0x3a, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x22, 0xf5, 0x02, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x39, 0x0a, + 0x19, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6a, 0x77, 0x73, 0x5f, 0x68, + 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x16, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4a, 0x77, 0x73, 0x48, 0x6d, + 0x61, 0x63, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, + 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x22, 0x63, 0x61, 0x73, 0x5f, 0x72, + 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x1d, 0x63, 0x61, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x35, 0x0a, 0x04, 0x6f, 0x69, 0x64, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x4f, + 0x49, 0x44, 0x43, 0x52, 0x04, 0x6f, 0x69, 0x64, 0x63, 0x1a, 0x90, 0x01, 0x0a, 0x04, 0x4f, 0x49, + 0x44, 0x43, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x13, + 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x22, 0xa5, 0x01, 0x0a, + 0x02, 0x43, 0x41, 0x12, 0x3c, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, + 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x41, 0x48, 0x00, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x43, + 0x61, 0x1a, 0x5b, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x41, 0x12, 0x1b, 0x0a, 0x09, 0x63, + 0x65, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x65, 0x72, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, + 0x0a, 0x02, 0x63, 0x61, 0x22, 0x59, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x72, 0x6f, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, + 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, + 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1296,7 +1302,8 @@ var file_controlplane_config_v1_conf_proto_goTypes = []interface{}{ (*Auth_OIDC)(nil), // 14: controlplane.config.v1.Auth.OIDC (*CA_FileCA)(nil), // 15: controlplane.config.v1.CA.FileCA (*v1.Credentials)(nil), // 16: credentials.v1.Credentials - (*durationpb.Duration)(nil), // 17: google.protobuf.Duration + (v11.MembershipRole)(0), // 17: controlplane.v1.MembershipRole + (*durationpb.Duration)(nil), // 18: google.protobuf.Duration } var file_controlplane_config_v1_conf_proto_depIdxs = []int32{ 2, // 0: controlplane.config.v1.Bootstrap.server:type_name -> controlplane.config.v1.Server @@ -1314,16 +1321,17 @@ var file_controlplane_config_v1_conf_proto_depIdxs = []int32{ 13, // 12: controlplane.config.v1.Data.database:type_name -> controlplane.config.v1.Data.Database 14, // 13: controlplane.config.v1.Auth.oidc:type_name -> controlplane.config.v1.Auth.OIDC 15, // 14: controlplane.config.v1.CA.file_ca:type_name -> controlplane.config.v1.CA.FileCA - 9, // 15: controlplane.config.v1.Bootstrap.Observability.sentry:type_name -> controlplane.config.v1.Bootstrap.Observability.Sentry - 12, // 16: controlplane.config.v1.Bootstrap.CASServer.grpc:type_name -> controlplane.config.v1.Server.GRPC - 17, // 17: controlplane.config.v1.Server.HTTP.timeout:type_name -> google.protobuf.Duration - 17, // 18: controlplane.config.v1.Server.GRPC.timeout:type_name -> google.protobuf.Duration - 11, // 19: controlplane.config.v1.Server.GRPC.tls_config:type_name -> controlplane.config.v1.Server.TLS - 20, // [20:20] is the sub-list for method output_type - 20, // [20:20] is the sub-list for method input_type - 20, // [20:20] is the sub-list for extension type_name - 20, // [20:20] is the sub-list for extension extendee - 0, // [0:20] is the sub-list for field type_name + 17, // 15: controlplane.config.v1.OnboardingSpec.role:type_name -> controlplane.v1.MembershipRole + 9, // 16: controlplane.config.v1.Bootstrap.Observability.sentry:type_name -> controlplane.config.v1.Bootstrap.Observability.Sentry + 12, // 17: controlplane.config.v1.Bootstrap.CASServer.grpc:type_name -> controlplane.config.v1.Server.GRPC + 18, // 18: controlplane.config.v1.Server.HTTP.timeout:type_name -> google.protobuf.Duration + 18, // 19: controlplane.config.v1.Server.GRPC.timeout:type_name -> google.protobuf.Duration + 11, // 20: controlplane.config.v1.Server.GRPC.tls_config:type_name -> controlplane.config.v1.Server.TLS + 21, // [21:21] is the sub-list for method output_type + 21, // [21:21] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_controlplane_config_v1_conf_proto_init() } diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto index 4ad37f2d0..6b1b51564 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto @@ -20,6 +20,7 @@ package controlplane.config.v1; import "buf/validate/validate.proto"; import "credentials/v1/config.proto"; import "google/protobuf/duration.proto"; +import "controlplane/v1/response_messages.proto"; option go_package = "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1;conf"; @@ -141,8 +142,8 @@ message CA { // OnboardingSpec is a configuration to automatically onboard users in organizations with specific roles message OnboardingSpec { - // name is the name of the organization + // Name of the organization string name = 1; - // role is the role to assign to the user. For the moment, only "viewer" is supported - string role = 2; + // Role to assign to the user + controlplane.v1.MembershipRole role = 2; } diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index 3a7c9341e..56994de08 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -54,11 +54,6 @@ const ( shortLivedDuration = 10 * time.Second // opt-in logLivedDuration = 24 * time.Hour - - // AutoOnboarding roles for the organizations - AutoOnboardingViewerRole = "viewer" - AutoOnboardingAdminRole = "admin" - AutoOnboardingOwnerRole = "owner" ) type oauthHandler struct { @@ -77,10 +72,9 @@ type AuthService struct { membershipUseCase *biz.MembershipUseCase orgInvitesUseCase *biz.OrgInvitationUseCase AuthURLs *AuthURLs - onboardingConfig []*conf.OnboardingSpec } -func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, onboardingConfig []*conf.OnboardingSpec, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { +func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { oidcConfig := authConfig.GetOidc() if oidcConfig == nil { return nil, errors.New("oauth configuration missing") @@ -106,7 +100,6 @@ func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC AuthURLs: authURLs, membershipUseCase: mUC, orgInvitesUseCase: inviteUC, - onboardingConfig: onboardingConfig, }, nil } @@ -249,11 +242,6 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) ( svc.log.Infow("msg", "new user associated to an org", "org_id", currentOrg.ID, "user_id", u.ID) } - // Auto onboard the user to the organizations specified in the config - if err := autoOnboardOnOrganizations(ctx, svc, u); err != nil { - return http.StatusInternalServerError, sl.LogAndMaskErr(err, svc.log) - } - // Accept any pending invites if err := svc.orgInvitesUseCase.AcceptPendingInvitations(ctx, u.Email); err != nil { return http.StatusInternalServerError, sl.LogAndMaskErr(err, svc.log) @@ -301,61 +289,6 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) ( return http.StatusTemporaryRedirect, nil } -// autoOnboardOnOrganizations onboards the user to the organizations specified in the config -// If the organization does not exist, it will be created with an inline CAS backend -// If the user is not already a member of the organization, a membership will be created with the role specified in the config -func autoOnboardOnOrganizations(ctx context.Context, svc *AuthService, u *biz.User) error { - for _, spec := range svc.onboardingConfig { - // Ensure the organization exists or create it if it doesn't - org, err := svc.orgUseCase.FindOrCreate(ctx, spec.GetName()) - if err != nil { - return sl.LogAndMaskErr(err, svc.log) - } - - // Determine the role to be assigned based on the config - role := determineRole(spec.GetRole()) - - // Ensures the user is a member of the organization with the specified role - if err := ensureMembership(ctx, svc, org.ID, u.ID, role); err != nil { - return sl.LogAndMaskErr(err, svc.log) - } - } - return nil -} - -// determineRole maps the config role to the appropriate authz.Role -func determineRole(configRole string) authz.Role { - switch configRole { - case AutoOnboardingAdminRole: - return authz.RoleAdmin - case AutoOnboardingViewerRole: - return authz.RoleViewer - case AutoOnboardingOwnerRole: - return authz.RoleOwner - default: - return authz.RoleViewer - } -} - -// ensureMembership ensures the user is a member of the organization with the specified role -func ensureMembership(ctx context.Context, svc *AuthService, orgID, userID string, role authz.Role) error { - m, err := svc.membershipUseCase.FindByOrgAndUser(ctx, orgID, userID) - if err != nil && !errors.As(err, &biz.ErrNotFound{}) { - return err - } - - // If there is a membership, we don't need to do anything - // Don't compare the role, as the user might have a different role, and we cannot update it - // because the user might have been assigned a different role by an admin - if m != nil { - return nil - } - - // Create the membership with the proper role if it doesn't exist - _, err = svc.membershipUseCase.Create(ctx, orgID, userID, biz.WithCurrentMembership(), biz.WithMembershipRole(role)) - return err -} - func crafCallbackURL(callback, userToken string) (string, error) { callbackURL, err := url.Parse(callback) if err != nil { diff --git a/app/controlplane/internal/service/auth_test.go b/app/controlplane/internal/service/auth_test.go index 307d80293..4345d1323 100644 --- a/app/controlplane/internal/service/auth_test.go +++ b/app/controlplane/internal/service/auth_test.go @@ -16,15 +16,10 @@ package service import ( - "context" "testing" - "github.com/chainloop-dev/chainloop/app/controlplane/internal/authz" conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/testhelpers" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" ) func TestGetAuthURLs(t *testing.T) { @@ -79,102 +74,3 @@ func TestGetAuthURLs(t *testing.T) { }) } } - -func TestAuthOnboarding(t *testing.T) { - suite.Run(t, new(authOnboardingTestSuite)) -} - -type authOnboardingTestSuite struct { - testhelpers.UseCasesEachTestSuite - usr, usr1 *biz.User - org *biz.Organization - m *biz.Membership -} - -func (s *authOnboardingTestSuite) SetupTest() { - t := s.T() - assert := assert.New(t) - ctx := context.Background() - - s.TestingUseCases = testhelpers.NewTestingUseCases(t) - - s.setupUsersAndOrganization(ctx, assert) - s.setupMembership(ctx, assert) -} - -func (s *authOnboardingTestSuite) setupUsersAndOrganization(ctx context.Context, assert *assert.Assertions) { - var err error - s.usr, err = s.User.FindOrCreateByEmail(ctx, "foo@bar") - assert.NoError(err) - - s.org, err = s.Organization.Create(ctx, "onboarded-org") - assert.NoError(err) - - s.usr1, err = s.User.FindOrCreateByEmail(ctx, "bar@foo") - assert.NoError(err) -} - -func (s *authOnboardingTestSuite) setupMembership(ctx context.Context, assert *assert.Assertions) { - var err error - s.m, err = s.Membership.Create(ctx, s.org.ID, s.usr1.ID, biz.WithMembershipRole(authz.RoleViewer)) - assert.NoError(err) -} - -func (s *authOnboardingTestSuite) TestAutoOnboardOrganizations() { - ctx := context.Background() - t := s.T() - assert := assert.New(t) - - svc := s.newAuthService("testing-org", "viewer") - - org, err := s.Organization.FindByName(ctx, "testing-org") - assert.Error(err) - assert.Nil(org) - - err = autoOnboardOnOrganizations(ctx, svc, s.usr) - assert.NoError(err) - - org, err = s.Organization.FindByName(ctx, "testing-org") - assert.NoError(err) - assert.NotNil(org) - - m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr.ID) - assert.NoError(err) - assert.NotNil(m) -} - -func (s *authOnboardingTestSuite) TestAutoOnboardWithExistingMemberships() { - ctx := context.Background() - t := s.T() - assert := assert.New(t) - - svc := s.newAuthService(s.org.Name, string(s.m.Role)) - - org, err := s.Organization.FindByName(ctx, s.org.Name) - assert.NoError(err) - assert.NotNil(org) - - m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) - assert.NoError(err) - assert.NotNil(m) - assert.Equal(s.m.Role, m.Role) - - err = autoOnboardOnOrganizations(ctx, svc, s.usr1) - assert.NoError(err) - - newM, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) - assert.NoError(err) - assert.NotNil(newM) - assert.Equal(s.m.Role, newM.Role) -} - -func (s *authOnboardingTestSuite) newAuthService(orgName, role string) *AuthService { - return &AuthService{ - onboardingConfig: []*conf.OnboardingSpec{ - {Name: orgName, Role: role}, - }, - userUseCase: s.TestingUseCases.User, - orgUseCase: s.TestingUseCases.Organization, - membershipUseCase: s.TestingUseCases.Membership, - } -} diff --git a/app/controlplane/internal/service/organization.go b/app/controlplane/internal/service/organization.go index 85105a54d..c87eb0587 100644 --- a/app/controlplane/internal/service/organization.go +++ b/app/controlplane/internal/service/organization.go @@ -121,7 +121,7 @@ func (s *OrganizationService) UpdateMembership(ctx context.Context, req *pb.Orga return nil, err } - m, err := s.membershipUC.UpdateRole(ctx, currentOrg.ID, currentUser.ID, req.MembershipId, pbRoleToBiz(req.Role)) + m, err := s.membershipUC.UpdateRole(ctx, currentOrg.ID, currentUser.ID, req.MembershipId, biz.PbRoleToBiz(req.Role)) if err != nil { return nil, handleUseCaseErr(err, s.log) } diff --git a/app/controlplane/internal/service/orginvitation.go b/app/controlplane/internal/service/orginvitation.go index cae207256..c05b00829 100644 --- a/app/controlplane/internal/service/orginvitation.go +++ b/app/controlplane/internal/service/orginvitation.go @@ -49,7 +49,7 @@ func (s *OrgInvitationService) Create(ctx context.Context, req *pb.OrgInvitation } // Validations and rbac checks are done in the biz layer - i, err := s.useCase.Create(ctx, org.ID, user.ID, req.ReceiverEmail, biz.WithInvitationRole(pbRoleToBiz(req.Role))) + i, err := s.useCase.Create(ctx, org.ID, user.ID, req.ReceiverEmail, biz.WithInvitationRole(biz.PbRoleToBiz(req.Role))) if err != nil { return nil, handleUseCaseErr(err, s.log) } diff --git a/app/controlplane/internal/service/user.go b/app/controlplane/internal/service/user.go index 788556f10..9552b3ad7 100644 --- a/app/controlplane/internal/service/user.go +++ b/app/controlplane/internal/service/user.go @@ -95,19 +95,6 @@ func (s *UserService) DeleteMembership(ctx context.Context, req *pb.DeleteMember return &pb.DeleteMembershipResponse{}, nil } -func pbRoleToBiz(r pb.MembershipRole) authz.Role { - switch r { - case pb.MembershipRole_MEMBERSHIP_ROLE_ORG_OWNER: - return authz.RoleOwner - case pb.MembershipRole_MEMBERSHIP_ROLE_ORG_ADMIN: - return authz.RoleAdmin - case pb.MembershipRole_MEMBERSHIP_ROLE_ORG_VIEWER: - return authz.RoleViewer - default: - return "" - } -} - func bizMembershipToPb(m *biz.Membership) *pb.OrgMembershipItem { item := &pb.OrgMembershipItem{ Id: m.ID.String(), Current: m.Current, diff --git a/app/controlplane/internal/usercontext/apitoken_middleware_test.go b/app/controlplane/internal/usercontext/apitoken_middleware_test.go index 3fa15461a..370efb91a 100644 --- a/app/controlplane/internal/usercontext/apitoken_middleware_test.go +++ b/app/controlplane/internal/usercontext/apitoken_middleware_test.go @@ -101,7 +101,7 @@ func TestWithCurrentAPITokenAndOrgMiddleware(t *testing.T) { orgRepo := bizMocks.NewOrganizationRepo(t) apiTokenUC, err := biz.NewAPITokenUseCase(apiTokenRepo, &conf.Auth{GeneratedJwsHmacSecret: "test"}, nil, nil) require.NoError(t, err) - orgUC := biz.NewOrganizationUseCase(orgRepo, nil, nil, nil, nil) + orgUC := biz.NewOrganizationUseCase(orgRepo, nil, nil, nil, nil, nil) require.NoError(t, err) ctx := context.Background() diff --git a/app/controlplane/pkg/biz/organization.go b/app/controlplane/pkg/biz/organization.go index 957f6e7db..d1b5d3273 100644 --- a/app/controlplane/pkg/biz/organization.go +++ b/app/controlplane/pkg/biz/organization.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" "github.com/moby/moby/pkg/namesgenerator" @@ -45,14 +46,16 @@ type OrganizationUseCase struct { casBackendUseCase *CASBackendUseCase integrationUC *IntegrationUseCase membershipRepo MembershipRepo + onboardingConfig []*conf.OnboardingSpec } -func NewOrganizationUseCase(repo OrganizationRepo, repoUC *CASBackendUseCase, iUC *IntegrationUseCase, mRepo MembershipRepo, logger log.Logger) *OrganizationUseCase { +func NewOrganizationUseCase(repo OrganizationRepo, repoUC *CASBackendUseCase, iUC *IntegrationUseCase, mRepo MembershipRepo, onboardingConfig []*conf.OnboardingSpec, logger log.Logger) *OrganizationUseCase { return &OrganizationUseCase{orgRepo: repo, logger: log.NewHelper(logger), casBackendUseCase: repoUC, integrationUC: iUC, membershipRepo: mRepo, + onboardingConfig: onboardingConfig, } } @@ -214,16 +217,6 @@ func (uc *OrganizationUseCase) FindByName(ctx context.Context, name string) (*Or return org, nil } -// FindOrCreate finds an organization by name, or creates it if it doesn't exist. -func (uc *OrganizationUseCase) FindOrCreate(ctx context.Context, name string) (*Organization, error) { - org, err := uc.FindByName(ctx, name) - if err != nil && errors.As(err, &ErrNotFound{}) { - org, err = uc.Create(ctx, name, WithCreateInlineBackend()) - } - - return org, err -} - // Delete deletes an organization and all relevant data // This includes: // - The organization @@ -271,3 +264,75 @@ func (uc *OrganizationUseCase) Delete(ctx context.Context, id string) error { // Delete the organization return uc.orgRepo.Delete(ctx, orgUUID) } + +// AutoOnboardOrganizations creates the organizations specified in the onboarding config and assigns the user to them +// with the specified role if they are not already a member. +func (uc *OrganizationUseCase) AutoOnboardOrganizations(ctx context.Context, userID string) error { + // Parse user UUID + userUUID, err := uuid.Parse(userID) + if err != nil { + return NewErrInvalidUUID(err) + } + + for _, spec := range uc.onboardingConfig { + // Ensure the organization exists or create it if it doesn't + org, err := uc.ensureOrganizationExists(ctx, spec) + if err != nil { + return fmt.Errorf("failed to ensure organization exists: %w", err) + } + + // Parse organization UUID + orgUUID, err := uuid.Parse(org.ID) + if err != nil { + return NewErrInvalidUUID(err) + } + + // Ensure user membership + if err := uc.ensureUserMembership(ctx, orgUUID, userUUID, spec); err != nil { + return fmt.Errorf("failed to ensure user membership: %w", err) + } + } + + return nil +} + +// ensureOrganizationExists ensures that an organization specified by the onboarding configuration exists. +// If the organization does not exist, it creates it. +func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spec *conf.OnboardingSpec) (*Organization, error) { + // Ensure the organization exists or create it if it doesn't + org, err := uc.FindByName(ctx, spec.GetName()) + if err != nil { + if errors.As(err, &ErrNotFound{}) { + org, err = uc.Create(ctx, spec.GetName(), WithCreateInlineBackend()) + if err != nil { + return nil, fmt.Errorf("failed to create organization: %w", err) + } + } else { + return nil, fmt.Errorf("failed to find organization: %w", err) + } + } + + return org, nil +} + +// ensureUserMembership ensures that a user is a member of the specified organization with the appropriate role. +// If the membership does not exist, it creates it. +func (uc *OrganizationUseCase) ensureUserMembership(ctx context.Context, orgUUID, userUUID uuid.UUID, spec *conf.OnboardingSpec) error { + m, err := uc.membershipRepo.FindByOrgAndUser(ctx, orgUUID, userUUID) + if err != nil && !errors.As(err, &ErrNotFound{}) { + return fmt.Errorf("failed to find membership: %w", err) + } + + if m != nil { + // Membership already exists, no further action needed + return nil + } + + // Create the membership with the specified role + _, err = uc.membershipRepo.Create(ctx, orgUUID, userUUID, true, PbRoleToBiz(spec.GetRole())) + if err != nil { + return fmt.Errorf("failed to create membership: %w", err) + } + + return nil +} diff --git a/app/controlplane/pkg/biz/organization_integration_test.go b/app/controlplane/pkg/biz/organization_integration_test.go index 26a92a7c5..6fc7dfc34 100644 --- a/app/controlplane/pkg/biz/organization_integration_test.go +++ b/app/controlplane/pkg/biz/organization_integration_test.go @@ -19,6 +19,9 @@ import ( "context" "testing" + v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/authz" + conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/testhelpers" "github.com/chainloop-dev/chainloop/app/controlplane/plugins/sdk/v1" @@ -193,6 +196,7 @@ func (s *OrgIntegrationTestSuite) TestDeleteOrg() { // Run the tests func TestOrgUseCase(t *testing.T) { suite.Run(t, new(OrgIntegrationTestSuite)) + suite.Run(t, new(AuthOnboardingTestSuite)) } // Utility struct to hold the test suite @@ -268,3 +272,88 @@ func (s *OrgIntegrationTestSuite) SetupTest() { assert.NoError(err) assert.Len(contracts, 1) } + +type AuthOnboardingTestSuite struct { + testhelpers.UseCasesEachTestSuite + usr, usr1 *biz.User + org *biz.Organization + m *biz.Membership +} + +func (s *AuthOnboardingTestSuite) SetupTest() { + t := s.T() + assert := assert.New(t) + ctx := context.Background() + + s.TestingUseCases = testhelpers.NewTestingUseCases(t, testhelpers.WithOnboardingConfiguration([]*conf.OnboardingSpec{ + { + Name: "testing-org", + Role: v1.MembershipRole_MEMBERSHIP_ROLE_ORG_VIEWER, + }, + })) + + s.setupUsersAndOrganization(ctx, assert) + s.setupMembership(ctx, assert) +} + +func (s *AuthOnboardingTestSuite) setupUsersAndOrganization(ctx context.Context, assert *assert.Assertions) { + var err error + s.org, err = s.Organization.Create(ctx, "onboarded-org") + assert.NoError(err) + + s.usr, err = s.User.CreateByEmail(ctx, "foo@bar") + assert.NoError(err) + + s.usr1, err = s.User.CreateByEmail(ctx, "bar@foo") + assert.NoError(err) +} + +func (s *AuthOnboardingTestSuite) setupMembership(ctx context.Context, assert *assert.Assertions) { + var err error + s.m, err = s.Membership.Create(ctx, s.org.ID, s.usr1.ID, biz.WithMembershipRole(authz.RoleViewer)) + assert.NoError(err) +} + +func (s *AuthOnboardingTestSuite) TestAutoOnboardOrganizations() { + ctx := context.Background() + t := s.T() + assert := assert.New(t) + + org, err := s.Organization.FindByName(ctx, "testing-org") + assert.Error(err) + assert.Nil(org) + + err = s.Organization.AutoOnboardOrganizations(ctx, s.usr.ID) + assert.NoError(err) + + org, err = s.Organization.FindByName(ctx, "testing-org") + assert.NoError(err) + assert.NotNil(org) + + m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr.ID) + assert.NoError(err) + assert.NotNil(m) +} + +func (s *AuthOnboardingTestSuite) TestAutoOnboardWithExistingMemberships() { + ctx := context.Background() + t := s.T() + assert := assert.New(t) + + org, err := s.Organization.FindByName(ctx, s.org.Name) + assert.NoError(err) + assert.NotNil(org) + + m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) + assert.NoError(err) + assert.NotNil(m) + assert.Equal(s.m.Role, m.Role) + + err = s.Organization.AutoOnboardOrganizations(ctx, s.usr1.ID) + assert.NoError(err) + + newM, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) + assert.NoError(err) + assert.NotNil(newM) + assert.Equal(s.m.Role, newM.Role) +} diff --git a/app/controlplane/pkg/biz/organization_test.go b/app/controlplane/pkg/biz/organization_test.go index ce7b5b3a8..ee6a0b355 100644 --- a/app/controlplane/pkg/biz/organization_test.go +++ b/app/controlplane/pkg/biz/organization_test.go @@ -33,7 +33,7 @@ type organizationTestSuite struct { func (s *organizationTestSuite) TestCreateWithRandomName() { repo := repoM.NewOrganizationRepo(s.T()) - uc := biz.NewOrganizationUseCase(repo, nil, nil, nil, log.NewStdLogger(io.Discard)) + uc := biz.NewOrganizationUseCase(repo, nil, nil, nil, nil, log.NewStdLogger(io.Discard)) s.Run("the org exists, we retry", func() { ctx := context.Background() diff --git a/app/controlplane/pkg/biz/testhelpers/database.go b/app/controlplane/pkg/biz/testhelpers/database.go index b970dc39d..3a2b2e1e8 100644 --- a/app/controlplane/pkg/biz/testhelpers/database.go +++ b/app/controlplane/pkg/biz/testhelpers/database.go @@ -83,9 +83,10 @@ type TestingRepos struct { } type newTestingOpts struct { - credsReaderWriter credentials.ReaderWriter - integrations sdk.AvailablePlugins - providers backends.Providers + credsReaderWriter credentials.ReaderWriter + integrations sdk.AvailablePlugins + providers backends.Providers + onboardingConfiguration []*conf.OnboardingSpec } type NewTestingUCOpt func(*newTestingOpts) @@ -106,6 +107,12 @@ func WithRegisteredIntegration(i sdk.FanOut) NewTestingUCOpt { } } +func WithOnboardingConfiguration(conf []*conf.OnboardingSpec) NewTestingUCOpt { + return func(tu *newTestingOpts) { + tu.onboardingConfiguration = conf + } +} + func NewTestingUseCases(t *testing.T, opts ...NewTestingUCOpt) *TestingUseCases { // default args newArgs := &newTestingOpts{credsReaderWriter: creds.NewReaderWriter(t), @@ -125,7 +132,7 @@ func NewTestingUseCases(t *testing.T, opts ...NewTestingUCOpt) *TestingUseCases testData, _, err := WireTestData(db, t, log, newArgs.credsReaderWriter, &robotaccount.Builder{}, &conf.Auth{ GeneratedJwsHmacSecret: "test", CasRobotAccountPrivateKeyPath: "./testdata/test-key.ec.pem", - }, newArgs.integrations, newArgs.providers) + }, newArgs.onboardingConfiguration, newArgs.integrations, newArgs.providers) assert.NoError(t, err) // Run DB migrations for testing diff --git a/app/controlplane/pkg/biz/testhelpers/wire.go b/app/controlplane/pkg/biz/testhelpers/wire.go index 413192d47..f4077f598 100644 --- a/app/controlplane/pkg/biz/testhelpers/wire.go +++ b/app/controlplane/pkg/biz/testhelpers/wire.go @@ -36,7 +36,7 @@ import ( ) // wireTestData init testing data -func WireTestData(*TestDatabase, *testing.T, log.Logger, credentials.ReaderWriter, *robotaccount.Builder, *conf.Auth, sdk.AvailablePlugins, backends.Providers) (*TestingUseCases, func(), error) { +func WireTestData(*TestDatabase, *testing.T, log.Logger, credentials.ReaderWriter, *robotaccount.Builder, *conf.Auth, []*conf.OnboardingSpec, sdk.AvailablePlugins, backends.Providers) (*TestingUseCases, func(), error) { panic( wire.Build( data.ProviderSet, diff --git a/app/controlplane/pkg/biz/testhelpers/wire_gen.go b/app/controlplane/pkg/biz/testhelpers/wire_gen.go index 5a5448bec..0894e2cee 100644 --- a/app/controlplane/pkg/biz/testhelpers/wire_gen.go +++ b/app/controlplane/pkg/biz/testhelpers/wire_gen.go @@ -26,7 +26,7 @@ import ( // Injectors from wire.go: // wireTestData init testing data -func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, readerWriter credentials.ReaderWriter, builder *robotaccount.Builder, auth *conf.Auth, availablePlugins sdk.AvailablePlugins, providers backend.Providers) (*TestingUseCases, func(), error) { +func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, readerWriter credentials.ReaderWriter, builder *robotaccount.Builder, auth *conf.Auth, arg []*conf.OnboardingSpec, availablePlugins sdk.AvailablePlugins, providers backend.Providers) (*TestingUseCases, func(), error) { confData := NewConfData(testDatabase, t) newConfig := NewDataConfig(confData) dataData, cleanup, err := data.NewData(newConfig, logger) @@ -48,7 +48,7 @@ func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, r Logger: logger, } integrationUseCase := biz.NewIntegrationUseCase(newIntegrationUseCaseOpts) - organizationUseCase := biz.NewOrganizationUseCase(organizationRepo, casBackendUseCase, integrationUseCase, membershipRepo, logger) + organizationUseCase := biz.NewOrganizationUseCase(organizationRepo, casBackendUseCase, integrationUseCase, membershipRepo, arg, logger) membershipUseCase := biz.NewMembershipUseCase(membershipRepo, organizationUseCase, logger) workflowContractRepo := data.NewWorkflowContractRepo(dataData, logger) workflowContractUseCase := biz.NewWorkflowContractUseCase(workflowContractRepo, logger) @@ -64,6 +64,7 @@ func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, r UserRepo: userRepo, MembershipUseCase: membershipUseCase, OrganizationUseCase: organizationUseCase, + OnboardingConfig: arg, Logger: logger, } userUseCase := biz.NewUserUseCase(newUserUseCaseParams) diff --git a/app/controlplane/pkg/biz/user.go b/app/controlplane/pkg/biz/user.go index 162392799..91d6f8b24 100644 --- a/app/controlplane/pkg/biz/user.go +++ b/app/controlplane/pkg/biz/user.go @@ -21,6 +21,9 @@ import ( "fmt" "time" + pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/authz" + conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" ) @@ -48,12 +51,14 @@ type UserUseCase struct { logger *log.Helper membershipUseCase *MembershipUseCase organizationUseCase *OrganizationUseCase + onboardingConfig []*conf.OnboardingSpec } type NewUserUseCaseParams struct { UserRepo UserRepo MembershipUseCase *MembershipUseCase OrganizationUseCase *OrganizationUseCase + OnboardingConfig []*conf.OnboardingSpec Logger log.Logger } @@ -62,6 +67,7 @@ func NewUserUseCase(opts *NewUserUseCaseParams) *UserUseCase { userRepo: opts.UserRepo, membershipUseCase: opts.MembershipUseCase, organizationUseCase: opts.OrganizationUseCase, + onboardingConfig: opts.OnboardingConfig, logger: log.NewHelper(opts.Logger), } } @@ -90,6 +96,15 @@ func (uc *UserUseCase) DeleteUser(ctx context.Context, userID string) error { return uc.userRepo.Delete(ctx, userUUID) } +func (uc *UserUseCase) CreateByEmail(ctx context.Context, email string) (*User, error) { + u, err := uc.userRepo.CreateByEmail(ctx, email) + if err != nil { + return nil, fmt.Errorf("failed to create user: %w", err) + } + + return u, nil +} + func (uc *UserUseCase) FindOrCreateByEmail(ctx context.Context, email string) (*User, error) { u, err := uc.userRepo.FindByEmail(ctx, email) if err != nil { @@ -98,7 +113,16 @@ func (uc *UserUseCase) FindOrCreateByEmail(ctx context.Context, email string) (* return u, nil } - return uc.userRepo.CreateByEmail(ctx, email) + u, err = uc.CreateByEmail(ctx, email) + if err != nil { + return nil, fmt.Errorf("failed to create user: %w", err) + } + + if err := uc.organizationUseCase.AutoOnboardOrganizations(ctx, u.ID); err != nil { + return nil, fmt.Errorf("failed to auto-onboard user: %w", err) + } + + return u, err } func (uc *UserUseCase) FindByID(ctx context.Context, userID string) (*User, error) { @@ -137,3 +161,16 @@ func (uc *UserUseCase) CurrentMembership(ctx context.Context, userID string) (*M return m, nil } + +func PbRoleToBiz(r pb.MembershipRole) authz.Role { + switch r { + case pb.MembershipRole_MEMBERSHIP_ROLE_ORG_OWNER: + return authz.RoleOwner + case pb.MembershipRole_MEMBERSHIP_ROLE_ORG_ADMIN: + return authz.RoleAdmin + case pb.MembershipRole_MEMBERSHIP_ROLE_ORG_VIEWER: + return authz.RoleViewer + default: + return "" + } +} From 856e745aa67a123c1548c09c9691d1d4d5ae167c Mon Sep 17 00:00:00 2001 From: Javier Rodriguez Date: Mon, 17 Jun 2024 11:53:53 +0200 Subject: [PATCH 4/4] Tackle feedback Signed-off-by: Javier Rodriguez --- .../conf/controlplane/config/v1/conf.pb.go | 27 ++--- .../conf/controlplane/config/v1/conf.proto | 2 +- app/controlplane/pkg/biz/organization.go | 38 +++---- .../pkg/biz/organization_integration_test.go | 103 ++++++++++++------ .../pkg/biz/testhelpers/database.go | 1 + .../pkg/biz/testhelpers/wire_gen.go | 1 + app/controlplane/pkg/biz/user.go | 23 ++-- .../pkg/biz/user_integration_test.go | 39 +++++++ 8 files changed, 148 insertions(+), 86 deletions(-) diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go index e24fcb828..4b02e8abd 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go @@ -1256,19 +1256,20 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x42, 0x04, - 0x0a, 0x02, 0x63, 0x61, 0x22, 0x59, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, - 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x72, 0x6f, - 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, - 0x5f, 0x5a, 0x5d, 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, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, - 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0a, 0x02, 0x63, 0x61, 0x22, 0x62, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, + 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x42, 0x5f, 0x5a, 0x5d, 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, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto index 6b1b51564..3f68a3328 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto @@ -143,7 +143,7 @@ message CA { // OnboardingSpec is a configuration to automatically onboard users in organizations with specific roles message OnboardingSpec { // Name of the organization - string name = 1; + string name = 1 [(buf.validate.field).string.min_len = 1];; // Role to assign to the user controlplane.v1.MembershipRole role = 2; } diff --git a/app/controlplane/pkg/biz/organization.go b/app/controlplane/pkg/biz/organization.go index d1b5d3273..1514c68fb 100644 --- a/app/controlplane/pkg/biz/organization.go +++ b/app/controlplane/pkg/biz/organization.go @@ -201,22 +201,6 @@ func (uc *OrganizationUseCase) FindByID(ctx context.Context, id string) (*Organi return org, nil } -// FindByName finds an organization by name. -func (uc *OrganizationUseCase) FindByName(ctx context.Context, name string) (*Organization, error) { - if err := ValidateIsDNS1123(name); err != nil { - return nil, NewErrValidation(errOrgName) - } - - org, err := uc.orgRepo.FindByName(ctx, name) - if err != nil { - return nil, fmt.Errorf("failed to find organization: %w", err) - } else if org == nil { - return nil, NewErrNotFound("organization") - } - - return org, nil -} - // Delete deletes an organization and all relevant data // This includes: // - The organization @@ -300,15 +284,19 @@ func (uc *OrganizationUseCase) AutoOnboardOrganizations(ctx context.Context, use // If the organization does not exist, it creates it. func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spec *conf.OnboardingSpec) (*Organization, error) { // Ensure the organization exists or create it if it doesn't - org, err := uc.FindByName(ctx, spec.GetName()) + org, err := uc.orgRepo.FindByName(ctx, spec.GetName()) if err != nil { - if errors.As(err, &ErrNotFound{}) { - org, err = uc.Create(ctx, spec.GetName(), WithCreateInlineBackend()) - if err != nil { - return nil, fmt.Errorf("failed to create organization: %w", err) - } - } else { - return nil, fmt.Errorf("failed to find organization: %w", err) + return nil, fmt.Errorf("failed to find organization: %w", err) + } else if org == nil { + // Create the organization since it does not exist + org, err = uc.orgRepo.Create(ctx, spec.GetName()) + if err != nil { + return nil, fmt.Errorf("failed to create organization: %w", err) + } + + // Create default inline CAS-backend + if _, err := uc.casBackendUseCase.CreateInlineFallbackBackend(ctx, org.ID); err != nil { + return nil, fmt.Errorf("failed to create fallback backend: %w", err) } } @@ -319,7 +307,7 @@ func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spe // If the membership does not exist, it creates it. func (uc *OrganizationUseCase) ensureUserMembership(ctx context.Context, orgUUID, userUUID uuid.UUID, spec *conf.OnboardingSpec) error { m, err := uc.membershipRepo.FindByOrgAndUser(ctx, orgUUID, userUUID) - if err != nil && !errors.As(err, &ErrNotFound{}) { + if err != nil { return fmt.Errorf("failed to find membership: %w", err) } diff --git a/app/controlplane/pkg/biz/organization_integration_test.go b/app/controlplane/pkg/biz/organization_integration_test.go index 6fc7dfc34..55b34a83d 100644 --- a/app/controlplane/pkg/biz/organization_integration_test.go +++ b/app/controlplane/pkg/biz/organization_integration_test.go @@ -282,7 +282,6 @@ type AuthOnboardingTestSuite struct { func (s *AuthOnboardingTestSuite) SetupTest() { t := s.T() - assert := assert.New(t) ctx := context.Background() s.TestingUseCases = testhelpers.NewTestingUseCases(t, testhelpers.WithOnboardingConfiguration([]*conf.OnboardingSpec{ @@ -292,68 +291,104 @@ func (s *AuthOnboardingTestSuite) SetupTest() { }, })) - s.setupUsersAndOrganization(ctx, assert) - s.setupMembership(ctx, assert) + s.setupUsersAndOrganization(ctx) + s.setupMembership(ctx) } -func (s *AuthOnboardingTestSuite) setupUsersAndOrganization(ctx context.Context, assert *assert.Assertions) { +func (s *AuthOnboardingTestSuite) setupUsersAndOrganization(ctx context.Context) { var err error s.org, err = s.Organization.Create(ctx, "onboarded-org") - assert.NoError(err) + require.NoError(s.T(), err) - s.usr, err = s.User.CreateByEmail(ctx, "foo@bar") - assert.NoError(err) + s.usr, err = s.User.FindOrCreateByEmail(ctx, "foo@bar", true) + require.NoError(s.T(), err) - s.usr1, err = s.User.CreateByEmail(ctx, "bar@foo") - assert.NoError(err) + s.usr1, err = s.User.FindOrCreateByEmail(ctx, "bar@foo", true) + require.NoError(s.T(), err) } -func (s *AuthOnboardingTestSuite) setupMembership(ctx context.Context, assert *assert.Assertions) { +func (s *AuthOnboardingTestSuite) setupMembership(ctx context.Context) { var err error s.m, err = s.Membership.Create(ctx, s.org.ID, s.usr1.ID, biz.WithMembershipRole(authz.RoleViewer)) - assert.NoError(err) + s.NoError(err) } func (s *AuthOnboardingTestSuite) TestAutoOnboardOrganizations() { ctx := context.Background() - t := s.T() - assert := assert.New(t) - org, err := s.Organization.FindByName(ctx, "testing-org") - assert.Error(err) - assert.Nil(org) + org, err := s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.Nil(err) + s.Nil(org) err = s.Organization.AutoOnboardOrganizations(ctx, s.usr.ID) - assert.NoError(err) + s.NoError(err) - org, err = s.Organization.FindByName(ctx, "testing-org") - assert.NoError(err) - assert.NotNil(org) + org, err = s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.NoError(err) + s.NotNil(org) m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr.ID) - assert.NoError(err) - assert.NotNil(m) + s.NoError(err) + s.NotNil(m) +} + +func (s *AuthOnboardingTestSuite) TestOnboardOrganizationsTwice() { + ctx := context.Background() + + org, err := s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.Nil(err) + s.Nil(org) + + // Call it once + err = s.Organization.AutoOnboardOrganizations(ctx, s.usr.ID) + s.NoError(err) + + // Call it twice + err = s.Organization.AutoOnboardOrganizations(ctx, s.usr.ID) + s.NoError(err) + + org, err = s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.NoError(err) + s.NotNil(org) + + m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr.ID) + s.NoError(err) + s.NotNil(m) } func (s *AuthOnboardingTestSuite) TestAutoOnboardWithExistingMemberships() { ctx := context.Background() - t := s.T() - assert := assert.New(t) - org, err := s.Organization.FindByName(ctx, s.org.Name) - assert.NoError(err) - assert.NotNil(org) + org, err := s.Repos.OrganizationRepo.FindByName(ctx, s.org.Name) + s.Nil(err) + s.NotNil(org) m, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) - assert.NoError(err) - assert.NotNil(m) - assert.Equal(s.m.Role, m.Role) + s.NoError(err) + s.NotNil(m) + s.Equal(s.m.Role, m.Role) err = s.Organization.AutoOnboardOrganizations(ctx, s.usr1.ID) - assert.NoError(err) + s.NoError(err) newM, err := s.Membership.FindByOrgAndUser(ctx, org.ID, s.usr1.ID) - assert.NoError(err) - assert.NotNil(newM) - assert.Equal(s.m.Role, newM.Role) + s.NoError(err) + s.NotNil(newM) + s.Equal(s.m.Role, newM.Role) +} + +func (s *AuthOnboardingTestSuite) TestAutoOnboardWithoutConfiguration() { + ctx := context.Background() + s.TestingUseCases = testhelpers.NewTestingUseCases(s.T()) + + org, err := s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.Nil(err) + s.Nil(org) + + err = s.Organization.AutoOnboardOrganizations(ctx, s.usr.ID) + s.NoError(err) + + org, err = s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.Nil(err) + s.Nil(org) } diff --git a/app/controlplane/pkg/biz/testhelpers/database.go b/app/controlplane/pkg/biz/testhelpers/database.go index 3a2b2e1e8..3de04b3eb 100644 --- a/app/controlplane/pkg/biz/testhelpers/database.go +++ b/app/controlplane/pkg/biz/testhelpers/database.go @@ -80,6 +80,7 @@ type TestingRepos struct { Workflow biz.WorkflowRepo WorkflowRunRepo biz.WorkflowRunRepo AttestationState biz.AttestationStateRepo + OrganizationRepo biz.OrganizationRepo } type newTestingOpts struct { diff --git a/app/controlplane/pkg/biz/testhelpers/wire_gen.go b/app/controlplane/pkg/biz/testhelpers/wire_gen.go index 0894e2cee..52a3863f3 100644 --- a/app/controlplane/pkg/biz/testhelpers/wire_gen.go +++ b/app/controlplane/pkg/biz/testhelpers/wire_gen.go @@ -109,6 +109,7 @@ func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, r Workflow: workflowRepo, WorkflowRunRepo: workflowRunRepo, AttestationState: attestationStateRepo, + OrganizationRepo: organizationRepo, } testingUseCases := &TestingUseCases{ DB: testDatabase, diff --git a/app/controlplane/pkg/biz/user.go b/app/controlplane/pkg/biz/user.go index 91d6f8b24..80883ecd2 100644 --- a/app/controlplane/pkg/biz/user.go +++ b/app/controlplane/pkg/biz/user.go @@ -96,16 +96,10 @@ func (uc *UserUseCase) DeleteUser(ctx context.Context, userID string) error { return uc.userRepo.Delete(ctx, userUUID) } -func (uc *UserUseCase) CreateByEmail(ctx context.Context, email string) (*User, error) { - u, err := uc.userRepo.CreateByEmail(ctx, email) - if err != nil { - return nil, fmt.Errorf("failed to create user: %w", err) - } - - return u, nil -} - -func (uc *UserUseCase) FindOrCreateByEmail(ctx context.Context, email string) (*User, error) { +// FindOrCreateByEmail finds or creates a user by email. By default, it will auto-onboard the user +// to the organizations defined in the configuration. If disableAutoOnboarding is set to true, it will +// skip the auto-onboarding process. +func (uc *UserUseCase) FindOrCreateByEmail(ctx context.Context, email string, disableAutoOnboarding ...bool) (*User, error) { u, err := uc.userRepo.FindByEmail(ctx, email) if err != nil { return nil, err @@ -113,13 +107,16 @@ func (uc *UserUseCase) FindOrCreateByEmail(ctx context.Context, email string) (* return u, nil } - u, err = uc.CreateByEmail(ctx, email) + u, err = uc.userRepo.CreateByEmail(ctx, email) if err != nil { return nil, fmt.Errorf("failed to create user: %w", err) } - if err := uc.organizationUseCase.AutoOnboardOrganizations(ctx, u.ID); err != nil { - return nil, fmt.Errorf("failed to auto-onboard user: %w", err) + // Check if we should auto-onboard the user + if disableAutoOnboarding == nil || (len(disableAutoOnboarding) > 0 && !disableAutoOnboarding[0]) { + if err := uc.organizationUseCase.AutoOnboardOrganizations(ctx, u.ID); err != nil { + return nil, fmt.Errorf("failed to auto-onboard user: %w", err) + } } return u, err diff --git a/app/controlplane/pkg/biz/user_integration_test.go b/app/controlplane/pkg/biz/user_integration_test.go index 79aee19ca..bbdc664f1 100644 --- a/app/controlplane/pkg/biz/user_integration_test.go +++ b/app/controlplane/pkg/biz/user_integration_test.go @@ -19,7 +19,9 @@ import ( "context" "testing" + v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" "github.com/chainloop-dev/chainloop/app/controlplane/internal/authz" + conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/testhelpers" @@ -118,6 +120,43 @@ func (s *userIntegrationTestSuite) TestCurrentMembership() { // Run the tests func TestUserUseCase(t *testing.T) { suite.Run(t, new(userIntegrationTestSuite)) + suite.Run(t, new(userOnboardingTestSuite)) +} + +type userOnboardingTestSuite struct { + testhelpers.UseCasesEachTestSuite +} + +func (s *userOnboardingTestSuite) TestAutoOnboardOrganizationsNoConfiguration() { + ctx := context.Background() + // Create a user with no orgs + user, err := s.User.FindOrCreateByEmail(ctx, "foo@bar.com", true) + s.NoError(err) + s.NotNil(user) +} + +func (s *userOnboardingTestSuite) TestAutoOnboardOrganizationsWithConfiguration() { + ctx := context.Background() + // Create a user with no orgs + + s.TestingUseCases = testhelpers.NewTestingUseCases(s.T(), testhelpers.WithOnboardingConfiguration([]*conf.OnboardingSpec{ + { + Name: "testing-org", + Role: v1.MembershipRole_MEMBERSHIP_ROLE_ORG_VIEWER, + }, + })) + + org, err := s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.Nil(err) + s.Nil(org) + + user, err := s.User.FindOrCreateByEmail(ctx, "foo@bar.com") + s.NoError(err) + s.NotNil(user) + + org, err = s.Repos.OrganizationRepo.FindByName(ctx, "testing-org") + s.NoError(err) + s.NotNil(org) } // Utility struct to hold the test suite