From 6fa4c0d330315ff635d9806bfabc97d85a6d5549 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sat, 26 Jul 2025 23:29:05 +0100 Subject: [PATCH 1/9] feat: option to restrict org creation Signed-off-by: Miguel Martinez --- .../api/controlplane/v1/status.pb.go | 69 ++-- .../api/controlplane/v1/status.proto | 4 +- .../api/controlplane/v1/status_grpc.pb.go | 2 +- .../gen/frontend/controlplane/v1/status.ts | 17 +- .../frontend/google/protobuf/descriptor.ts | 16 +- ...trolplane.v1.InfozResponse.jsonschema.json | 8 + .../controlplane.v1.InfozResponse.schema.json | 8 + app/controlplane/cmd/wire.go | 4 +- app/controlplane/cmd/wire_gen.go | 7 +- app/controlplane/configs/config.devel.yaml | 3 + .../conf/controlplane/config/v1/conf.pb.go | 390 +++++++++--------- .../conf/controlplane/config/v1/conf.proto | 3 + app/controlplane/internal/server/grpc.go | 5 +- app/controlplane/internal/server/http.go | 2 +- .../internal/service/organization.go | 31 ++ app/controlplane/internal/service/status.go | 15 +- app/controlplane/pkg/authz/authz.go | 8 + app/controlplane/pkg/authz/enforcer.go | 10 +- 18 files changed, 358 insertions(+), 244 deletions(-) diff --git a/app/controlplane/api/controlplane/v1/status.pb.go b/app/controlplane/api/controlplane/v1/status.pb.go index 63104858b..f3be472c6 100644 --- a/app/controlplane/api/controlplane/v1/status.pb.go +++ b/app/controlplane/api/controlplane/v1/status.pb.go @@ -1,5 +1,5 @@ // -// Copyright 2023 The Chainloop Authors. +// Copyright 2023-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -133,6 +133,8 @@ type InfozResponse struct { Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` // Version of the helm chart used during deployment ChartVersion string `protobuf:"bytes,3,opt,name=chart_version,json=chartVersion,proto3" json:"chart_version,omitempty"` + // Whether organization creation is restricted to admins + RestrictedOrgCreation bool `protobuf:"varint,4,opt,name=restricted_org_creation,json=restrictedOrgCreation,proto3" json:"restricted_org_creation,omitempty"` } func (x *InfozResponse) Reset() { @@ -188,6 +190,13 @@ func (x *InfozResponse) GetChartVersion() string { return "" } +func (x *InfozResponse) GetRestrictedOrgCreation() bool { + if x != nil { + return x.RestrictedOrgCreation + } + return false +} + type StatuszResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -237,33 +246,37 @@ var file_controlplane_v1_status_proto_rawDesc = []byte{ 0x0c, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2e, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x22, 0x6b, 0x0a, - 0x0d, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, - 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, - 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc7, 0x01, - 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x56, 0x0a, 0x05, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x7a, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, - 0x06, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x7a, 0x12, 0x5e, 0x0a, 0x07, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x7a, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, - 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, - 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, - 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x22, 0xa3, 0x01, + 0x0a, 0x0d, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x52, 0x4c, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, + 0x68, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x17, 0x72, + 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x72, 0x67, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x72, 0x65, + 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x4f, 0x72, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc7, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x05, 0x49, 0x6e, 0x66, 0x6f, + 0x7a, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x7a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x7a, + 0x12, 0x5e, 0x0a, 0x07, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x12, 0x1f, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x7a, + 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/controlplane/api/controlplane/v1/status.proto b/app/controlplane/api/controlplane/v1/status.proto index 16d9e4728..af2da742a 100644 --- a/app/controlplane/api/controlplane/v1/status.proto +++ b/app/controlplane/api/controlplane/v1/status.proto @@ -1,5 +1,5 @@ // -// Copyright 2023 The Chainloop Authors. +// Copyright 2023-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -44,6 +44,8 @@ message InfozResponse { string version = 2; // Version of the helm chart used during deployment string chart_version = 3; + // Whether organization creation is restricted to admins + bool restricted_org_creation = 4; } message StatuszResponse {} diff --git a/app/controlplane/api/controlplane/v1/status_grpc.pb.go b/app/controlplane/api/controlplane/v1/status_grpc.pb.go index 2adbc9649..cfbcc4187 100644 --- a/app/controlplane/api/controlplane/v1/status_grpc.pb.go +++ b/app/controlplane/api/controlplane/v1/status_grpc.pb.go @@ -1,5 +1,5 @@ // -// Copyright 2023 The Chainloop Authors. +// Copyright 2023-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/status.ts b/app/controlplane/api/gen/frontend/controlplane/v1/status.ts index afecc983f..e448571a5 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/status.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/status.ts @@ -22,6 +22,8 @@ export interface InfozResponse { version: string; /** Version of the helm chart used during deployment */ chartVersion: string; + /** Whether organization creation is restricted to admins */ + restrictedOrgCreation: boolean; } export interface StatuszResponse { @@ -128,7 +130,7 @@ export const StatuszRequest = { }; function createBaseInfozResponse(): InfozResponse { - return { loginUrl: "", version: "", chartVersion: "" }; + return { loginUrl: "", version: "", chartVersion: "", restrictedOrgCreation: false }; } export const InfozResponse = { @@ -142,6 +144,9 @@ export const InfozResponse = { if (message.chartVersion !== "") { writer.uint32(26).string(message.chartVersion); } + if (message.restrictedOrgCreation === true) { + writer.uint32(32).bool(message.restrictedOrgCreation); + } return writer; }, @@ -173,6 +178,13 @@ export const InfozResponse = { message.chartVersion = reader.string(); continue; + case 4: + if (tag !== 32) { + break; + } + + message.restrictedOrgCreation = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -187,6 +199,7 @@ export const InfozResponse = { loginUrl: isSet(object.loginURL) ? String(object.loginURL) : "", version: isSet(object.version) ? String(object.version) : "", chartVersion: isSet(object.chartVersion) ? String(object.chartVersion) : "", + restrictedOrgCreation: isSet(object.restrictedOrgCreation) ? Boolean(object.restrictedOrgCreation) : false, }; }, @@ -195,6 +208,7 @@ export const InfozResponse = { message.loginUrl !== undefined && (obj.loginURL = message.loginUrl); message.version !== undefined && (obj.version = message.version); message.chartVersion !== undefined && (obj.chartVersion = message.chartVersion); + message.restrictedOrgCreation !== undefined && (obj.restrictedOrgCreation = message.restrictedOrgCreation); return obj; }, @@ -207,6 +221,7 @@ export const InfozResponse = { message.loginUrl = object.loginUrl ?? ""; message.version = object.version ?? ""; message.chartVersion = object.chartVersion ?? ""; + message.restrictedOrgCreation = object.restrictedOrgCreation ?? false; return message; }, }; diff --git a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts index d59b21da4..0d2d2fb32 100644 --- a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts +++ b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts @@ -30,7 +30,7 @@ export enum Edition { EDITION_2024 = 1001, /** * EDITION_1_TEST_ONLY - Placeholder editions for testing feature resolution. These should not be - * used or relied on outside of tests. + * used or relyed on outside of tests. */ EDITION_1_TEST_ONLY = 1, EDITION_2_TEST_ONLY = 2, @@ -875,13 +875,12 @@ export interface MessageOptions { export interface FieldOptions { /** - * NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. * The ctype option instructs the C++ code generator to use a different * representation of the field than it normally would. See the specific * options below. This option is only implemented to support use of * [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - * type "bytes" in the open source release. - * TODO: make ctype actually deprecated. + * type "bytes" in the open source release -- sorry, we'll try to include + * other types in a future version! */ ctype: FieldOptions_CType; /** @@ -1053,7 +1052,11 @@ export function fieldOptions_JSTypeToJSON(object: FieldOptions_JSType): string { } } -/** If set to RETENTION_SOURCE, the option will be omitted from the binary. */ +/** + * If set to RETENTION_SOURCE, the option will be omitted from the binary. + * Note: as of January 2023, support for this is in progress and does not yet + * have an effect (b/264593489). + */ export enum FieldOptions_OptionRetention { RETENTION_UNKNOWN = 0, RETENTION_RUNTIME = 1, @@ -1096,7 +1099,8 @@ export function fieldOptions_OptionRetentionToJSON(object: FieldOptions_OptionRe /** * This indicates the types of entities that the field may apply to when used * as an option. If it is unset, then the field may be freely used as an - * option on any kind of entity. + * option on any kind of entity. Note: as of January 2023, support for this is + * in progress and does not yet have an effect (b/264593489). */ export enum FieldOptions_OptionTargetType { TARGET_TYPE_UNKNOWN = 0, diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.jsonschema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.jsonschema.json index 46ec5f6df..3df08f5cd 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.jsonschema.json @@ -9,6 +9,10 @@ }, "^(login_url)$": { "type": "string" + }, + "^(restricted_org_creation)$": { + "description": "Whether organization creation is restricted to admins", + "type": "boolean" } }, "properties": { @@ -19,6 +23,10 @@ "loginURL": { "type": "string" }, + "restrictedOrgCreation": { + "description": "Whether organization creation is restricted to admins", + "type": "boolean" + }, "version": { "type": "string" } diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.schema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.schema.json index 713b4b8c9..3423ead2c 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.InfozResponse.schema.json @@ -9,6 +9,10 @@ }, "^(loginURL)$": { "type": "string" + }, + "^(restrictedOrgCreation)$": { + "description": "Whether organization creation is restricted to admins", + "type": "boolean" } }, "properties": { @@ -19,6 +23,10 @@ "login_url": { "type": "string" }, + "restricted_org_creation": { + "description": "Whether organization creation is restricted to admins", + "type": "boolean" + }, "version": { "type": "string" } diff --git a/app/controlplane/cmd/wire.go b/app/controlplane/cmd/wire.go index 9c03ecb53..a18982312 100644 --- a/app/controlplane/cmd/wire.go +++ b/app/controlplane/cmd/wire.go @@ -69,8 +69,8 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.Availabl ) } -func authzConfig() *authz.Config { - return &authz.Config{ManagedResources: authz.ManagedResources, RolesMap: authz.RolesMap} +func authzConfig(conf *conf.Bootstrap) *authz.Config { + return &authz.Config{ManagedResources: authz.ManagedResources, RolesMap: authz.RolesMap, RestrictOrgCreation: conf.RestrictOrgCreation} } func newJWTConfig(conf *conf.Auth) *biz.APITokenJWTConfig { diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index 4f1f324e4..6c13dc68f 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -107,7 +107,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l } apiTokenRepo := data.NewAPITokenRepo(dataData, logger) apiTokenJWTConfig := newJWTConfig(auth) - config := authzConfig() + config := authzConfig(bootstrap) enforcer, err := authz.NewDatabaseEnforcer(databaseConfig, config) if err != nil { cleanup() @@ -275,6 +275,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l ServerConfig: confServer, AuthConfig: auth, FederatedConfig: federatedAuthentication, + BootstrapConfig: bootstrap, Credentials: readerWriter, Enforcer: enforcer, Validator: validator, @@ -313,8 +314,8 @@ var ( // wire.go: -func authzConfig() *authz.Config { - return &authz.Config{ManagedResources: authz.ManagedResources, RolesMap: authz.RolesMap} +func authzConfig(conf2 *conf.Bootstrap) *authz.Config { + return &authz.Config{ManagedResources: authz.ManagedResources, RolesMap: authz.RolesMap, RestrictOrgCreation: conf2.RestrictOrgCreation} } func newJWTConfig(conf2 *conf.Auth) *biz.APITokenJWTConfig { diff --git a/app/controlplane/configs/config.devel.yaml b/app/controlplane/configs/config.devel.yaml index a6ed90ff4..92012a6bb 100644 --- a/app/controlplane/configs/config.devel.yaml +++ b/app/controlplane/configs/config.devel.yaml @@ -19,6 +19,9 @@ server: # nats_server: # uri: nats://0.0.0.0:4222 +# Restrict organization creation to role:instance:admin +restrict_org_creation: false + certificate_authorities: - issuer: true file_ca: 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 25abacc35..5dc44047b 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go @@ -78,6 +78,8 @@ type Bootstrap struct { // to a third party service for verification // For example, we can forward Gitlab or Github API tokens FederatedAuthentication *FederatedAuthentication `protobuf:"bytes,16,opt,name=federated_authentication,json=federatedAuthentication,proto3" json:"federated_authentication,omitempty"` + // Restrict organization creation to admins + RestrictOrgCreation bool `protobuf:"varint,18,opt,name=restrict_org_creation,json=restrictOrgCreation,proto3" json:"restrict_org_creation,omitempty"` } func (x *Bootstrap) Reset() { @@ -232,6 +234,13 @@ func (x *Bootstrap) GetFederatedAuthentication() *FederatedAuthentication { return nil } +func (x *Bootstrap) GetRestrictOrgCreation() bool { + if x != nil { + return x.RestrictOrgCreation + } + return false +} + type FederatedAuthentication struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1613,7 +1622,7 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x72, 0x65, 0x64, 0x65, 0x6e, 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, 0xbe, 0x0d, 0x0a, 0x09, 0x42, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf2, 0x0d, 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, @@ -1693,198 +1702,201 @@ var file_controlplane_config_v1_conf_proto_rawDesc = []byte{ 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x17, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, + 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5f, 0x6f, 0x72, 0x67, 0x5f, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x72, 0x65, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 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, 0xc0, 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, 0x12, 0x33, + 0x0a, 0x16, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, + 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x53, + 0x69, 0x7a, 0x65, 0x1a, 0x5a, 0x0a, 0x0a, 0x4e, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x12, 0x19, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, + 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1f, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x10, 0x0a, + 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x4f, 0x0a, 0x17, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x03, 0x75, 0x72, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, + 0x01, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x22, 0xee, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, + 0x65, 0x2e, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, + 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, + 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, + 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, + 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, + 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 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, 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, 0xc0, 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, 0x12, 0x33, 0x0a, 0x16, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x5f, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x1a, - 0x5a, 0x0a, 0x0a, 0x4e, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x19, 0x0a, - 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, - 0x02, 0x10, 0x01, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1f, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, - 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4f, 0x0a, 0x17, 0x46, - 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x03, 0x75, - 0x72, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xee, 0x01, 0x0a, - 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, - 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x82, - 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x64, 0x6e, - 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, - 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, - 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, - 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, 0x2d, - 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, - 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, - 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 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, + 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, 0x54, 0x4c, 0x53, 0x52, 0x09, 0x74, 0x6c, - 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9a, 0x02, 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, 0xce, 0x01, 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, - 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, - 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x4f, 0x70, 0x65, - 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x6f, 0x70, - 0x65, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, - 0x6d, 0x61, 0x78, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x73, 0x12, 0x46, 0x0a, 0x12, - 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 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, 0x0f, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x64, 0x6c, 0x65, - 0x54, 0x69, 0x6d, 0x65, 0x22, 0xb1, 0x03, 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, 0x40, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, + 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, 0x9a, 0x02, 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, 0xce, 0x01, 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, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, + 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x69, + 0x6e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, + 0x78, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x73, + 0x12, 0x46, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x69, 0x64, 0x6c, + 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 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, 0x0f, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, + 0x49, 0x64, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xb1, 0x03, 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, 0x40, 0x0a, 0x0a, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 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, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, + 0x69, 0x73, 0x74, 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, + 0x12, 0x19, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x55, 0x73, 0x65, 0x72, 0x1a, 0x8e, 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, 0x2c, + 0x0a, 0x12, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x6f, 0x76, 0x65, 0x72, + 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x6f, 0x67, 0x69, + 0x6e, 0x55, 0x72, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0x57, 0x0a, 0x03, + 0x54, 0x53, 0x41, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x63, 0x65, 0x72, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, + 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x22, 0xe4, 0x04, 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, 0x12, 0x3d, 0x0a, 0x08, 0x65, 0x6a, + 0x62, 0x63, 0x61, 0x5f, 0x63, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 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, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 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, 0x12, 0x19, 0x0a, 0x08, - 0x64, 0x65, 0x76, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x64, 0x65, 0x76, 0x55, 0x73, 0x65, 0x72, 0x1a, 0x8e, 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, 0x2c, 0x0a, 0x12, 0x6c, 0x6f, - 0x67, 0x69, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x72, 0x6c, - 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0x57, 0x0a, 0x03, 0x54, 0x53, 0x41, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, - 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, + 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x2e, 0x45, 0x4a, 0x42, 0x43, 0x41, 0x48, 0x00, + 0x52, 0x07, 0x65, 0x6a, 0x62, 0x63, 0x61, 0x43, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x72, 0x22, 0xe4, 0x04, 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, 0x12, 0x3d, 0x0a, 0x08, 0x65, 0x6a, 0x62, 0x63, 0x61, 0x5f, - 0x63, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 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, 0x45, 0x4a, 0x42, 0x43, 0x41, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6a, - 0x62, 0x63, 0x61, 0x43, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 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, 0x1a, 0xe5, 0x02, 0x0a, 0x05, 0x45, - 0x4a, 0x42, 0x43, 0x41, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, - 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, - 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x22, 0x0a, 0x08, - 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, - 0x12, 0x24, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x63, 0x65, - 0x72, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, - 0x61, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, - 0x6f, 0x74, 0x43, 0x61, 0x50, 0x61, 0x74, 0x68, 0x12, 0x41, 0x0a, 0x18, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, - 0x02, 0x10, 0x01, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x17, 0x65, - 0x6e, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, - 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x14, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x1a, 0x63, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x18, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x4e, 0x61, - 0x6d, 0x65, 0x42, 0x04, 0x0a, 0x02, 0x63, 0x61, 0x22, 0x3f, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x6d, - 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x22, 0x0a, 0x08, 0x6f, 0x72, 0x67, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, - 0x52, 0x07, 0x6f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 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, + 0x72, 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, 0x1a, 0xe5, + 0x02, 0x0a, 0x05, 0x45, 0x4a, 0x42, 0x43, 0x41, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, + 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, + 0x12, 0x22, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x07, 0x6b, 0x65, 0x79, + 0x50, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, + 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x6f, + 0x6f, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x61, 0x50, 0x61, 0x74, 0x68, 0x12, 0x41, 0x0a, 0x18, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, + 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x3e, 0x0a, 0x17, 0x65, 0x6e, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x14, 0x65, 0x6e, 0x64, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x45, 0x0a, 0x1a, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x18, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x04, 0x0a, 0x02, 0x63, 0x61, 0x22, 0x3f, 0x0a, 0x19, + 0x50, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x22, 0x0a, 0x08, 0x6f, 0x72, 0x67, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x07, 0x6f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 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 8d1c711cc..254cdd15d 100644 --- a/app/controlplane/internal/conf/controlplane/config/v1/conf.proto +++ b/app/controlplane/internal/conf/controlplane/config/v1/conf.proto @@ -91,6 +91,9 @@ message Bootstrap { // For example, we can forward Gitlab or Github API tokens FederatedAuthentication federated_authentication = 16; + // Restrict organization creation to admins + bool restrict_org_creation = 18; + message NatsServer { // Connection URI string uri = 1 [(buf.validate.field).string.min_len = 1]; diff --git a/app/controlplane/internal/server/grpc.go b/app/controlplane/internal/server/grpc.go index 4a18ba866..6197c9de6 100644 --- a/app/controlplane/internal/server/grpc.go +++ b/app/controlplane/internal/server/grpc.go @@ -89,6 +89,7 @@ type Opts struct { ServerConfig *conf.Server AuthConfig *conf.Auth FederatedConfig *conf.FederatedAuthentication + BootstrapConfig *conf.Bootstrap Credentials credentials.ReaderWriter Enforcer *authz.Enforcer Validator *protovalidate.Validator @@ -134,7 +135,7 @@ func NewGRPCServer(opts *Opts) (*grpc.Server, error) { srv := grpc.NewServer(serverOpts...) v1.RegisterWorkflowServiceServer(srv, opts.WorkflowSvc) - v1.RegisterStatusServiceServer(srv, service.NewStatusService(opts.AuthSvc.AuthURLs.Login, Version, opts.CASClientUseCase)) + v1.RegisterStatusServiceServer(srv, service.NewStatusService(opts.AuthSvc.AuthURLs.Login, Version, opts.CASClientUseCase, opts.BootstrapConfig)) v1.RegisterRobotAccountServiceServer(srv, opts.RobotAccountSvc) v1.RegisterWorkflowRunServiceServer(srv, opts.WorkflowRunSvc) v1.RegisterAttestationServiceServer(srv, opts.AttestationSvc) @@ -282,7 +283,7 @@ func requireRobotAccountMatcher() selector.MatchFunc { // Matches all operations that require to have a current organization func requireAllButOrganizationOperationsMatcher() selector.MatchFunc { - const skipRegexp = "/controlplane.v1.OrganizationService/Create|/controlplane.v1.UserService/ListMemberships|/controlplane.v1.ContextService/Current|/controlplane.v1.AuthService/DeleteAccount" + const skipRegexp = "/controlplane.v1.UserService/ListMemberships|/controlplane.v1.ContextService/Current|/controlplane.v1.AuthService/DeleteAccount" return func(ctx context.Context, operation string) bool { r := regexp.MustCompile(skipRegexp) return !r.MatchString(operation) diff --git a/app/controlplane/internal/server/http.go b/app/controlplane/internal/server/http.go index b0aab047c..e4191c258 100644 --- a/app/controlplane/internal/server/http.go +++ b/app/controlplane/internal/server/http.go @@ -72,7 +72,7 @@ func NewHTTPServer(opts *Opts, grpcSrv *grpc.Server) (*http.Server, error) { opts.PrometheusSvc, ), )) - v1.RegisterStatusServiceHTTPServer(httpSrv, service.NewStatusService(opts.AuthSvc.AuthURLs.Login, Version, opts.CASClientUseCase)) + v1.RegisterStatusServiceHTTPServer(httpSrv, service.NewStatusService(opts.AuthSvc.AuthURLs.Login, Version, opts.CASClientUseCase, opts.BootstrapConfig)) v1.RegisterReferrerServiceHTTPServer(httpSrv, service.NewReferrerService(opts.ReferrerUseCase)) // Wrap http server to handle grpc-web calls and we will return this new server diff --git a/app/controlplane/internal/service/organization.go b/app/controlplane/internal/service/organization.go index 954005181..bef24f1aa 100644 --- a/app/controlplane/internal/service/organization.go +++ b/app/controlplane/internal/service/organization.go @@ -19,8 +19,10 @@ import ( "context" pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/entities" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/authz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" + errors "github.com/go-kratos/kratos/v2/errors" "github.com/google/uuid" ) @@ -48,6 +50,15 @@ func (s *OrganizationService) Create(ctx context.Context, req *pb.OrganizationSe return nil, err } + canCreate, err := s.canCreateOrganization(ctx) + if err != nil { + return nil, err + } + + if !canCreate { + return nil, errors.Forbidden("forbidden", "creation of organizations is restricted to instance admins") + } + // Create an organization with an associated inline CAS backend org, err := s.orgUC.Create(ctx, req.Name, biz.WithCreateInlineBackend()) if err != nil { @@ -158,3 +169,23 @@ func (s *OrganizationService) UpdateMembership(ctx context.Context, req *pb.Orga return &pb.OrganizationServiceUpdateMembershipResponse{Result: bizMembershipToPb(m)}, nil } + +func (s *OrganizationService) canCreateOrganization(ctx context.Context) (bool, error) { + // Restricted org creation is disabled, allow creation + if !s.enforcer.RestrictOrgCreation { + return true, nil + } + + m := entities.CurrentMembership(ctx) + for _, rm := range m.Resources { + pass, err := s.enforcer.Enforce(string(rm.Role), authz.PolicyOrganizationCreate) + if err != nil { + return false, handleUseCaseErr(err, s.log) + } + if pass { + return true, nil + } + } + + return false, nil +} diff --git a/app/controlplane/internal/service/status.go b/app/controlplane/internal/service/status.go index 9565287f8..98e473579 100644 --- a/app/controlplane/internal/service/status.go +++ b/app/controlplane/internal/service/status.go @@ -1,5 +1,5 @@ // -// Copyright 2023 The Chainloop Authors. +// Copyright 2023-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import ( "os" pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" + conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/go-kratos/kratos/v2/errors" ) @@ -28,10 +29,11 @@ type StatusService struct { loginURL, version string pb.UnimplementedStatusServiceServer casClient *biz.CASClientUseCase + bootstrap *conf.Bootstrap } -func NewStatusService(logingURL, version string, casClient *biz.CASClientUseCase) *StatusService { - return &StatusService{loginURL: logingURL, version: version, casClient: casClient} +func NewStatusService(logingURL, version string, casClient *biz.CASClientUseCase, bootstrap *conf.Bootstrap) *StatusService { + return &StatusService{loginURL: logingURL, version: version, casClient: casClient, bootstrap: bootstrap} } // Only on readiness probes we check this service external dependencies @@ -46,8 +48,9 @@ func (s *StatusService) Statusz(ctx context.Context, r *pb.StatuszRequest) (*pb. func (s *StatusService) Infoz(_ context.Context, _ *pb.InfozRequest) (*pb.InfozResponse, error) { return &pb.InfozResponse{ - LoginUrl: s.loginURL, - Version: s.version, - ChartVersion: os.Getenv("CHART_VERSION"), + LoginUrl: s.loginURL, + Version: s.version, + ChartVersion: os.Getenv("CHART_VERSION"), + RestrictedOrgCreation: s.bootstrap.RestrictOrgCreation, }, nil } diff --git a/app/controlplane/pkg/authz/authz.go b/app/controlplane/pkg/authz/authz.go index d9cee0b0e..f5ac8ed81 100644 --- a/app/controlplane/pkg/authz/authz.go +++ b/app/controlplane/pkg/authz/authz.go @@ -65,6 +65,9 @@ const ( ResourceOrganizationInvitations = "organization_invitations" ResourceGroupProjects = "group_projects" + // Top level instance admin role + // this is used to know if an user is a super admin of the chainloop instance + RoleInstanceAdmin Role = "role:instance:admin" // We have for now three roles, viewer, admin and owner // The owner of an org // The administrator of an org @@ -164,6 +167,7 @@ var ( // Projects PolicyProjectCreate = &Policy{ResourceProject, ActionCreate} + PolicyOrganizationCreate = &Policy{Organization, ActionCreate} // User Membership PolicyOrganizationRead = &Policy{Organization, ActionRead} PolicyOrganizationListMemberships = &Policy{OrganizationMemberships, ActionList} @@ -192,6 +196,10 @@ var ( // NOTE: roles are not necessarily hierarchical, however the Admin Role inherits all the policies from the Viewer Role // so we do not need to add them as well. var RolesMap = map[Role][]*Policy{ + // Organizations in chainloop might be restricted to instance admins + RoleInstanceAdmin: { + PolicyOrganizationCreate, + }, // RoleViewer is an org-scoped role that provides read-only access to all resources RoleViewer: { // Referrer diff --git a/app/controlplane/pkg/authz/enforcer.go b/app/controlplane/pkg/authz/enforcer.go index ddc5a8fee..109cccdd6 100644 --- a/app/controlplane/pkg/authz/enforcer.go +++ b/app/controlplane/pkg/authz/enforcer.go @@ -43,14 +43,16 @@ func (t *SubjectAPIToken) String() string { var modelFile []byte type Config struct { - ManagedResources []string - RolesMap map[Role][]*Policy + ManagedResources []string + RolesMap map[Role][]*Policy + RestrictOrgCreation bool } type Enforcer struct { *casbin.Enforcer - config *Config + config *Config + RestrictOrgCreation bool } func (e *Enforcer) AddPolicies(sub *SubjectAPIToken, policies ...*Policy) error { @@ -161,7 +163,7 @@ func newEnforcer(a persist.Adapter, config *Config) (*Enforcer, error) { return nil, fmt.Errorf("failed to create enforcer: %w", err) } - e := &Enforcer{enforcer, config} + e := &Enforcer{enforcer, config, config.RestrictOrgCreation} // Initialize the enforcer with the roles map if err := syncRBACRoles(e, config); err != nil { From d20a23bc0e59845b85e153d0e959b7aae2eca3f9 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sat, 26 Jul 2025 23:38:45 +0100 Subject: [PATCH 2/9] chore: update helm chart Signed-off-by: Miguel Martinez --- deployment/chainloop/templates/controlplane/configmap.yaml | 1 + deployment/chainloop/values.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/deployment/chainloop/templates/controlplane/configmap.yaml b/deployment/chainloop/templates/controlplane/configmap.yaml index f6ee1339d..e974809c3 100644 --- a/deployment/chainloop/templates/controlplane/configmap.yaml +++ b/deployment/chainloop/templates/controlplane/configmap.yaml @@ -45,6 +45,7 @@ data: default_entry_max_size: {{ .Values.cas.defaultMaxEntrySize | quote }} {{- end }} plugins_dir: {{ .Values.controlplane.pluginsDir }} + restrict_org_creation: {{ .Values.controlplane.restrictOrgCreation }} referrer_shared_index: {{- toYaml .Values.controlplane.referrerSharedIndex | nindent 6 }} {{ if .Values.controlplane.onboarding }} diff --git a/deployment/chainloop/values.yaml b/deployment/chainloop/values.yaml index 19a83e09a..ab608ea04 100644 --- a/deployment/chainloop/values.yaml +++ b/deployment/chainloop/values.yaml @@ -177,6 +177,9 @@ controlplane: enabled: false url: "" + ## @skip controlplane.restrictOrgCreation Restrict organization creation to instance admins + restrictOrgCreation: false + ## @extra controlplane.nats optional NATS configuration for events publishing. ## @param controlplane.nats.enabled Enable events publishing through a Nats stream ## @param controlplane.nats.host NATS Host From bfbd60464b91fa0808a9aee7a7b95f6f72c6d55e Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sun, 27 Jul 2025 00:05:53 +0100 Subject: [PATCH 3/9] chore: update helm chart Signed-off-by: Miguel Martinez --- app/controlplane/internal/server/grpc_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controlplane/internal/server/grpc_test.go b/app/controlplane/internal/server/grpc_test.go index f6629e709..163e30c38 100644 --- a/app/controlplane/internal/server/grpc_test.go +++ b/app/controlplane/internal/server/grpc_test.go @@ -88,7 +88,7 @@ func TestRequireAllButOrganizationOperationsMatcher(t *testing.T) { }{ {"/controlplane.v1.WorkflowService/List", true}, {"/controlplane.v1.WorkflowRunService/List", true}, - {"/controlplane.v1.OrganizationService/Create", false}, + {"/controlplane.v1.OrganizationService/Create", true}, {"/controlplane.v1.CASBackendService/List", true}, {"/controlplane.v1.CASBackendService/Add", true}, } From af797b700ff67631577f127135ef0812cc137903 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sun, 27 Jul 2025 20:04:20 +0100 Subject: [PATCH 4/9] chore: update helm chart Signed-off-by: Miguel Martinez --- .../gen/frontend/google/protobuf/descriptor.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts index 0d2d2fb32..d59b21da4 100644 --- a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts +++ b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts @@ -30,7 +30,7 @@ export enum Edition { EDITION_2024 = 1001, /** * EDITION_1_TEST_ONLY - Placeholder editions for testing feature resolution. These should not be - * used or relyed on outside of tests. + * used or relied on outside of tests. */ EDITION_1_TEST_ONLY = 1, EDITION_2_TEST_ONLY = 2, @@ -875,12 +875,13 @@ export interface MessageOptions { export interface FieldOptions { /** + * NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. * The ctype option instructs the C++ code generator to use a different * representation of the field than it normally would. See the specific * options below. This option is only implemented to support use of * [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - * type "bytes" in the open source release -- sorry, we'll try to include - * other types in a future version! + * type "bytes" in the open source release. + * TODO: make ctype actually deprecated. */ ctype: FieldOptions_CType; /** @@ -1052,11 +1053,7 @@ export function fieldOptions_JSTypeToJSON(object: FieldOptions_JSType): string { } } -/** - * If set to RETENTION_SOURCE, the option will be omitted from the binary. - * Note: as of January 2023, support for this is in progress and does not yet - * have an effect (b/264593489). - */ +/** If set to RETENTION_SOURCE, the option will be omitted from the binary. */ export enum FieldOptions_OptionRetention { RETENTION_UNKNOWN = 0, RETENTION_RUNTIME = 1, @@ -1099,8 +1096,7 @@ export function fieldOptions_OptionRetentionToJSON(object: FieldOptions_OptionRe /** * This indicates the types of entities that the field may apply to when used * as an option. If it is unset, then the field may be freely used as an - * option on any kind of entity. Note: as of January 2023, support for this is - * in progress and does not yet have an effect (b/264593489). + * option on any kind of entity. */ export enum FieldOptions_OptionTargetType { TARGET_TYPE_UNKNOWN = 0, From 455a07fc05fe236401978cb24d3e1a028079a3c1 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sun, 27 Jul 2025 23:56:58 +0100 Subject: [PATCH 5/9] add value for ent Signed-off-by: Miguel Martinez --- app/controlplane/pkg/authz/authz.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controlplane/pkg/authz/authz.go b/app/controlplane/pkg/authz/authz.go index f5ac8ed81..f9f2dd29e 100644 --- a/app/controlplane/pkg/authz/authz.go +++ b/app/controlplane/pkg/authz/authz.go @@ -446,6 +446,8 @@ var ServerOperationsMap = map[string][]*Policy{ // so they can be added to the database schema func (Role) Values() (roles []string) { for _, s := range []Role{ + RoleInstanceAdmin, + RoleOwner, RoleAdmin, RoleViewer, From e8fe8c27f718bd1aeda98519f994d33787648e4f Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Mon, 28 Jul 2025 00:01:00 +0100 Subject: [PATCH 6/9] add value for ent Signed-off-by: Miguel Martinez --- app/controlplane/pkg/data/ent/membership/membership.go | 2 +- app/controlplane/pkg/data/ent/migrate/schema.go | 4 ++-- app/controlplane/pkg/data/ent/orginvitation/orginvitation.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controlplane/pkg/data/ent/membership/membership.go b/app/controlplane/pkg/data/ent/membership/membership.go index c29b70c97..6316942d7 100644 --- a/app/controlplane/pkg/data/ent/membership/membership.go +++ b/app/controlplane/pkg/data/ent/membership/membership.go @@ -119,7 +119,7 @@ var ( // RoleValidator is a validator for the "role" field enum values. It is called by the builders before save. func RoleValidator(r authz.Role) error { switch r { - case "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer": + case "role:instance:admin", "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer": return nil default: return fmt.Errorf("membership: invalid enum value for role field: %q", r) diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 88c973dbf..e8d11f640 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -320,7 +320,7 @@ var ( {Name: "current", Type: field.TypeBool, Default: false}, {Name: "created_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, {Name: "updated_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, - {Name: "role", Type: field.TypeEnum, Enums: []string{"role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer"}}, + {Name: "role", Type: field.TypeEnum, Enums: []string{"role:instance:admin", "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer"}}, {Name: "membership_type", Type: field.TypeEnum, Nullable: true, Enums: []string{"user", "group"}}, {Name: "member_id", Type: field.TypeUUID, Nullable: true}, {Name: "resource_type", Type: field.TypeEnum, Nullable: true, Enums: []string{"organization", "project", "group", "product"}}, @@ -385,7 +385,7 @@ var ( {Name: "status", Type: field.TypeEnum, Enums: []string{"accepted", "pending"}, Default: "pending"}, {Name: "created_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, {Name: "deleted_at", Type: field.TypeTime, Nullable: true}, - {Name: "role", Type: field.TypeEnum, Nullable: true, Enums: []string{"role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer"}}, + {Name: "role", Type: field.TypeEnum, Nullable: true, Enums: []string{"role:instance:admin", "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer"}}, {Name: "context", Type: field.TypeJSON, Nullable: true}, {Name: "organization_id", Type: field.TypeUUID}, {Name: "sender_id", Type: field.TypeUUID}, diff --git a/app/controlplane/pkg/data/ent/orginvitation/orginvitation.go b/app/controlplane/pkg/data/ent/orginvitation/orginvitation.go index 061e5cdf7..4ac60b516 100644 --- a/app/controlplane/pkg/data/ent/orginvitation/orginvitation.go +++ b/app/controlplane/pkg/data/ent/orginvitation/orginvitation.go @@ -101,7 +101,7 @@ func StatusValidator(s biz.OrgInvitationStatus) error { // RoleValidator is a validator for the "role" field enum values. It is called by the builders before save. func RoleValidator(r authz.Role) error { switch r { - case "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer": + case "role:instance:admin", "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer": return nil default: return fmt.Errorf("orginvitation: invalid enum value for role field: %q", r) From 8317a0110812f28cd5cc9bc493cac88ef8ad2885 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Mon, 28 Jul 2025 00:45:42 +0100 Subject: [PATCH 7/9] chore: fix middleware Signed-off-by: Miguel Martinez --- app/controlplane/internal/server/grpc.go | 4 ++- .../currentorganization_middleware.go | 29 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/app/controlplane/internal/server/grpc.go b/app/controlplane/internal/server/grpc.go index 6197c9de6..19dfb7e76 100644 --- a/app/controlplane/internal/server/grpc.go +++ b/app/controlplane/internal/server/grpc.go @@ -200,6 +200,8 @@ func craftMiddleware(opts *Opts) []middleware.Middleware { // 3 - Check user/token authorization authzMiddleware.WithAuthzMiddleware(opts.Enforcer, logHelper), ).Match(requireAllButOrganizationOperationsMatcher()).Build(), + // Store all memberships in the context + usercontext.WithCurrentMembershipsMiddleware(opts.MembershipUseCase), // 4 - Make sure the account is fully functional selector.Server( usercontext.CheckUserHasAccess(opts.AuthConfig.AllowList, opts.UserUseCase), @@ -283,7 +285,7 @@ func requireRobotAccountMatcher() selector.MatchFunc { // Matches all operations that require to have a current organization func requireAllButOrganizationOperationsMatcher() selector.MatchFunc { - const skipRegexp = "/controlplane.v1.UserService/ListMemberships|/controlplane.v1.ContextService/Current|/controlplane.v1.AuthService/DeleteAccount" + const skipRegexp = "/controlplane.v1.OrganizationService/Create|/controlplane.v1.UserService/ListMemberships|/controlplane.v1.ContextService/Current|/controlplane.v1.AuthService/DeleteAccount" return func(ctx context.Context, operation string) bool { r := regexp.MustCompile(skipRegexp) return !r.MatchString(operation) diff --git a/app/controlplane/internal/usercontext/currentorganization_middleware.go b/app/controlplane/internal/usercontext/currentorganization_middleware.go index 1f1f17414..c039a6a39 100644 --- a/app/controlplane/internal/usercontext/currentorganization_middleware.go +++ b/app/controlplane/internal/usercontext/currentorganization_middleware.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -33,6 +33,27 @@ import ( // membershipsCache caches user memberships to save some database queries during intensive sessions var membershipsCache = expirable.NewLRU[string, *entities.Membership](0, nil, time.Second*1) +func WithCurrentMembershipsMiddleware(membershipUC biz.MembershipsRBAC) middleware.Middleware { + return func(handler middleware.Handler) middleware.Handler { + return func(ctx context.Context, req interface{}) (interface{}, error) { + // Get the current user and return if not found, meaning we are probably coming from an API Token + u := entities.CurrentUser(ctx) + if u == nil { + return handler(ctx, req) + } + + var err error + // Let's store all memberships in the context. + ctx, err = setCurrentMembershipsForUser(ctx, u, membershipUC) + if err != nil { + return nil, fmt.Errorf("error setting current org membership: %w", err) + } + + return handler(ctx, req) + } + } +} + func WithCurrentOrganizationMiddleware(userUseCase biz.UserOrgFinder, membershipUC biz.MembershipsRBAC, logger *log.Helper) middleware.Middleware { return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (interface{}, error) { @@ -61,12 +82,6 @@ func WithCurrentOrganizationMiddleware(userUseCase biz.UserOrgFinder, membership } } - // Let's store all memberships in the context. - ctx, err = setCurrentMembershipsForUser(ctx, u, membershipUC) - if err != nil { - return nil, fmt.Errorf("error setting current org membership: %w", err) - } - org := entities.CurrentOrg(ctx) if org == nil { return nil, errors.New("org not found") From d415712d54db0545847da7617f8cc4c888634c4a Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Mon, 28 Jul 2025 01:34:03 +0100 Subject: [PATCH 8/9] feat: support for admins auto-omboarding Signed-off-by: Miguel Martinez --- app/controlplane/configs/config.devel.yaml | 8 ++++---- app/controlplane/internal/server/grpc_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controlplane/configs/config.devel.yaml b/app/controlplane/configs/config.devel.yaml index 92012a6bb..2aedd8f08 100644 --- a/app/controlplane/configs/config.devel.yaml +++ b/app/controlplane/configs/config.devel.yaml @@ -16,11 +16,11 @@ server: # certificate: "../../devel/devkeys/selfsigned/controlplane.crt" # private_key: "../../devel/devkeys/selfsigned/controlplane.key" -# nats_server: -# uri: nats://0.0.0.0:4222 +nats_server: + uri: nats://0.0.0.0:4222 # Restrict organization creation to role:instance:admin -restrict_org_creation: false +restrict_org_creation: true certificate_authorities: - issuer: true @@ -107,4 +107,4 @@ enable_profiler: true # federated_authentication: # enabled: true -# url: http://localhost:8002/machine-identity/verify-token \ No newline at end of file +# url: http://localhost:8002/machine-identity/verify-token diff --git a/app/controlplane/internal/server/grpc_test.go b/app/controlplane/internal/server/grpc_test.go index 163e30c38..f6629e709 100644 --- a/app/controlplane/internal/server/grpc_test.go +++ b/app/controlplane/internal/server/grpc_test.go @@ -88,7 +88,7 @@ func TestRequireAllButOrganizationOperationsMatcher(t *testing.T) { }{ {"/controlplane.v1.WorkflowService/List", true}, {"/controlplane.v1.WorkflowRunService/List", true}, - {"/controlplane.v1.OrganizationService/Create", true}, + {"/controlplane.v1.OrganizationService/Create", false}, {"/controlplane.v1.CASBackendService/List", true}, {"/controlplane.v1.CASBackendService/Add", true}, } From 0780ad5e4c98f9b1dc2278e3b47b9a218e6f8792 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Mon, 28 Jul 2025 17:23:52 +0100 Subject: [PATCH 9/9] fix: add instance type Signed-off-by: Miguel Martinez --- app/controlplane/internal/server/grpc.go | 8 +++++--- app/controlplane/internal/service/organization.go | 4 ++++ .../usercontext/currentorganization_middleware.go | 2 +- .../usercontext/currentorganization_middleware_test.go | 7 ++----- .../internal/usercontext/currentuser_middleware.go | 4 ++-- app/controlplane/pkg/authz/membership.go | 2 ++ app/controlplane/pkg/data/ent/membership/membership.go | 2 +- app/controlplane/pkg/data/ent/migrate/schema.go | 2 +- 8 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/controlplane/internal/server/grpc.go b/app/controlplane/internal/server/grpc.go index 19dfb7e76..4ee63ae5e 100644 --- a/app/controlplane/internal/server/grpc.go +++ b/app/controlplane/internal/server/grpc.go @@ -196,7 +196,7 @@ func craftMiddleware(opts *Opts) []middleware.Middleware { usercontext.WithCurrentUserMiddleware(opts.UserUseCase, logHelper), selector.Server( // 2.d- Set its organization - usercontext.WithCurrentOrganizationMiddleware(opts.UserUseCase, opts.MembershipUseCase, logHelper), + usercontext.WithCurrentOrganizationMiddleware(opts.UserUseCase, logHelper), // 3 - Check user/token authorization authzMiddleware.WithAuthzMiddleware(opts.Enforcer, logHelper), ).Match(requireAllButOrganizationOperationsMatcher()).Build(), @@ -212,7 +212,7 @@ func craftMiddleware(opts *Opts) []middleware.Middleware { ).Match(requireCurrentUserMatcher()).Build(), ) - // attestation robot account authentication + // attestation branch middlewares = append(middlewares, // if we require a robot account selector.Server( @@ -233,7 +233,9 @@ func craftMiddleware(opts *Opts) []middleware.Middleware { // 2.b - Set its API token and Robot Account as alternative to the user usercontext.WithAttestationContextFromAPIToken(opts.APITokenUseCase, opts.OrganizationUseCase, logHelper), // 2.c - Set Attestation context from user token - usercontext.WithAttestationContextFromUser(opts.UserUseCase, opts.MembershipUseCase, logHelper), + usercontext.WithAttestationContextFromUser(opts.UserUseCase, logHelper), + // Store all memberships in the context + usercontext.WithCurrentMembershipsMiddleware(opts.MembershipUseCase), // 2.d - Set its robot account from federated delegation usercontext.WithAttestationContextFromFederatedInfo(opts.OrganizationUseCase, logHelper), // 3 - Update API Token last usage diff --git a/app/controlplane/internal/service/organization.go b/app/controlplane/internal/service/organization.go index bef24f1aa..f048ea985 100644 --- a/app/controlplane/internal/service/organization.go +++ b/app/controlplane/internal/service/organization.go @@ -178,6 +178,10 @@ func (s *OrganizationService) canCreateOrganization(ctx context.Context) (bool, m := entities.CurrentMembership(ctx) for _, rm := range m.Resources { + if rm.ResourceType != authz.ResourceTypeInstance { + continue + } + pass, err := s.enforcer.Enforce(string(rm.Role), authz.PolicyOrganizationCreate) if err != nil { return false, handleUseCaseErr(err, s.log) diff --git a/app/controlplane/internal/usercontext/currentorganization_middleware.go b/app/controlplane/internal/usercontext/currentorganization_middleware.go index c039a6a39..0518766ff 100644 --- a/app/controlplane/internal/usercontext/currentorganization_middleware.go +++ b/app/controlplane/internal/usercontext/currentorganization_middleware.go @@ -54,7 +54,7 @@ func WithCurrentMembershipsMiddleware(membershipUC biz.MembershipsRBAC) middlewa } } -func WithCurrentOrganizationMiddleware(userUseCase biz.UserOrgFinder, membershipUC biz.MembershipsRBAC, logger *log.Helper) middleware.Middleware { +func WithCurrentOrganizationMiddleware(userUseCase biz.UserOrgFinder, logger *log.Helper) middleware.Middleware { return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (interface{}, error) { // Get the current user and return if not found, meaning we are probably coming from an API Token diff --git a/app/controlplane/internal/usercontext/currentorganization_middleware_test.go b/app/controlplane/internal/usercontext/currentorganization_middleware_test.go index 9c2b0bf84..c48a776f4 100644 --- a/app/controlplane/internal/usercontext/currentorganization_middleware_test.go +++ b/app/controlplane/internal/usercontext/currentorganization_middleware_test.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -29,7 +29,6 @@ import ( "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) func TestWithCurrentOrganizationMiddleware(t *testing.T) { @@ -67,7 +66,6 @@ func TestWithCurrentOrganizationMiddleware(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { usecase := bizMocks.NewUserOrgFinder(t) - msMock := bizMocks.NewMembershipsRBAC(t) ctx := context.Background() if tc.loggedIn { ctx = entities.WithCurrentUser(ctx, &entities.User{ID: wantUser.ID}) @@ -76,12 +74,11 @@ func TestWithCurrentOrganizationMiddleware(t *testing.T) { if tc.orgExist { usecase.On("CurrentMembership", ctx, wantUser.ID).Return(wantMembership, nil) - msMock.On("ListAllMembershipsForUser", mock.Anything, mock.Anything).Return([]*biz.Membership{wantMembership}, nil) } else if tc.loggedIn { usecase.On("CurrentMembership", ctx, wantUser.ID).Maybe().Return(nil, nil) } - m := WithCurrentOrganizationMiddleware(usecase, msMock, logger) + m := WithCurrentOrganizationMiddleware(usecase, logger) _, err := m( func(ctx context.Context, _ interface{}) (interface{}, error) { if tc.wantErr { diff --git a/app/controlplane/internal/usercontext/currentuser_middleware.go b/app/controlplane/internal/usercontext/currentuser_middleware.go index f243f0f20..cf1975268 100644 --- a/app/controlplane/internal/usercontext/currentuser_middleware.go +++ b/app/controlplane/internal/usercontext/currentuser_middleware.go @@ -88,7 +88,7 @@ func setCurrentUser(ctx context.Context, userUC biz.UserOrgFinder, userID string // WithAttestationContextFromUser injects the current user + organization to the context during the attestation process // it leverages the existing middlewares to set the current user and organization // but with a skipping behavior since that's the one required by the attMiddleware multi-selector -func WithAttestationContextFromUser(userUC *biz.UserUseCase, membershipUC *biz.MembershipUseCase, logger *log.Helper) middleware.Middleware { +func WithAttestationContextFromUser(userUC *biz.UserUseCase, logger *log.Helper) middleware.Middleware { return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (interface{}, error) { // If the token is not an user token, we don't need to do anything @@ -114,7 +114,7 @@ func WithAttestationContextFromUser(userUC *biz.UserUseCase, membershipUC *biz.M // NOTE: we reuse the existing middlewares to set the current user and organization by wrapping the call // Now we can load the organization using the other middleware we have set return WithCurrentUserMiddleware(userUC, logger)(func(ctx context.Context, req any) (any, error) { - return WithCurrentOrganizationMiddleware(userUC, membershipUC, logger)(func(ctx context.Context, req any) (any, error) { + return WithCurrentOrganizationMiddleware(userUC, logger)(func(ctx context.Context, req any) (any, error) { org := entities.CurrentOrg(ctx) if org == nil { return nil, errors.New("organization not found") diff --git a/app/controlplane/pkg/authz/membership.go b/app/controlplane/pkg/authz/membership.go index d7d876d4d..1733d36de 100644 --- a/app/controlplane/pkg/authz/membership.go +++ b/app/controlplane/pkg/authz/membership.go @@ -25,6 +25,7 @@ const ( MembershipTypeUser MembershipType = "user" MembershipTypeGroup MembershipType = "group" + ResourceTypeInstance ResourceType = "instance" ResourceTypeOrganization ResourceType = "organization" ResourceTypeProject ResourceType = "project" ResourceTypeProduct ResourceType = "product" @@ -44,6 +45,7 @@ func (MembershipType) Values() (values []string) { // Values implement https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues func (ResourceType) Values() (values []string) { values = append(values, + string(ResourceTypeInstance), string(ResourceTypeOrganization), string(ResourceTypeProject), string(ResourceTypeGroup), diff --git a/app/controlplane/pkg/data/ent/membership/membership.go b/app/controlplane/pkg/data/ent/membership/membership.go index 6316942d7..16defe85e 100644 --- a/app/controlplane/pkg/data/ent/membership/membership.go +++ b/app/controlplane/pkg/data/ent/membership/membership.go @@ -139,7 +139,7 @@ func MembershipTypeValidator(mt authz.MembershipType) error { // ResourceTypeValidator is a validator for the "resource_type" field enum values. It is called by the builders before save. func ResourceTypeValidator(rt authz.ResourceType) error { switch rt { - case "organization", "project", "group", "product": + case "instance", "organization", "project", "group", "product": return nil default: return fmt.Errorf("membership: invalid enum value for resource_type field: %q", rt) diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index e8d11f640..3d612bf64 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -323,7 +323,7 @@ var ( {Name: "role", Type: field.TypeEnum, Enums: []string{"role:instance:admin", "role:org:owner", "role:org:admin", "role:org:viewer", "role:org:member", "role:org:contributor", "role:project:admin", "role:project:viewer", "role:group:maintainer", "role:product:admin", "role:product:viewer"}}, {Name: "membership_type", Type: field.TypeEnum, Nullable: true, Enums: []string{"user", "group"}}, {Name: "member_id", Type: field.TypeUUID, Nullable: true}, - {Name: "resource_type", Type: field.TypeEnum, Nullable: true, Enums: []string{"organization", "project", "group", "product"}}, + {Name: "resource_type", Type: field.TypeEnum, Nullable: true, Enums: []string{"instance", "organization", "project", "group", "product"}}, {Name: "resource_id", Type: field.TypeUUID, Nullable: true}, {Name: "parent_id", Type: field.TypeUUID, Nullable: true}, {Name: "organization_memberships", Type: field.TypeUUID, Nullable: true},