From 52daa2e0631326965c34b88b8066a9cd31e528df Mon Sep 17 00:00:00 2001 From: Sylwester Piskozub Date: Fri, 5 Dec 2025 08:47:13 +0100 Subject: [PATCH 1/3] add org setting for preventing project scoped contracts Signed-off-by: Sylwester Piskozub --- .../api/controlplane/v1/organization.pb.go | 142 ++++---- .../api/controlplane/v1/organization.proto | 3 + .../controlplane/v1/response_messages.pb.go | 331 +++++++++--------- .../controlplane/v1/response_messages.proto | 2 + .../frontend/controlplane/v1/organization.ts | 23 +- .../controlplane/v1/response_messages.ts | 19 + .../controlplane.v1.OrgItem.jsonschema.json | 8 + .../controlplane.v1.OrgItem.schema.json | 8 + ...zationServiceUpdateRequest.jsonschema.json | 8 + ...ganizationServiceUpdateRequest.schema.json | 8 + app/controlplane/cmd/wire_gen.go | 2 +- app/controlplane/internal/service/context.go | 1 + .../internal/service/organization.go | 2 +- .../internal/service/workflowcontract.go | 15 +- app/controlplane/pkg/biz/organization.go | 8 +- .../ent/migrate/migrations/20251204133913.sql | 2 + .../pkg/data/ent/migrate/migrations/atlas.sum | 3 +- .../pkg/data/ent/migrate/schema.go | 1 + app/controlplane/pkg/data/ent/mutation.go | 56 ++- app/controlplane/pkg/data/ent/organization.go | 13 +- .../pkg/data/ent/organization/organization.go | 10 + .../pkg/data/ent/organization/where.go | 15 + .../pkg/data/ent/organization_create.go | 65 ++++ .../pkg/data/ent/organization_update.go | 34 ++ app/controlplane/pkg/data/ent/runtime.go | 4 + .../pkg/data/ent/schema/organization.go | 2 + app/controlplane/pkg/data/organization.go | 4 +- 27 files changed, 556 insertions(+), 233 deletions(-) create mode 100644 app/controlplane/pkg/data/ent/migrate/migrations/20251204133913.sql diff --git a/app/controlplane/api/controlplane/v1/organization.pb.go b/app/controlplane/api/controlplane/v1/organization.pb.go index 6522e4c56..200e051cf 100644 --- a/app/controlplane/api/controlplane/v1/organization.pb.go +++ b/app/controlplane/api/controlplane/v1/organization.pb.go @@ -471,6 +471,8 @@ type OrganizationServiceUpdateRequest struct { UpdatePoliciesAllowedHostnames bool `protobuf:"varint,4,opt,name=update_policies_allowed_hostnames,json=updatePoliciesAllowedHostnames,proto3" json:"update_policies_allowed_hostnames,omitempty"` // prevent workflows and projects from being created implicitly during attestation init PreventImplicitWorkflowCreation *bool `protobuf:"varint,5,opt,name=prevent_implicit_workflow_creation,json=preventImplicitWorkflowCreation,proto3,oneof" json:"prevent_implicit_workflow_creation,omitempty"` + // prevent_project_scoped_contracts restricts contract creation to only organization-level contracts + PreventProjectScopedContracts *bool `protobuf:"varint,6,opt,name=prevent_project_scoped_contracts,json=preventProjectScopedContracts,proto3,oneof" json:"prevent_project_scoped_contracts,omitempty"` } func (x *OrganizationServiceUpdateRequest) Reset() { @@ -540,6 +542,13 @@ func (x *OrganizationServiceUpdateRequest) GetPreventImplicitWorkflowCreation() return false } +func (x *OrganizationServiceUpdateRequest) GetPreventProjectScopedContracts() bool { + if x != nil && x.PreventProjectScopedContracts != nil { + return *x.PreventProjectScopedContracts + } + return false +} + type OrganizationServiceUpdateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -752,7 +761,7 @@ var file_controlplane_v1_organization_proto_rawDesc = []byte{ 0x73, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x22, 0x9f, 0x03, 0x0a, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x73, 0x75, 0x6c, 0x74, 0x22, 0x92, 0x04, 0x0a, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, @@ -774,78 +783,85 @@ var file_controlplane_v1_organization_proto_rawDesc = []byte{ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x1f, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, - 0x01, 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x6e, 0x5f, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, - 0x25, 0x0a, 0x23, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6d, 0x70, 0x6c, - 0x69, 0x63, 0x69, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x55, 0x0a, 0x21, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, - 0x67, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3f, 0x0a, - 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x23, - 0x0a, 0x21, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x32, 0x95, 0x06, 0x0a, 0x13, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, 0x0a, 0x06, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, - 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x01, 0x12, 0x4c, 0x0a, 0x20, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x48, 0x02, 0x52, 0x1d, 0x70, + 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x63, 0x6f, + 0x70, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x88, 0x01, 0x01, 0x42, + 0x1c, 0x0a, 0x1a, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x5f, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x25, 0x0a, + 0x23, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x63, + 0x69, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x23, 0x0a, 0x21, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x22, 0x55, 0x0a, 0x21, 0x4f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, + 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x22, 0x3f, 0x0a, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x22, 0x23, 0x0a, 0x21, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x06, 0x0a, 0x13, 0x4f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, + 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x06, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x6f, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, - 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6f, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8a, - 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x10, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x12, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x10, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x12, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x8a, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x68, 0x69, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8d, + 0x01, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x12, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x3c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8d, + 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x12, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x3c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4c, 0x5a, 0x4a, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, - 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4c, + 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/controlplane/api/controlplane/v1/organization.proto b/app/controlplane/api/controlplane/v1/organization.proto index 59533dc21..ba6fd8b29 100644 --- a/app/controlplane/api/controlplane/v1/organization.proto +++ b/app/controlplane/api/controlplane/v1/organization.proto @@ -96,6 +96,9 @@ message OrganizationServiceUpdateRequest { // prevent workflows and projects from being created implicitly during attestation init optional bool prevent_implicit_workflow_creation = 5; + + // prevent_project_scoped_contracts restricts contract creation to only organization-level contracts + optional bool prevent_project_scoped_contracts = 6; } message OrganizationServiceUpdateResponse { diff --git a/app/controlplane/api/controlplane/v1/response_messages.pb.go b/app/controlplane/api/controlplane/v1/response_messages.pb.go index db3b528f7..fe5af9bfe 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.pb.go +++ b/app/controlplane/api/controlplane/v1/response_messages.pb.go @@ -1928,6 +1928,8 @@ type OrgItem struct { PolicyAllowedHostnames []string `protobuf:"bytes,5,rep,name=policy_allowed_hostnames,json=policyAllowedHostnames,proto3" json:"policy_allowed_hostnames,omitempty"` // prevent workflows and projects from being created implicitly during attestation init PreventImplicitWorkflowCreation bool `protobuf:"varint,7,opt,name=prevent_implicit_workflow_creation,json=preventImplicitWorkflowCreation,proto3" json:"prevent_implicit_workflow_creation,omitempty"` + // prevent_project_scoped_contracts restricts contract creation to only organization-level contracts + PreventProjectScopedContracts bool `protobuf:"varint,8,opt,name=prevent_project_scoped_contracts,json=preventProjectScopedContracts,proto3" json:"prevent_project_scoped_contracts,omitempty"` } func (x *OrgItem) Reset() { @@ -2011,6 +2013,13 @@ func (x *OrgItem) GetPreventImplicitWorkflowCreation() bool { return false } +func (x *OrgItem) GetPreventProjectScopedContracts() bool { + if x != nil { + return x.PreventProjectScopedContracts + } + return false +} + type CASBackendItem struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3008,7 +3017,7 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x33, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0xe7, 0x04, + 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0xb0, 0x05, 0x0a, 0x07, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, @@ -3036,165 +3045,169 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0xb4, 0x01, 0x0a, 0x1f, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, - 0x74, 0x65, 0x67, 0x79, 0x12, 0x32, 0x0a, 0x2e, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, - 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, 0x4e, - 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2c, 0x0a, 0x28, 0x50, 0x4f, 0x4c, 0x49, - 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, - 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x42, - 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x2f, 0x0a, 0x2b, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, - 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x41, 0x44, 0x56, - 0x49, 0x53, 0x4f, 0x52, 0x59, 0x10, 0x02, 0x22, 0xf5, 0x05, 0x0a, 0x0e, 0x43, 0x41, 0x53, 0x42, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x12, 0x47, 0x0a, 0x20, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x70, 0x72, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x1f, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x32, 0x0a, + 0x2e, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, + 0x45, 0x47, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x2c, 0x0a, 0x28, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, + 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, + 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, + 0x2f, 0x0a, 0x2b, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, + 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x41, 0x44, 0x56, 0x49, 0x53, 0x4f, 0x52, 0x59, 0x10, 0x02, + 0x22, 0xf5, 0x05, 0x0a, 0x0e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x5d, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x53, + 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x10, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x06, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x6c, 0x69, 0x6e, + 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x49, 0x6e, 0x6c, 0x69, 0x6e, + 0x65, 0x12, 0x2e, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, + 0x01, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0x25, 0x0a, 0x06, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x41, 0x4c, 0x49, 0x44, + 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x41, + 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, + 0x44, 0x10, 0x02, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xdd, 0x03, 0x0a, 0x0c, 0x41, 0x50, 0x49, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x27, 0x0a, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x72, 0x67, 0x61, + 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x63, 0x6f, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x5d, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, - 0x65, 0x6d, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x06, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, - 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x73, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, - 0x73, 0x5f, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, - 0x69, 0x73, 0x49, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x2e, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x1a, 0x25, 0x0a, 0x06, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, 0x0a, - 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x08, 0x6d, 0x61, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x10, 0x56, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, - 0x0a, 0x1d, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x56, - 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, - 0xdd, 0x03, 0x0a, 0x0c, 0x41, 0x50, 0x49, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x74, 0x65, 0x6d, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x2b, 0x0a, 0x11, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x72, 0x67, 0x61, - 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0d, - 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x52, 0x0c, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x72, - 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, - 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, - 0x73, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, - 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x41, 0x74, 0x2a, - 0xa6, 0x01, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, - 0x16, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x55, 0x4e, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, - 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, - 0x15, 0x0a, 0x11, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, - 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x12, 0x18, - 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, - 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x2a, 0xa1, 0x01, 0x0a, 0x16, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x24, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, - 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2c, 0x0a, - 0x28, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x56, - 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x01, 0x12, 0x2f, 0x0a, 0x2b, 0x50, - 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, - 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x5f, - 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x02, 0x2a, 0xd4, 0x01, 0x0a, - 0x0e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x12, - 0x1f, 0x0a, 0x1b, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, - 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, - 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x45, 0x52, 0x10, 0x01, - 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, - 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, - 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, - 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x03, 0x12, 0x1e, - 0x0a, 0x1a, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, - 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x04, 0x12, 0x23, - 0x0a, 0x1f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, - 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x4f, - 0x52, 0x10, 0x05, 0x2a, 0x60, 0x0a, 0x0e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, - 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x26, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, - 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, - 0x49, 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, - 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x6d, 0x0a, 0x12, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x24, 0x0a, 0x20, 0x46, - 0x45, 0x44, 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x2b, 0x0a, 0x21, 0x46, 0x45, 0x44, 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, - 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, - 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, - 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x84, 0x01, 0x0a, 0x19, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, - 0x68, 0x4e, 0x6f, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x45, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x29, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, - 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x32, 0x0a, 0x28, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x4e, - 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x45, 0x52, 0x52, - 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x01, 0x1a, - 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x80, 0x01, 0x0a, 0x17, - 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x66, 0x4f, - 0x72, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x28, 0x55, 0x53, 0x45, 0x52, 0x5f, - 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, - 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x31, 0x0a, 0x27, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f, - 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x47, 0x5f, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x47, - 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x42, 0x4c, - 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6c, 0x61, + 0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x41, 0x74, 0x2a, 0xa6, 0x01, 0x0a, 0x09, 0x52, 0x75, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, + 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, + 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x55, 0x4e, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, + 0x16, 0x0a, 0x12, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, + 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, + 0x05, 0x2a, 0xa1, 0x01, 0x0a, 0x16, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x24, + 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2c, 0x0a, 0x28, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, + 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x54, + 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x53, 0x10, 0x01, 0x12, 0x2f, 0x0a, 0x2b, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, + 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, + 0x5f, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x53, 0x10, 0x02, 0x2a, 0xd4, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x45, 0x4d, 0x42, + 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x4d, + 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, + 0x5f, 0x56, 0x49, 0x45, 0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, + 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, + 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, 0x42, + 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, + 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x03, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x4d, 0x42, 0x45, + 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x4d, + 0x45, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x4d, 0x45, 0x4d, 0x42, 0x45, + 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x43, + 0x4f, 0x4e, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x4f, 0x52, 0x10, 0x05, 0x2a, 0x60, 0x0a, 0x0e, + 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, + 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, + 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x26, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, + 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x6d, + 0x0a, 0x12, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x45, 0x44, 0x45, 0x52, 0x41, 0x54, 0x45, + 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x21, 0x46, 0x45, + 0x44, 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, + 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, + 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x84, 0x01, + 0x0a, 0x19, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x6f, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x29, 0x55, + 0x53, 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, + 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x32, 0x0a, 0x28, 0x55, 0x53, + 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, + 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, + 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, + 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x80, 0x01, 0x0a, 0x17, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x66, 0x4f, 0x72, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x2c, 0x0a, 0x28, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, + 0x42, 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x31, + 0x0a, 0x27, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, + 0x52, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, + 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, + 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, + 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, + 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, + 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/controlplane/api/controlplane/v1/response_messages.proto b/app/controlplane/api/controlplane/v1/response_messages.proto index 8dcee28d1..f13015526 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.proto +++ b/app/controlplane/api/controlplane/v1/response_messages.proto @@ -281,6 +281,8 @@ message OrgItem { repeated string policy_allowed_hostnames = 5; // prevent workflows and projects from being created implicitly during attestation init bool prevent_implicit_workflow_creation = 7; + // prevent_project_scoped_contracts restricts contract creation to only organization-level contracts + bool prevent_project_scoped_contracts = 8; enum PolicyViolationBlockingStrategy { POLICY_VIOLATION_BLOCKING_STRATEGY_UNSPECIFIED = 0; diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/organization.ts b/app/controlplane/api/gen/frontend/controlplane/v1/organization.ts index aecd08468..830eadfd4 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/organization.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/organization.ts @@ -77,7 +77,11 @@ export interface OrganizationServiceUpdateRequest { */ updatePoliciesAllowedHostnames: boolean; /** prevent workflows and projects from being created implicitly during attestation init */ - preventImplicitWorkflowCreation?: boolean | undefined; + preventImplicitWorkflowCreation?: + | boolean + | undefined; + /** prevent_project_scoped_contracts restricts contract creation to only organization-level contracts */ + preventProjectScopedContracts?: boolean | undefined; } export interface OrganizationServiceUpdateResponse { @@ -666,6 +670,7 @@ function createBaseOrganizationServiceUpdateRequest(): OrganizationServiceUpdate policiesAllowedHostnames: [], updatePoliciesAllowedHostnames: false, preventImplicitWorkflowCreation: undefined, + preventProjectScopedContracts: undefined, }; } @@ -686,6 +691,9 @@ export const OrganizationServiceUpdateRequest = { if (message.preventImplicitWorkflowCreation !== undefined) { writer.uint32(40).bool(message.preventImplicitWorkflowCreation); } + if (message.preventProjectScopedContracts !== undefined) { + writer.uint32(48).bool(message.preventProjectScopedContracts); + } return writer; }, @@ -731,6 +739,13 @@ export const OrganizationServiceUpdateRequest = { message.preventImplicitWorkflowCreation = reader.bool(); continue; + case 6: + if (tag !== 48) { + break; + } + + message.preventProjectScopedContracts = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -753,6 +768,9 @@ export const OrganizationServiceUpdateRequest = { preventImplicitWorkflowCreation: isSet(object.preventImplicitWorkflowCreation) ? Boolean(object.preventImplicitWorkflowCreation) : undefined, + preventProjectScopedContracts: isSet(object.preventProjectScopedContracts) + ? Boolean(object.preventProjectScopedContracts) + : undefined, }; }, @@ -769,6 +787,8 @@ export const OrganizationServiceUpdateRequest = { (obj.updatePoliciesAllowedHostnames = message.updatePoliciesAllowedHostnames); message.preventImplicitWorkflowCreation !== undefined && (obj.preventImplicitWorkflowCreation = message.preventImplicitWorkflowCreation); + message.preventProjectScopedContracts !== undefined && + (obj.preventProjectScopedContracts = message.preventProjectScopedContracts); return obj; }, @@ -787,6 +807,7 @@ export const OrganizationServiceUpdateRequest = { message.policiesAllowedHostnames = object.policiesAllowedHostnames?.map((e) => e) || []; message.updatePoliciesAllowedHostnames = object.updatePoliciesAllowedHostnames ?? false; message.preventImplicitWorkflowCreation = object.preventImplicitWorkflowCreation ?? undefined; + message.preventProjectScopedContracts = object.preventProjectScopedContracts ?? undefined; return message; }, }; diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts index d46979db4..6f5f346c8 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts @@ -608,6 +608,8 @@ export interface OrgItem { policyAllowedHostnames: string[]; /** prevent workflows and projects from being created implicitly during attestation init */ preventImplicitWorkflowCreation: boolean; + /** prevent_project_scoped_contracts restricts contract creation to only organization-level contracts */ + preventProjectScopedContracts: boolean; } export enum OrgItem_PolicyViolationBlockingStrategy { @@ -3756,6 +3758,7 @@ function createBaseOrgItem(): OrgItem { defaultPolicyViolationStrategy: 0, policyAllowedHostnames: [], preventImplicitWorkflowCreation: false, + preventProjectScopedContracts: false, }; } @@ -3782,6 +3785,9 @@ export const OrgItem = { if (message.preventImplicitWorkflowCreation === true) { writer.uint32(56).bool(message.preventImplicitWorkflowCreation); } + if (message.preventProjectScopedContracts === true) { + writer.uint32(64).bool(message.preventProjectScopedContracts); + } return writer; }, @@ -3841,6 +3847,13 @@ export const OrgItem = { message.preventImplicitWorkflowCreation = reader.bool(); continue; + case 8: + if (tag !== 64) { + break; + } + + message.preventProjectScopedContracts = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -3865,6 +3878,9 @@ export const OrgItem = { preventImplicitWorkflowCreation: isSet(object.preventImplicitWorkflowCreation) ? Boolean(object.preventImplicitWorkflowCreation) : false, + preventProjectScopedContracts: isSet(object.preventProjectScopedContracts) + ? Boolean(object.preventProjectScopedContracts) + : false, }; }, @@ -3885,6 +3901,8 @@ export const OrgItem = { } message.preventImplicitWorkflowCreation !== undefined && (obj.preventImplicitWorkflowCreation = message.preventImplicitWorkflowCreation); + message.preventProjectScopedContracts !== undefined && + (obj.preventProjectScopedContracts = message.preventProjectScopedContracts); return obj; }, @@ -3901,6 +3919,7 @@ export const OrgItem = { message.defaultPolicyViolationStrategy = object.defaultPolicyViolationStrategy ?? 0; message.policyAllowedHostnames = object.policyAllowedHostnames?.map((e) => e) || []; message.preventImplicitWorkflowCreation = object.preventImplicitWorkflowCreation ?? false; + message.preventProjectScopedContracts = object.preventProjectScopedContracts ?? false; return message; }, }; diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.jsonschema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.jsonschema.json index 0a179c3b7..6dda0276e 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.jsonschema.json @@ -34,6 +34,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "^(prevent_project_scoped_contracts)$": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "^(updated_at)$": { "$ref": "google.protobuf.Timestamp.jsonschema.json" } @@ -76,6 +80,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "preventProjectScopedContracts": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "updatedAt": { "$ref": "google.protobuf.Timestamp.jsonschema.json" } diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.schema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.schema.json index ec7cd08c4..825a08dfe 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.schema.json @@ -34,6 +34,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "^(preventProjectScopedContracts)$": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "^(updatedAt)$": { "$ref": "google.protobuf.Timestamp.schema.json" } @@ -76,6 +80,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "prevent_project_scoped_contracts": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "updated_at": { "$ref": "google.protobuf.Timestamp.schema.json" } diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.jsonschema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.jsonschema.json index feebca398..463c047c8 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.jsonschema.json @@ -18,6 +18,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "^(prevent_project_scoped_contracts)$": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "^(update_policies_allowed_hostnames)$": { "description": "flag that allows us to detect if the value is explicitly set\n since repeated fields can not be optional", "type": "boolean" @@ -43,6 +47,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "preventProjectScopedContracts": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "updatePoliciesAllowedHostnames": { "description": "flag that allows us to detect if the value is explicitly set\n since repeated fields can not be optional", "type": "boolean" diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.schema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.schema.json index 346b7f3a9..4ec1baefb 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.schema.json @@ -18,6 +18,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "^(preventProjectScopedContracts)$": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "^(updatePoliciesAllowedHostnames)$": { "description": "flag that allows us to detect if the value is explicitly set\n since repeated fields can not be optional", "type": "boolean" @@ -43,6 +47,10 @@ "description": "prevent workflows and projects from being created implicitly during attestation init", "type": "boolean" }, + "prevent_project_scoped_contracts": { + "description": "prevent_project_scoped_contracts restricts contract creation to only organization-level contracts", + "type": "boolean" + }, "update_policies_allowed_hostnames": { "description": "flag that allows us to detect if the value is explicitly set\n since repeated fields can not be optional", "type": "boolean" diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index 436700e5e..c4113d72c 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -205,7 +205,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l Opts: v5, } attestationService := service.NewAttestationService(newAttestationServiceOpts) - workflowContractService := service.NewWorkflowSchemaService(workflowContractUseCase, v5...) + workflowContractService := service.NewWorkflowSchemaService(workflowContractUseCase, organizationUseCase, v5...) contextService := service.NewContextService(casBackendUseCase, userUseCase, v5...) casCredentialsService := service.NewCASCredentialsService(casCredentialsUseCase, casMappingUseCase, casBackendUseCase, authzUseCase, v5...) orgMetricsService := service.NewOrgMetricsService(orgMetricsUseCase, v5...) diff --git a/app/controlplane/internal/service/context.go b/app/controlplane/internal/service/context.go index 3764f9d02..95c1039da 100644 --- a/app/controlplane/internal/service/context.go +++ b/app/controlplane/internal/service/context.go @@ -122,6 +122,7 @@ func bizOrgToPb(m *biz.Organization) *pb.OrgItem { DefaultPolicyViolationStrategy: bizPolicyViolationBlockingStrategyToPb(m.BlockOnPolicyViolation), PolicyAllowedHostnames: m.PoliciesAllowedHostnames, PreventImplicitWorkflowCreation: m.PreventImplicitWorkflowCreation, + PreventProjectScopedContracts: m.PreventProjectScopedContracts, } } diff --git a/app/controlplane/internal/service/organization.go b/app/controlplane/internal/service/organization.go index 6a6f62f03..a0b32e83d 100644 --- a/app/controlplane/internal/service/organization.go +++ b/app/controlplane/internal/service/organization.go @@ -89,7 +89,7 @@ func (s *OrganizationService) Update(ctx context.Context, req *pb.OrganizationSe } } - org, err := s.orgUC.Update(ctx, currentUser.ID, req.Name, req.BlockOnPolicyViolation, policiesAllowedHostnames, req.PreventImplicitWorkflowCreation) + org, err := s.orgUC.Update(ctx, currentUser.ID, req.Name, req.BlockOnPolicyViolation, policiesAllowedHostnames, req.PreventImplicitWorkflowCreation, req.PreventProjectScopedContracts) if err != nil { return nil, handleUseCaseErr(err, s.log) } diff --git a/app/controlplane/internal/service/workflowcontract.go b/app/controlplane/internal/service/workflowcontract.go index 701c4a4a4..718bb3271 100644 --- a/app/controlplane/internal/service/workflowcontract.go +++ b/app/controlplane/internal/service/workflowcontract.go @@ -34,12 +34,14 @@ type WorkflowContractService struct { *service contractUseCase *biz.WorkflowContractUseCase + orgUseCase *biz.OrganizationUseCase } -func NewWorkflowSchemaService(uc *biz.WorkflowContractUseCase, opts ...NewOpt) *WorkflowContractService { +func NewWorkflowSchemaService(uc *biz.WorkflowContractUseCase, orgUC *biz.OrganizationUseCase, opts ...NewOpt) *WorkflowContractService { return &WorkflowContractService{ service: newService(opts...), contractUseCase: uc, + orgUseCase: orgUC, } } @@ -109,9 +111,20 @@ func (s *WorkflowContractService) Create(ctx context.Context, req *pb.WorkflowCo return nil, errors.BadRequest("invalid", "project is required") } + // Check organization settings for project-scoped contracts + org, err := s.orgUseCase.FindByID(ctx, currentOrg.ID) + if err != nil { + return nil, handleUseCaseErr(err, s.log) + } + // if the project is provided we make sure it exists and the user has permission to it var projectID *uuid.UUID if req.ProjectReference.IsSet() { + // Check if organization prevents project-scoped contracts + if org.PreventProjectScopedContracts { + return nil, errors.BadRequest("invalid", "organization does not allow project-scoped contracts") + } + // Make sure the provided project exists and the user has permission to create tokens in it project, err := s.userHasPermissionOnProject(ctx, currentOrg.ID, req.GetProjectReference(), authz.PolicyWorkflowContractCreate) if err != nil { diff --git a/app/controlplane/pkg/biz/organization.go b/app/controlplane/pkg/biz/organization.go index 1787b14cf..3a7572595 100644 --- a/app/controlplane/pkg/biz/organization.go +++ b/app/controlplane/pkg/biz/organization.go @@ -41,13 +41,15 @@ type Organization struct { PoliciesAllowedHostnames []string // PreventImplicitWorkflowCreation prevents workflows and projects from being created implicitly during attestation init PreventImplicitWorkflowCreation bool + // PreventProjectScopedContracts restricts contract creation to only organization-level contracts + PreventProjectScopedContracts bool } type OrganizationRepo interface { FindByID(ctx context.Context, orgID uuid.UUID) (*Organization, error) FindByName(ctx context.Context, name string) (*Organization, error) Create(ctx context.Context, name string) (*Organization, error) - Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*Organization, error) + Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool, preventProjectScopedContracts *bool) (*Organization, error) Delete(ctx context.Context, ID uuid.UUID) error } @@ -187,7 +189,7 @@ func (uc *OrganizationUseCase) doCreate(ctx context.Context, name string, opts . return org, nil } -func (uc *OrganizationUseCase) Update(ctx context.Context, userID, orgName string, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*Organization, error) { +func (uc *OrganizationUseCase) Update(ctx context.Context, userID, orgName string, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool, preventProjectScopedContracts *bool) (*Organization, error) { userUUID, err := uuid.Parse(userID) if err != nil { return nil, NewErrInvalidUUID(err) @@ -207,7 +209,7 @@ func (uc *OrganizationUseCase) Update(ctx context.Context, userID, orgName strin } // Perform the update - org, err := uc.orgRepo.Update(ctx, orgUUID, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + org, err := uc.orgRepo.Update(ctx, orgUUID, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation, preventProjectScopedContracts) if err != nil { return nil, fmt.Errorf("failed to update organization: %w", err) } else if org == nil { diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20251204133913.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20251204133913.sql new file mode 100644 index 000000000..073ea711c --- /dev/null +++ b/app/controlplane/pkg/data/ent/migrate/migrations/20251204133913.sql @@ -0,0 +1,2 @@ +-- Modify "organizations" table +ALTER TABLE "organizations" ADD COLUMN "prevent_project_scoped_contracts" boolean NOT NULL DEFAULT false; diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum index 527c94030..51c060885 100644 --- a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:2JyaUYFWieGKl87rW890mAXAE3XJrL4K4/C51Nl3qOk= +h1:ElZ12CneaiJmAK7EoN8AbLfpZebycSFaTDWu6BG4ZR0= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -120,3 +120,4 @@ h1:2JyaUYFWieGKl87rW890mAXAE3XJrL4K4/C51Nl3qOk= 20251107233855.sql h1:fNK+hRlqzlM4qxKR7SPMEtbrYSAJfau6bKm1jecRDpE= 20251111162946.sql h1:oNke93PdAreUH6F5AD5FE6uI6riJpE4KPb77LXTeuRU= 20251114174059.sql h1:f/wB/OlhZxIc9AVCxTNu4dFmPd1T3sCY0nS8Zb9ZS9Q= +20251204133913.sql h1:tPjlN6sp64nsspbvaXln+PVvLs2R7N+w16fxNqKke1Y= diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 1a564b7dc..a8e624c99 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -423,6 +423,7 @@ var ( {Name: "block_on_policy_violation", Type: field.TypeBool, Default: false}, {Name: "policies_allowed_hostnames", Type: field.TypeJSON, Nullable: true}, {Name: "prevent_implicit_workflow_creation", Type: field.TypeBool, Default: false}, + {Name: "prevent_project_scoped_contracts", Type: field.TypeBool, Default: false}, } // OrganizationsTable holds the schema information for the "organizations" table. OrganizationsTable = &schema.Table{ diff --git a/app/controlplane/pkg/data/ent/mutation.go b/app/controlplane/pkg/data/ent/mutation.go index dd2fe0581..f0d1ab738 100644 --- a/app/controlplane/pkg/data/ent/mutation.go +++ b/app/controlplane/pkg/data/ent/mutation.go @@ -8707,6 +8707,7 @@ type OrganizationMutation struct { policies_allowed_hostnames *[]string appendpolicies_allowed_hostnames []string prevent_implicit_workflow_creation *bool + prevent_project_scoped_contracts *bool clearedFields map[string]struct{} memberships map[uuid.UUID]struct{} removedmemberships map[uuid.UUID]struct{} @@ -9135,6 +9136,42 @@ func (m *OrganizationMutation) ResetPreventImplicitWorkflowCreation() { m.prevent_implicit_workflow_creation = nil } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (m *OrganizationMutation) SetPreventProjectScopedContracts(b bool) { + m.prevent_project_scoped_contracts = &b +} + +// PreventProjectScopedContracts returns the value of the "prevent_project_scoped_contracts" field in the mutation. +func (m *OrganizationMutation) PreventProjectScopedContracts() (r bool, exists bool) { + v := m.prevent_project_scoped_contracts + if v == nil { + return + } + return *v, true +} + +// OldPreventProjectScopedContracts returns the old "prevent_project_scoped_contracts" field's value of the Organization entity. +// If the Organization object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrganizationMutation) OldPreventProjectScopedContracts(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPreventProjectScopedContracts is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPreventProjectScopedContracts requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPreventProjectScopedContracts: %w", err) + } + return oldValue.PreventProjectScopedContracts, nil +} + +// ResetPreventProjectScopedContracts resets all changes to the "prevent_project_scoped_contracts" field. +func (m *OrganizationMutation) ResetPreventProjectScopedContracts() { + m.prevent_project_scoped_contracts = nil +} + // AddMembershipIDs adds the "memberships" edge to the Membership entity by ids. func (m *OrganizationMutation) AddMembershipIDs(ids ...uuid.UUID) { if m.memberships == nil { @@ -9601,7 +9638,7 @@ func (m *OrganizationMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *OrganizationMutation) Fields() []string { - fields := make([]string, 0, 7) + fields := make([]string, 0, 8) if m.name != nil { fields = append(fields, organization.FieldName) } @@ -9623,6 +9660,9 @@ func (m *OrganizationMutation) Fields() []string { if m.prevent_implicit_workflow_creation != nil { fields = append(fields, organization.FieldPreventImplicitWorkflowCreation) } + if m.prevent_project_scoped_contracts != nil { + fields = append(fields, organization.FieldPreventProjectScopedContracts) + } return fields } @@ -9645,6 +9685,8 @@ func (m *OrganizationMutation) Field(name string) (ent.Value, bool) { return m.PoliciesAllowedHostnames() case organization.FieldPreventImplicitWorkflowCreation: return m.PreventImplicitWorkflowCreation() + case organization.FieldPreventProjectScopedContracts: + return m.PreventProjectScopedContracts() } return nil, false } @@ -9668,6 +9710,8 @@ func (m *OrganizationMutation) OldField(ctx context.Context, name string) (ent.V return m.OldPoliciesAllowedHostnames(ctx) case organization.FieldPreventImplicitWorkflowCreation: return m.OldPreventImplicitWorkflowCreation(ctx) + case organization.FieldPreventProjectScopedContracts: + return m.OldPreventProjectScopedContracts(ctx) } return nil, fmt.Errorf("unknown Organization field %s", name) } @@ -9726,6 +9770,13 @@ func (m *OrganizationMutation) SetField(name string, value ent.Value) error { } m.SetPreventImplicitWorkflowCreation(v) return nil + case organization.FieldPreventProjectScopedContracts: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPreventProjectScopedContracts(v) + return nil } return fmt.Errorf("unknown Organization field %s", name) } @@ -9811,6 +9862,9 @@ func (m *OrganizationMutation) ResetField(name string) error { case organization.FieldPreventImplicitWorkflowCreation: m.ResetPreventImplicitWorkflowCreation() return nil + case organization.FieldPreventProjectScopedContracts: + m.ResetPreventProjectScopedContracts() + return nil } return fmt.Errorf("unknown Organization field %s", name) } diff --git a/app/controlplane/pkg/data/ent/organization.go b/app/controlplane/pkg/data/ent/organization.go index 2e17f6bfe..3efb5d5f2 100644 --- a/app/controlplane/pkg/data/ent/organization.go +++ b/app/controlplane/pkg/data/ent/organization.go @@ -33,6 +33,8 @@ type Organization struct { PoliciesAllowedHostnames []string `json:"policies_allowed_hostnames,omitempty"` // PreventImplicitWorkflowCreation holds the value of the "prevent_implicit_workflow_creation" field. PreventImplicitWorkflowCreation bool `json:"prevent_implicit_workflow_creation,omitempty"` + // PreventProjectScopedContracts holds the value of the "prevent_project_scoped_contracts" field. + PreventProjectScopedContracts bool `json:"prevent_project_scoped_contracts,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the OrganizationQuery when eager-loading is set. Edges OrganizationEdges `json:"edges"` @@ -141,7 +143,7 @@ func (*Organization) scanValues(columns []string) ([]any, error) { switch columns[i] { case organization.FieldPoliciesAllowedHostnames: values[i] = new([]byte) - case organization.FieldBlockOnPolicyViolation, organization.FieldPreventImplicitWorkflowCreation: + case organization.FieldBlockOnPolicyViolation, organization.FieldPreventImplicitWorkflowCreation, organization.FieldPreventProjectScopedContracts: values[i] = new(sql.NullBool) case organization.FieldName: values[i] = new(sql.NullString) @@ -214,6 +216,12 @@ func (o *Organization) assignValues(columns []string, values []any) error { } else if value.Valid { o.PreventImplicitWorkflowCreation = value.Bool } + case organization.FieldPreventProjectScopedContracts: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field prevent_project_scoped_contracts", values[i]) + } else if value.Valid { + o.PreventProjectScopedContracts = value.Bool + } default: o.selectValues.Set(columns[i], values[i]) } @@ -310,6 +318,9 @@ func (o *Organization) String() string { builder.WriteString(", ") builder.WriteString("prevent_implicit_workflow_creation=") builder.WriteString(fmt.Sprintf("%v", o.PreventImplicitWorkflowCreation)) + builder.WriteString(", ") + builder.WriteString("prevent_project_scoped_contracts=") + builder.WriteString(fmt.Sprintf("%v", o.PreventProjectScopedContracts)) builder.WriteByte(')') return builder.String() } diff --git a/app/controlplane/pkg/data/ent/organization/organization.go b/app/controlplane/pkg/data/ent/organization/organization.go index f948fc628..78d2c269c 100644 --- a/app/controlplane/pkg/data/ent/organization/organization.go +++ b/app/controlplane/pkg/data/ent/organization/organization.go @@ -29,6 +29,8 @@ const ( FieldPoliciesAllowedHostnames = "policies_allowed_hostnames" // FieldPreventImplicitWorkflowCreation holds the string denoting the prevent_implicit_workflow_creation field in the database. FieldPreventImplicitWorkflowCreation = "prevent_implicit_workflow_creation" + // FieldPreventProjectScopedContracts holds the string denoting the prevent_project_scoped_contracts field in the database. + FieldPreventProjectScopedContracts = "prevent_project_scoped_contracts" // EdgeMemberships holds the string denoting the memberships edge name in mutations. EdgeMemberships = "memberships" // EdgeWorkflowContracts holds the string denoting the workflow_contracts edge name in mutations. @@ -115,6 +117,7 @@ var Columns = []string{ FieldBlockOnPolicyViolation, FieldPoliciesAllowedHostnames, FieldPreventImplicitWorkflowCreation, + FieldPreventProjectScopedContracts, } // ValidColumn reports if the column name is valid (part of the table columns). @@ -136,6 +139,8 @@ var ( DefaultBlockOnPolicyViolation bool // DefaultPreventImplicitWorkflowCreation holds the default value on creation for the "prevent_implicit_workflow_creation" field. DefaultPreventImplicitWorkflowCreation bool + // DefaultPreventProjectScopedContracts holds the default value on creation for the "prevent_project_scoped_contracts" field. + DefaultPreventProjectScopedContracts bool // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) @@ -178,6 +183,11 @@ func ByPreventImplicitWorkflowCreation(opts ...sql.OrderTermOption) OrderOption return sql.OrderByField(FieldPreventImplicitWorkflowCreation, opts...).ToFunc() } +// ByPreventProjectScopedContracts orders the results by the prevent_project_scoped_contracts field. +func ByPreventProjectScopedContracts(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPreventProjectScopedContracts, opts...).ToFunc() +} + // ByMembershipsCount orders the results by memberships count. func ByMembershipsCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { diff --git a/app/controlplane/pkg/data/ent/organization/where.go b/app/controlplane/pkg/data/ent/organization/where.go index 566974961..4fe55dff0 100644 --- a/app/controlplane/pkg/data/ent/organization/where.go +++ b/app/controlplane/pkg/data/ent/organization/where.go @@ -86,6 +86,11 @@ func PreventImplicitWorkflowCreation(v bool) predicate.Organization { return predicate.Organization(sql.FieldEQ(FieldPreventImplicitWorkflowCreation, v)) } +// PreventProjectScopedContracts applies equality check predicate on the "prevent_project_scoped_contracts" field. It's identical to PreventProjectScopedContractsEQ. +func PreventProjectScopedContracts(v bool) predicate.Organization { + return predicate.Organization(sql.FieldEQ(FieldPreventProjectScopedContracts, v)) +} + // NameEQ applies the EQ predicate on the "name" field. func NameEQ(v string) predicate.Organization { return predicate.Organization(sql.FieldEQ(FieldName, v)) @@ -311,6 +316,16 @@ func PreventImplicitWorkflowCreationNEQ(v bool) predicate.Organization { return predicate.Organization(sql.FieldNEQ(FieldPreventImplicitWorkflowCreation, v)) } +// PreventProjectScopedContractsEQ applies the EQ predicate on the "prevent_project_scoped_contracts" field. +func PreventProjectScopedContractsEQ(v bool) predicate.Organization { + return predicate.Organization(sql.FieldEQ(FieldPreventProjectScopedContracts, v)) +} + +// PreventProjectScopedContractsNEQ applies the NEQ predicate on the "prevent_project_scoped_contracts" field. +func PreventProjectScopedContractsNEQ(v bool) predicate.Organization { + return predicate.Organization(sql.FieldNEQ(FieldPreventProjectScopedContracts, v)) +} + // HasMemberships applies the HasEdge predicate on the "memberships" edge. func HasMemberships() predicate.Organization { return predicate.Organization(func(s *sql.Selector) { diff --git a/app/controlplane/pkg/data/ent/organization_create.go b/app/controlplane/pkg/data/ent/organization_create.go index db0c7283c..1c52e0542 100644 --- a/app/controlplane/pkg/data/ent/organization_create.go +++ b/app/controlplane/pkg/data/ent/organization_create.go @@ -114,6 +114,20 @@ func (oc *OrganizationCreate) SetNillablePreventImplicitWorkflowCreation(b *bool return oc } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (oc *OrganizationCreate) SetPreventProjectScopedContracts(b bool) *OrganizationCreate { + oc.mutation.SetPreventProjectScopedContracts(b) + return oc +} + +// SetNillablePreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field if the given value is not nil. +func (oc *OrganizationCreate) SetNillablePreventProjectScopedContracts(b *bool) *OrganizationCreate { + if b != nil { + oc.SetPreventProjectScopedContracts(*b) + } + return oc +} + // SetID sets the "id" field. func (oc *OrganizationCreate) SetID(u uuid.UUID) *OrganizationCreate { oc.mutation.SetID(u) @@ -299,6 +313,10 @@ func (oc *OrganizationCreate) defaults() { v := organization.DefaultPreventImplicitWorkflowCreation oc.mutation.SetPreventImplicitWorkflowCreation(v) } + if _, ok := oc.mutation.PreventProjectScopedContracts(); !ok { + v := organization.DefaultPreventProjectScopedContracts + oc.mutation.SetPreventProjectScopedContracts(v) + } if _, ok := oc.mutation.ID(); !ok { v := organization.DefaultID() oc.mutation.SetID(v) @@ -322,6 +340,9 @@ func (oc *OrganizationCreate) check() error { if _, ok := oc.mutation.PreventImplicitWorkflowCreation(); !ok { return &ValidationError{Name: "prevent_implicit_workflow_creation", err: errors.New(`ent: missing required field "Organization.prevent_implicit_workflow_creation"`)} } + if _, ok := oc.mutation.PreventProjectScopedContracts(); !ok { + return &ValidationError{Name: "prevent_project_scoped_contracts", err: errors.New(`ent: missing required field "Organization.prevent_project_scoped_contracts"`)} + } return nil } @@ -386,6 +407,10 @@ func (oc *OrganizationCreate) createSpec() (*Organization, *sqlgraph.CreateSpec) _spec.SetField(organization.FieldPreventImplicitWorkflowCreation, field.TypeBool, value) _node.PreventImplicitWorkflowCreation = value } + if value, ok := oc.mutation.PreventProjectScopedContracts(); ok { + _spec.SetField(organization.FieldPreventProjectScopedContracts, field.TypeBool, value) + _node.PreventProjectScopedContracts = value + } if nodes := oc.mutation.MembershipsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -650,6 +675,18 @@ func (u *OrganizationUpsert) UpdatePreventImplicitWorkflowCreation() *Organizati return u } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (u *OrganizationUpsert) SetPreventProjectScopedContracts(v bool) *OrganizationUpsert { + u.Set(organization.FieldPreventProjectScopedContracts, v) + return u +} + +// UpdatePreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field to the value that was provided on create. +func (u *OrganizationUpsert) UpdatePreventProjectScopedContracts() *OrganizationUpsert { + u.SetExcluded(organization.FieldPreventProjectScopedContracts) + return u +} + // UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // @@ -799,6 +836,20 @@ func (u *OrganizationUpsertOne) UpdatePreventImplicitWorkflowCreation() *Organiz }) } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (u *OrganizationUpsertOne) SetPreventProjectScopedContracts(v bool) *OrganizationUpsertOne { + return u.Update(func(s *OrganizationUpsert) { + s.SetPreventProjectScopedContracts(v) + }) +} + +// UpdatePreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field to the value that was provided on create. +func (u *OrganizationUpsertOne) UpdatePreventProjectScopedContracts() *OrganizationUpsertOne { + return u.Update(func(s *OrganizationUpsert) { + s.UpdatePreventProjectScopedContracts() + }) +} + // Exec executes the query. func (u *OrganizationUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -1115,6 +1166,20 @@ func (u *OrganizationUpsertBulk) UpdatePreventImplicitWorkflowCreation() *Organi }) } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (u *OrganizationUpsertBulk) SetPreventProjectScopedContracts(v bool) *OrganizationUpsertBulk { + return u.Update(func(s *OrganizationUpsert) { + s.SetPreventProjectScopedContracts(v) + }) +} + +// UpdatePreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field to the value that was provided on create. +func (u *OrganizationUpsertBulk) UpdatePreventProjectScopedContracts() *OrganizationUpsertBulk { + return u.Update(func(s *OrganizationUpsert) { + s.UpdatePreventProjectScopedContracts() + }) +} + // Exec executes the query. func (u *OrganizationUpsertBulk) Exec(ctx context.Context) error { if u.create.err != nil { diff --git a/app/controlplane/pkg/data/ent/organization_update.go b/app/controlplane/pkg/data/ent/organization_update.go index a6ae9efab..66390f730 100644 --- a/app/controlplane/pkg/data/ent/organization_update.go +++ b/app/controlplane/pkg/data/ent/organization_update.go @@ -133,6 +133,20 @@ func (ou *OrganizationUpdate) SetNillablePreventImplicitWorkflowCreation(b *bool return ou } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (ou *OrganizationUpdate) SetPreventProjectScopedContracts(b bool) *OrganizationUpdate { + ou.mutation.SetPreventProjectScopedContracts(b) + return ou +} + +// SetNillablePreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field if the given value is not nil. +func (ou *OrganizationUpdate) SetNillablePreventProjectScopedContracts(b *bool) *OrganizationUpdate { + if b != nil { + ou.SetPreventProjectScopedContracts(*b) + } + return ou +} + // AddMembershipIDs adds the "memberships" edge to the Membership entity by IDs. func (ou *OrganizationUpdate) AddMembershipIDs(ids ...uuid.UUID) *OrganizationUpdate { ou.mutation.AddMembershipIDs(ids...) @@ -497,6 +511,9 @@ func (ou *OrganizationUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := ou.mutation.PreventImplicitWorkflowCreation(); ok { _spec.SetField(organization.FieldPreventImplicitWorkflowCreation, field.TypeBool, value) } + if value, ok := ou.mutation.PreventProjectScopedContracts(); ok { + _spec.SetField(organization.FieldPreventProjectScopedContracts, field.TypeBool, value) + } if ou.mutation.MembershipsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -973,6 +990,20 @@ func (ouo *OrganizationUpdateOne) SetNillablePreventImplicitWorkflowCreation(b * return ouo } +// SetPreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field. +func (ouo *OrganizationUpdateOne) SetPreventProjectScopedContracts(b bool) *OrganizationUpdateOne { + ouo.mutation.SetPreventProjectScopedContracts(b) + return ouo +} + +// SetNillablePreventProjectScopedContracts sets the "prevent_project_scoped_contracts" field if the given value is not nil. +func (ouo *OrganizationUpdateOne) SetNillablePreventProjectScopedContracts(b *bool) *OrganizationUpdateOne { + if b != nil { + ouo.SetPreventProjectScopedContracts(*b) + } + return ouo +} + // AddMembershipIDs adds the "memberships" edge to the Membership entity by IDs. func (ouo *OrganizationUpdateOne) AddMembershipIDs(ids ...uuid.UUID) *OrganizationUpdateOne { ouo.mutation.AddMembershipIDs(ids...) @@ -1367,6 +1398,9 @@ func (ouo *OrganizationUpdateOne) sqlSave(ctx context.Context) (_node *Organizat if value, ok := ouo.mutation.PreventImplicitWorkflowCreation(); ok { _spec.SetField(organization.FieldPreventImplicitWorkflowCreation, field.TypeBool, value) } + if value, ok := ouo.mutation.PreventProjectScopedContracts(); ok { + _spec.SetField(organization.FieldPreventProjectScopedContracts, field.TypeBool, value) + } if ouo.mutation.MembershipsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/app/controlplane/pkg/data/ent/runtime.go b/app/controlplane/pkg/data/ent/runtime.go index b5548739f..2107f13be 100644 --- a/app/controlplane/pkg/data/ent/runtime.go +++ b/app/controlplane/pkg/data/ent/runtime.go @@ -209,6 +209,10 @@ func init() { organizationDescPreventImplicitWorkflowCreation := organizationFields[7].Descriptor() // organization.DefaultPreventImplicitWorkflowCreation holds the default value on creation for the prevent_implicit_workflow_creation field. organization.DefaultPreventImplicitWorkflowCreation = organizationDescPreventImplicitWorkflowCreation.Default.(bool) + // organizationDescPreventProjectScopedContracts is the schema descriptor for prevent_project_scoped_contracts field. + organizationDescPreventProjectScopedContracts := organizationFields[8].Descriptor() + // organization.DefaultPreventProjectScopedContracts holds the default value on creation for the prevent_project_scoped_contracts field. + organization.DefaultPreventProjectScopedContracts = organizationDescPreventProjectScopedContracts.Default.(bool) // organizationDescID is the schema descriptor for id field. organizationDescID := organizationFields[0].Descriptor() // organization.DefaultID holds the default value on creation for the id field. diff --git a/app/controlplane/pkg/data/ent/schema/organization.go b/app/controlplane/pkg/data/ent/schema/organization.go index b422f9988..2ae5ddce1 100644 --- a/app/controlplane/pkg/data/ent/schema/organization.go +++ b/app/controlplane/pkg/data/ent/schema/organization.go @@ -53,6 +53,8 @@ func (Organization) Fields() []ent.Field { field.Strings("policies_allowed_hostnames").Optional(), // prevent workflows and projects from being created implicitly during attestation init field.Bool("prevent_implicit_workflow_creation").Default(false), + // prevent_project_scoped_contracts restricts contract creation to only organization-level contracts + field.Bool("prevent_project_scoped_contracts").Default(false), } } diff --git a/app/controlplane/pkg/data/organization.go b/app/controlplane/pkg/data/organization.go index 75b921352..63860b096 100644 --- a/app/controlplane/pkg/data/organization.go +++ b/app/controlplane/pkg/data/organization.go @@ -77,11 +77,12 @@ func (r *OrganizationRepo) FindByName(ctx context.Context, name string) (*biz.Or return entOrgToBizOrg(org), nil } -func (r *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*biz.Organization, error) { +func (r *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool, preventProjectScopedContracts *bool) (*biz.Organization, error) { opts := r.data.DB.Organization.UpdateOneID(id). Where(organization.DeletedAtIsNil()). SetNillableBlockOnPolicyViolation(blockOnPolicyViolation). SetNillablePreventImplicitWorkflowCreation(preventImplicitWorkflowCreation). + SetNillablePreventProjectScopedContracts(preventProjectScopedContracts). SetUpdatedAt(time.Now()) if policiesAllowedHostnames != nil { @@ -113,5 +114,6 @@ func entOrgToBizOrg(eu *ent.Organization) *biz.Organization { BlockOnPolicyViolation: eu.BlockOnPolicyViolation, PoliciesAllowedHostnames: eu.PoliciesAllowedHostnames, PreventImplicitWorkflowCreation: eu.PreventImplicitWorkflowCreation, + PreventProjectScopedContracts: eu.PreventProjectScopedContracts, } } From a7d741918afbaeb7c43db271dc0d35b6501b1856 Mon Sep 17 00:00:00 2001 From: Sylwester Piskozub Date: Sun, 7 Dec 2025 13:52:12 +0100 Subject: [PATCH 2/3] lint Signed-off-by: Sylwester Piskozub --- .../pkg/biz/mocks/OrganizationRepo.go | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/app/controlplane/pkg/biz/mocks/OrganizationRepo.go b/app/controlplane/pkg/biz/mocks/OrganizationRepo.go index 14d50f9df..56e67e83b 100644 --- a/app/controlplane/pkg/biz/mocks/OrganizationRepo.go +++ b/app/controlplane/pkg/biz/mocks/OrganizationRepo.go @@ -301,8 +301,8 @@ func (_c *OrganizationRepo_FindByName_Call) RunAndReturn(run func(ctx context.Co } // Update provides a mock function for the type OrganizationRepo -func (_mock *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*biz.Organization, error) { - ret := _mock.Called(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) +func (_mock *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool, preventProjectScopedContracts *bool) (*biz.Organization, error) { + ret := _mock.Called(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation, preventProjectScopedContracts) if len(ret) == 0 { panic("no return value specified for Update") @@ -310,18 +310,18 @@ func (_mock *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOn var r0 *biz.Organization var r1 error - if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool) (*biz.Organization, error)); ok { - return returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool, *bool) (*biz.Organization, error)); ok { + return returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation, preventProjectScopedContracts) } - if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool) *biz.Organization); ok { - r0 = returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool, *bool) *biz.Organization); ok { + r0 = returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation, preventProjectScopedContracts) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*biz.Organization) } } - if returnFunc, ok := ret.Get(1).(func(context.Context, uuid.UUID, *bool, []string, *bool) error); ok { - r1 = returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + if returnFunc, ok := ret.Get(1).(func(context.Context, uuid.UUID, *bool, []string, *bool, *bool) error); ok { + r1 = returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation, preventProjectScopedContracts) } else { r1 = ret.Error(1) } @@ -339,11 +339,12 @@ type OrganizationRepo_Update_Call struct { // - blockOnPolicyViolation *bool // - policiesAllowedHostnames []string // - preventImplicitWorkflowCreation *bool -func (_e *OrganizationRepo_Expecter) Update(ctx interface{}, id interface{}, blockOnPolicyViolation interface{}, policiesAllowedHostnames interface{}, preventImplicitWorkflowCreation interface{}) *OrganizationRepo_Update_Call { - return &OrganizationRepo_Update_Call{Call: _e.mock.On("Update", ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation)} +// - preventProjectScopedContracts *bool +func (_e *OrganizationRepo_Expecter) Update(ctx interface{}, id interface{}, blockOnPolicyViolation interface{}, policiesAllowedHostnames interface{}, preventImplicitWorkflowCreation interface{}, preventProjectScopedContracts interface{}) *OrganizationRepo_Update_Call { + return &OrganizationRepo_Update_Call{Call: _e.mock.On("Update", ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation, preventProjectScopedContracts)} } -func (_c *OrganizationRepo_Update_Call) Run(run func(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool)) *OrganizationRepo_Update_Call { +func (_c *OrganizationRepo_Update_Call) Run(run func(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool, preventProjectScopedContracts *bool)) *OrganizationRepo_Update_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 context.Context if args[0] != nil { @@ -365,12 +366,17 @@ func (_c *OrganizationRepo_Update_Call) Run(run func(ctx context.Context, id uui if args[4] != nil { arg4 = args[4].(*bool) } + var arg5 *bool + if args[5] != nil { + arg5 = args[5].(*bool) + } run( arg0, arg1, arg2, arg3, arg4, + arg5, ) }) return _c @@ -381,7 +387,7 @@ func (_c *OrganizationRepo_Update_Call) Return(organization *biz.Organization, e return _c } -func (_c *OrganizationRepo_Update_Call) RunAndReturn(run func(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*biz.Organization, error)) *OrganizationRepo_Update_Call { +func (_c *OrganizationRepo_Update_Call) RunAndReturn(run func(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool, preventProjectScopedContracts *bool) (*biz.Organization, error)) *OrganizationRepo_Update_Call { _c.Call.Return(run) return _c } From e659ba8c66b8522ab92ceb7dca94d28db2df17b3 Mon Sep 17 00:00:00 2001 From: Sylwester Piskozub Date: Sun, 7 Dec 2025 14:13:17 +0100 Subject: [PATCH 3/3] lint Signed-off-by: Sylwester Piskozub --- .../pkg/biz/organization_integration_test.go | 14 +++++++------- .../pkg/biz/workflow_integration_test.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controlplane/pkg/biz/organization_integration_test.go b/app/controlplane/pkg/biz/organization_integration_test.go index 2337df5b3..801a86fb2 100644 --- a/app/controlplane/pkg/biz/organization_integration_test.go +++ b/app/controlplane/pkg/biz/organization_integration_test.go @@ -118,7 +118,7 @@ func (s *OrgIntegrationTestSuite) TestUpdate() { s.Run("org non existent", func() { // org not found - _, err := s.Organization.Update(ctx, s.user.ID, uuid.NewString(), nil, nil, nil) + _, err := s.Organization.Update(ctx, s.user.ID, uuid.NewString(), nil, nil, nil, nil) s.Error(err) s.True(biz.IsNotFound(err)) }) @@ -126,35 +126,35 @@ func (s *OrgIntegrationTestSuite) TestUpdate() { s.Run("org not accessible to user", func() { org2, err := s.Organization.CreateWithRandomName(ctx) require.NoError(s.T(), err) - _, err = s.Organization.Update(ctx, s.user.ID, org2.Name, nil, nil, nil) + _, err = s.Organization.Update(ctx, s.user.ID, org2.Name, nil, nil, nil, nil) s.Error(err) s.True(biz.IsNotFound(err)) }) s.Run("valid block on policy violation update", func() { - got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, toPtrBool(true), nil, nil) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, toPtrBool(true), nil, nil, nil) s.NoError(err) s.True(got.BlockOnPolicyViolation) }) s.Run("valid policy allowed hostnames update", func() { - got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{"foo.com", "bar.com"}, nil) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{"foo.com", "bar.com"}, nil, nil) s.NoError(err) s.Equal([]string{"foo.com", "bar.com"}, got.PoliciesAllowedHostnames) }) s.Run("clear policy allowed hostnames", func() { - got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{}, nil) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{}, nil, nil) s.NoError(err) s.Equal([]string{}, got.PoliciesAllowedHostnames) }) s.Run("but not passing a value doesn't clear the hostnames value", func() { - got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{"foo.com", "bar.com"}, nil) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{"foo.com", "bar.com"}, nil, nil) s.NoError(err) s.Equal([]string{"foo.com", "bar.com"}, got.PoliciesAllowedHostnames) - got, err = s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, nil, nil) + got, err = s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, nil, nil, nil) s.NoError(err) s.Equal([]string{"foo.com", "bar.com"}, got.PoliciesAllowedHostnames) }) diff --git a/app/controlplane/pkg/biz/workflow_integration_test.go b/app/controlplane/pkg/biz/workflow_integration_test.go index c58aa648a..5bc303f00 100644 --- a/app/controlplane/pkg/biz/workflow_integration_test.go +++ b/app/controlplane/pkg/biz/workflow_integration_test.go @@ -187,7 +187,7 @@ func (s *workflowIntegrationTestSuite) TestCreate() { // Enable implicit workflow creation prevention for testing orgID, _ := uuid.Parse(s.org.ID) - _, err = s.Repos.OrganizationRepo.Update(ctx, orgID, nil, nil, toPtrBool(true)) + _, err = s.Repos.OrganizationRepo.Update(ctx, orgID, nil, nil, toPtrBool(true), nil) s.Require().NoError(err) for _, tc := range testCases {