diff --git a/app/cli/cmd/organization_update.go b/app/cli/cmd/organization_update.go index cd7ab368d..cc2306fd6 100644 --- a/app/cli/cmd/organization_update.go +++ b/app/cli/cmd/organization_update.go @@ -22,9 +22,10 @@ import ( func newOrganizationUpdateCmd() *cobra.Command { var ( - orgName string - blockOnPolicyViolation bool - policiesAllowedHostnames []string + orgName string + blockOnPolicyViolation bool + policiesAllowedHostnames []string + preventImplicitWorkflowCreation bool ) cmd := &cobra.Command{ @@ -40,6 +41,10 @@ func newOrganizationUpdateCmd() *cobra.Command { opts.PoliciesAllowedHostnames = &policiesAllowedHostnames } + if cmd.Flags().Changed("prevent-implicit-workflow-creation") { + opts.PreventImplicitWorkflowCreation = &preventImplicitWorkflowCreation + } + _, err := action.NewOrgUpdate(ActionOpts).Run(cmd.Context(), orgName, opts) if err != nil { return err @@ -56,5 +61,6 @@ func newOrganizationUpdateCmd() *cobra.Command { cmd.Flags().BoolVar(&blockOnPolicyViolation, "block", false, "set the default policy violation blocking strategy") cmd.Flags().StringSliceVar(&policiesAllowedHostnames, "policies-allowed-hostnames", []string{}, "set the allowed hostnames for the policy engine") + cmd.Flags().BoolVar(&preventImplicitWorkflowCreation, "prevent-implicit-workflow-creation", false, "prevent workflows and projects from being created implicitly during attestation init") return cmd } diff --git a/app/cli/documentation/cli-reference.mdx b/app/cli/documentation/cli-reference.mdx index d1a636aaf..db6c70a28 100755 --- a/app/cli/documentation/cli-reference.mdx +++ b/app/cli/documentation/cli-reference.mdx @@ -2765,6 +2765,7 @@ Options -h, --help help for update --name string organization name --policies-allowed-hostnames strings set the allowed hostnames for the policy engine +--prevent-implicit-workflow-creation prevent workflows and projects from being created implicitly during attestation init ``` Options inherited from parent commands diff --git a/app/cli/pkg/action/config_current_context.go b/app/cli/pkg/action/config_current_context.go index ae01954bf..16cf9d16c 100644 --- a/app/cli/pkg/action/config_current_context.go +++ b/app/cli/pkg/action/config_current_context.go @@ -31,14 +31,17 @@ func NewConfigCurrentContext(cfg *ActionsOpts) *ConfigCurrentContext { } type ConfigContextItem struct { - CurrentUser *UserItem - CurrentMembership *MembershipItem - CurrentCASBackend *CASBackendItem + CurrentUser *UserItem `json:"currentUser"` + CurrentMembership *MembershipItem `json:"currentMembership"` + CurrentCASBackend *CASBackendItem `json:"currentCASBackend"` } type UserItem struct { - ID, Email, FirstName, LastName string - CreatedAt *time.Time + ID string `json:"id"` + Email string `json:"email"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + CreatedAt *time.Time `json:"createdAt"` } // PrintUserProfileWithEmail formats the user's profile with their email. diff --git a/app/cli/pkg/action/membership_list.go b/app/cli/pkg/action/membership_list.go index 120ae61f0..b113ac92f 100644 --- a/app/cli/pkg/action/membership_list.go +++ b/app/cli/pkg/action/membership_list.go @@ -29,10 +29,12 @@ type MembershipList struct { } type OrgItem struct { - ID, Name string - CreatedAt *time.Time - PolicyViolationBlockingStrategy string - PolicyAllowedHostnames []string `json:"policyAllowedHostnames,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + CreatedAt *time.Time `json:"createdAt"` + PolicyViolationBlockingStrategy string `json:"policyViolationBlockingStrategy"` + PolicyAllowedHostnames []string `json:"policyAllowedHostnames,omitempty"` + PreventImplicitWorkflowCreation bool `json:"preventImplicitWorkflowCreation"` } type MembershipItem struct { @@ -40,9 +42,9 @@ type MembershipItem struct { Default bool `json:"current"` CreatedAt *time.Time `json:"joinedAt"` UpdatedAt *time.Time `json:"updatedAt"` - Org *OrgItem - User *UserItem - Role Role `json:"role"` + Org *OrgItem `json:"org"` + User *UserItem `json:"user"` + Role Role `json:"role"` } type ListMembersOpts struct { @@ -130,10 +132,11 @@ func (action *MembershipList) ListMembers(ctx context.Context, page int, pageSiz func pbOrgItemToAction(in *pb.OrgItem) *OrgItem { i := &OrgItem{ - ID: in.Id, - Name: in.Name, - CreatedAt: toTimePtr(in.CreatedAt.AsTime()), - PolicyAllowedHostnames: in.PolicyAllowedHostnames, + ID: in.Id, + Name: in.Name, + CreatedAt: toTimePtr(in.CreatedAt.AsTime()), + PolicyAllowedHostnames: in.PolicyAllowedHostnames, + PreventImplicitWorkflowCreation: in.PreventImplicitWorkflowCreation, } if in.DefaultPolicyViolationStrategy == pb.OrgItem_POLICY_VIOLATION_BLOCKING_STRATEGY_BLOCK { diff --git a/app/cli/pkg/action/org_update.go b/app/cli/pkg/action/org_update.go index 61e883681..9e344711e 100644 --- a/app/cli/pkg/action/org_update.go +++ b/app/cli/pkg/action/org_update.go @@ -30,16 +30,18 @@ func NewOrgUpdate(cfg *ActionsOpts) *OrgUpdate { } type NewOrgUpdateOpts struct { - BlockOnPolicyViolation *bool - PoliciesAllowedHostnames *[]string + BlockOnPolicyViolation *bool + PoliciesAllowedHostnames *[]string + PreventImplicitWorkflowCreation *bool } func (action *OrgUpdate) Run(ctx context.Context, name string, opts *NewOrgUpdateOpts) (*OrgItem, error) { client := pb.NewOrganizationServiceClient(action.cfg.CPConnection) payload := &pb.OrganizationServiceUpdateRequest{ - Name: name, - BlockOnPolicyViolation: opts.BlockOnPolicyViolation, + Name: name, + BlockOnPolicyViolation: opts.BlockOnPolicyViolation, + PreventImplicitWorkflowCreation: opts.PreventImplicitWorkflowCreation, } if opts.PoliciesAllowedHostnames != nil { diff --git a/app/controlplane/api/controlplane/v1/organization.pb.go b/app/controlplane/api/controlplane/v1/organization.pb.go index ca4d311fb..6522e4c56 100644 --- a/app/controlplane/api/controlplane/v1/organization.pb.go +++ b/app/controlplane/api/controlplane/v1/organization.pb.go @@ -469,6 +469,8 @@ type OrganizationServiceUpdateRequest struct { // flag that allows us to detect if the value is explicitly set // since repeated fields can not be optional 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"` } func (x *OrganizationServiceUpdateRequest) Reset() { @@ -531,6 +533,13 @@ func (x *OrganizationServiceUpdateRequest) GetUpdatePoliciesAllowedHostnames() b return false } +func (x *OrganizationServiceUpdateRequest) GetPreventImplicitWorkflowCreation() bool { + if x != nil && x.PreventImplicitWorkflowCreation != nil { + return *x.PreventImplicitWorkflowCreation + } + return false +} + type OrganizationServiceUpdateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -743,7 +752,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, 0xa6, 0x02, 0x0a, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x73, 0x75, 0x6c, 0x74, 0x22, 0x9f, 0x03, 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, @@ -759,76 +768,84 @@ var file_controlplane_v1_organization_proto_rawDesc = []byte{ 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 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, 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, 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, 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, + 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, + 0x50, 0x0a, 0x22, 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, 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, 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, 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, + 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, 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, + 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, + 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, + 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, 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, 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, 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, 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, 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 2637d3c2f..59533dc21 100644 --- a/app/controlplane/api/controlplane/v1/organization.proto +++ b/app/controlplane/api/controlplane/v1/organization.proto @@ -93,6 +93,9 @@ message OrganizationServiceUpdateRequest { // flag that allows us to detect if the value is explicitly set // since repeated fields can not be optional bool update_policies_allowed_hostnames = 4; + + // prevent workflows and projects from being created implicitly during attestation init + optional bool prevent_implicit_workflow_creation = 5; } 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 19ca21d33..88b9eef98 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.pb.go +++ b/app/controlplane/api/controlplane/v1/response_messages.pb.go @@ -1855,6 +1855,8 @@ type OrgItem struct { UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` DefaultPolicyViolationStrategy OrgItem_PolicyViolationBlockingStrategy `protobuf:"varint,4,opt,name=default_policy_violation_strategy,json=defaultPolicyViolationStrategy,proto3,enum=controlplane.v1.OrgItem_PolicyViolationBlockingStrategy" json:"default_policy_violation_strategy,omitempty"` 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"` } func (x *OrgItem) Reset() { @@ -1931,6 +1933,13 @@ func (x *OrgItem) GetPolicyAllowedHostnames() []string { return nil } +func (x *OrgItem) GetPreventImplicitWorkflowCreation() bool { + if x != nil { + return x.PreventImplicitWorkflowCreation + } + return false +} + type CASBackendItem struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2921,7 +2930,7 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 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, 0x9a, 0x04, 0x0a, 0x07, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, + 0x72, 0x6f, 0x6c, 0x65, 0x22, 0xe7, 0x04, 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, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, @@ -2943,155 +2952,160 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 0x12, 0x38, 0x0a, 0x18, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, - 0x64, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 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, + 0x64, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x22, 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, + 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, 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, + 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, 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, + 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, 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, 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, + 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, + 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, 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, + 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 56e0f90c9..b71518648 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.proto +++ b/app/controlplane/api/controlplane/v1/response_messages.proto @@ -266,6 +266,8 @@ message OrgItem { google.protobuf.Timestamp updated_at = 6; PolicyViolationBlockingStrategy default_policy_violation_strategy = 4; repeated string policy_allowed_hostnames = 5; + // prevent workflows and projects from being created implicitly during attestation init + bool prevent_implicit_workflow_creation = 7; 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 bed45bdb1..aecd08468 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/organization.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/organization.ts @@ -76,6 +76,8 @@ export interface OrganizationServiceUpdateRequest { * since repeated fields can not be optional */ updatePoliciesAllowedHostnames: boolean; + /** prevent workflows and projects from being created implicitly during attestation init */ + preventImplicitWorkflowCreation?: boolean | undefined; } export interface OrganizationServiceUpdateResponse { @@ -663,6 +665,7 @@ function createBaseOrganizationServiceUpdateRequest(): OrganizationServiceUpdate blockOnPolicyViolation: undefined, policiesAllowedHostnames: [], updatePoliciesAllowedHostnames: false, + preventImplicitWorkflowCreation: undefined, }; } @@ -680,6 +683,9 @@ export const OrganizationServiceUpdateRequest = { if (message.updatePoliciesAllowedHostnames === true) { writer.uint32(32).bool(message.updatePoliciesAllowedHostnames); } + if (message.preventImplicitWorkflowCreation !== undefined) { + writer.uint32(40).bool(message.preventImplicitWorkflowCreation); + } return writer; }, @@ -718,6 +724,13 @@ export const OrganizationServiceUpdateRequest = { message.updatePoliciesAllowedHostnames = reader.bool(); continue; + case 5: + if (tag !== 40) { + break; + } + + message.preventImplicitWorkflowCreation = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -737,6 +750,9 @@ export const OrganizationServiceUpdateRequest = { updatePoliciesAllowedHostnames: isSet(object.updatePoliciesAllowedHostnames) ? Boolean(object.updatePoliciesAllowedHostnames) : false, + preventImplicitWorkflowCreation: isSet(object.preventImplicitWorkflowCreation) + ? Boolean(object.preventImplicitWorkflowCreation) + : undefined, }; }, @@ -751,6 +767,8 @@ export const OrganizationServiceUpdateRequest = { } message.updatePoliciesAllowedHostnames !== undefined && (obj.updatePoliciesAllowedHostnames = message.updatePoliciesAllowedHostnames); + message.preventImplicitWorkflowCreation !== undefined && + (obj.preventImplicitWorkflowCreation = message.preventImplicitWorkflowCreation); return obj; }, @@ -768,6 +786,7 @@ export const OrganizationServiceUpdateRequest = { message.blockOnPolicyViolation = object.blockOnPolicyViolation ?? undefined; message.policiesAllowedHostnames = object.policiesAllowedHostnames?.map((e) => e) || []; message.updatePoliciesAllowedHostnames = object.updatePoliciesAllowedHostnames ?? false; + message.preventImplicitWorkflowCreation = object.preventImplicitWorkflowCreation ?? 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 473318dad..8181c0ef8 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts @@ -558,6 +558,8 @@ export interface OrgItem { updatedAt?: Date; defaultPolicyViolationStrategy: OrgItem_PolicyViolationBlockingStrategy; policyAllowedHostnames: string[]; + /** prevent workflows and projects from being created implicitly during attestation init */ + preventImplicitWorkflowCreation: boolean; } export enum OrgItem_PolicyViolationBlockingStrategy { @@ -3670,6 +3672,7 @@ function createBaseOrgItem(): OrgItem { updatedAt: undefined, defaultPolicyViolationStrategy: 0, policyAllowedHostnames: [], + preventImplicitWorkflowCreation: false, }; } @@ -3693,6 +3696,9 @@ export const OrgItem = { for (const v of message.policyAllowedHostnames) { writer.uint32(42).string(v!); } + if (message.preventImplicitWorkflowCreation === true) { + writer.uint32(56).bool(message.preventImplicitWorkflowCreation); + } return writer; }, @@ -3745,6 +3751,13 @@ export const OrgItem = { message.policyAllowedHostnames.push(reader.string()); continue; + case 7: + if (tag !== 56) { + break; + } + + message.preventImplicitWorkflowCreation = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -3766,6 +3779,9 @@ export const OrgItem = { policyAllowedHostnames: Array.isArray(object?.policyAllowedHostnames) ? object.policyAllowedHostnames.map((e: any) => String(e)) : [], + preventImplicitWorkflowCreation: isSet(object.preventImplicitWorkflowCreation) + ? Boolean(object.preventImplicitWorkflowCreation) + : false, }; }, @@ -3784,6 +3800,8 @@ export const OrgItem = { } else { obj.policyAllowedHostnames = []; } + message.preventImplicitWorkflowCreation !== undefined && + (obj.preventImplicitWorkflowCreation = message.preventImplicitWorkflowCreation); return obj; }, @@ -3799,6 +3817,7 @@ export const OrgItem = { message.updatedAt = object.updatedAt ?? undefined; message.defaultPolicyViolationStrategy = object.defaultPolicyViolationStrategy ?? 0; message.policyAllowedHostnames = object.policyAllowedHostnames?.map((e) => e) || []; + message.preventImplicitWorkflowCreation = object.preventImplicitWorkflowCreation ?? 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 b3142d742..0a179c3b7 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.jsonschema.json @@ -30,6 +30,10 @@ }, "type": "array" }, + "^(prevent_implicit_workflow_creation)$": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "type": "boolean" + }, "^(updated_at)$": { "$ref": "google.protobuf.Timestamp.jsonschema.json" } @@ -68,6 +72,10 @@ }, "type": "array" }, + "preventImplicitWorkflowCreation": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "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 1dcd00f8d..ec7cd08c4 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrgItem.schema.json @@ -30,6 +30,10 @@ }, "type": "array" }, + "^(preventImplicitWorkflowCreation)$": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "type": "boolean" + }, "^(updatedAt)$": { "$ref": "google.protobuf.Timestamp.schema.json" } @@ -68,6 +72,10 @@ }, "type": "array" }, + "prevent_implicit_workflow_creation": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "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 373993734..feebca398 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.jsonschema.json @@ -14,6 +14,10 @@ }, "type": "array" }, + "^(prevent_implicit_workflow_creation)$": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "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" @@ -35,6 +39,10 @@ }, "type": "array" }, + "preventImplicitWorkflowCreation": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "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 8d4a99644..346b7f3a9 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.OrganizationServiceUpdateRequest.schema.json @@ -14,6 +14,10 @@ }, "type": "array" }, + "^(preventImplicitWorkflowCreation)$": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "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" @@ -35,6 +39,10 @@ }, "type": "array" }, + "prevent_implicit_workflow_creation": { + "description": "prevent workflows and projects from being created implicitly during attestation init", + "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 a18514605..27003cd93 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -133,7 +133,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l return nil, nil, err } workflowContractUseCase := biz.NewWorkflowContractUseCase(workflowContractRepo, registry, auditorUseCase, logger) - workflowUseCase := biz.NewWorkflowUsecase(workflowRepo, projectsRepo, workflowContractUseCase, auditorUseCase, membershipUseCase, logger) + workflowUseCase := biz.NewWorkflowUsecase(workflowRepo, projectsRepo, workflowContractUseCase, auditorUseCase, membershipUseCase, organizationRepo, logger) orgInvitationRepo := data.NewOrgInvitation(dataData, logger) orgInvitationUseCase, err := biz.NewOrgInvitationUseCase(orgInvitationRepo, membershipRepo, userRepo, auditorUseCase, groupRepo, projectsRepo, logger) if err != nil { diff --git a/app/controlplane/internal/service/attestation.go b/app/controlplane/internal/service/attestation.go index ec886c53a..a787007d9 100644 --- a/app/controlplane/internal/service/attestation.go +++ b/app/controlplane/internal/service/attestation.go @@ -749,11 +749,12 @@ func (s *AttestationService) FindOrCreateWorkflow(ctx context.Context, req *cpAP // the workflow does not exist, let's create it alongside its project and contract createOpts := &biz.WorkflowCreateOpts{ - OrgID: apiToken.OrgID, - Name: req.GetWorkflowName(), - Project: req.GetProjectName(), - ContractName: req.GetContractName(), - ContractBytes: req.GetContractBytes(), + OrgID: apiToken.OrgID, + Name: req.GetWorkflowName(), + Project: req.GetProjectName(), + ContractName: req.GetContractName(), + ContractBytes: req.GetContractBytes(), + ImplicitCreation: true, // Mark as implicit creation from attestation init } // set project owner if RBAC is enabled @@ -768,6 +769,10 @@ func (s *AttestationService) FindOrCreateWorkflow(ctx context.Context, req *cpAP wf, err := s.workflowUseCase.Create(ctx, createOpts) if err != nil { + if errors.Is(err, biz.ErrImplicitWorkflowCreationDisabled) { + return nil, errors.Forbidden("forbidden", "creating workflows during the attestation process is disabled for this organization. Please create them in advance or contact your administrator") + } + return nil, handleUseCaseErr(fmt.Errorf("failed to initialize the attestation: %w", err), s.log) } diff --git a/app/controlplane/internal/service/context.go b/app/controlplane/internal/service/context.go index 021e768ca..3764f9d02 100644 --- a/app/controlplane/internal/service/context.go +++ b/app/controlplane/internal/service/context.go @@ -118,9 +118,10 @@ func (s *ContextService) Current(ctx context.Context, _ *pb.ContextServiceCurren func bizOrgToPb(m *biz.Organization) *pb.OrgItem { return &pb.OrgItem{Id: m.ID, Name: m.Name, CreatedAt: timestamppb.New(*m.CreatedAt), - UpdatedAt: timestamppb.New(*m.UpdatedAt), - DefaultPolicyViolationStrategy: bizPolicyViolationBlockingStrategyToPb(m.BlockOnPolicyViolation), - PolicyAllowedHostnames: m.PoliciesAllowedHostnames, + UpdatedAt: timestamppb.New(*m.UpdatedAt), + DefaultPolicyViolationStrategy: bizPolicyViolationBlockingStrategyToPb(m.BlockOnPolicyViolation), + PolicyAllowedHostnames: m.PoliciesAllowedHostnames, + PreventImplicitWorkflowCreation: m.PreventImplicitWorkflowCreation, } } diff --git a/app/controlplane/internal/service/organization.go b/app/controlplane/internal/service/organization.go index 72f24f3ae..e5711368c 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) + org, err := s.orgUC.Update(ctx, currentUser.ID, req.Name, req.BlockOnPolicyViolation, policiesAllowedHostnames, req.PreventImplicitWorkflowCreation) if err != nil { return nil, handleUseCaseErr(err, s.log) } diff --git a/app/controlplane/pkg/biz/.mockery.yml b/app/controlplane/pkg/biz/.mockery.yml index 103d2e709..66fa4bb34 100644 --- a/app/controlplane/pkg/biz/.mockery.yml +++ b/app/controlplane/pkg/biz/.mockery.yml @@ -1,18 +1,19 @@ all: false -dir: '{{.InterfaceDir}}' +dir: "{{.InterfaceDir}}" filename: mocks_test.go force-file-write: true formatter: goimports include-auto-generated: false log-level: info -structname: '{{.Mock}}{{.InterfaceName}}' -pkgname: '{{.SrcPackageName}}' +structname: "{{.Mock}}{{.InterfaceName}}" +pkgname: "{{.SrcPackageName}}" recursive: false require-template-schema-exists: true template: testify -template-schema: '{{.Template}}.schema.json' +template-schema: "{{.Template}}.schema.json" packages: github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz: interfaces: APITokenRepo: CASBackendRepo: + OrganizationRepo: diff --git a/app/controlplane/pkg/biz/mocks/OrganizationRepo.go b/app/controlplane/pkg/biz/mocks/OrganizationRepo.go index dad418d6b..d747b8c50 100644 --- a/app/controlplane/pkg/biz/mocks/OrganizationRepo.go +++ b/app/controlplane/pkg/biz/mocks/OrganizationRepo.go @@ -125,9 +125,9 @@ func (_m *OrganizationRepo) FindByName(ctx context.Context, name string) (*biz.O return r0, r1 } -// Update provides a mock function with given fields: ctx, id, blockOnPolicyViolation, policiesAllowedHostnames -func (_m *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string) (*biz.Organization, error) { - ret := _m.Called(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames) +// Update provides a mock function with given fields: ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation +func (_m *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*biz.Organization, error) { + ret := _m.Called(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) if len(ret) == 0 { panic("no return value specified for Update") @@ -135,19 +135,19 @@ func (_m *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPol var r0 *biz.Organization var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string) (*biz.Organization, error)); ok { - return rf(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames) + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool) (*biz.Organization, error)); ok { + return rf(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) } - if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string) *biz.Organization); ok { - r0 = rf(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames) + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool) *biz.Organization); ok { + r0 = rf(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*biz.Organization) } } - if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID, *bool, []string) error); ok { - r1 = rf(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames) + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID, *bool, []string, *bool) error); ok { + r1 = rf(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) } else { r1 = ret.Error(1) } diff --git a/app/controlplane/pkg/biz/mocks_test.go b/app/controlplane/pkg/biz/mocks_test.go index b93ff9392..c8d5865a3 100644 --- a/app/controlplane/pkg/biz/mocks_test.go +++ b/app/controlplane/pkg/biz/mocks_test.go @@ -1443,3 +1443,377 @@ func (_c *MockCASBackendRepo_UpdateValidationStatus_Call) RunAndReturn(run func( _c.Call.Return(run) return _c } + +// NewMockOrganizationRepo creates a new instance of MockOrganizationRepo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockOrganizationRepo(t interface { + mock.TestingT + Cleanup(func()) +}) *MockOrganizationRepo { + mock := &MockOrganizationRepo{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} + +// MockOrganizationRepo is an autogenerated mock type for the OrganizationRepo type +type MockOrganizationRepo struct { + mock.Mock +} + +type MockOrganizationRepo_Expecter struct { + mock *mock.Mock +} + +func (_m *MockOrganizationRepo) EXPECT() *MockOrganizationRepo_Expecter { + return &MockOrganizationRepo_Expecter{mock: &_m.Mock} +} + +// Create provides a mock function for the type MockOrganizationRepo +func (_mock *MockOrganizationRepo) Create(ctx context.Context, name string) (*Organization, error) { + ret := _mock.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 *Organization + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string) (*Organization, error)); ok { + return returnFunc(ctx, name) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string) *Organization); ok { + r0 = returnFunc(ctx, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*Organization) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = returnFunc(ctx, name) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockOrganizationRepo_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' +type MockOrganizationRepo_Create_Call struct { + *mock.Call +} + +// Create is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockOrganizationRepo_Expecter) Create(ctx interface{}, name interface{}) *MockOrganizationRepo_Create_Call { + return &MockOrganizationRepo_Create_Call{Call: _e.mock.On("Create", ctx, name)} +} + +func (_c *MockOrganizationRepo_Create_Call) Run(run func(ctx context.Context, name string)) *MockOrganizationRepo_Create_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockOrganizationRepo_Create_Call) Return(organization *Organization, err error) *MockOrganizationRepo_Create_Call { + _c.Call.Return(organization, err) + return _c +} + +func (_c *MockOrganizationRepo_Create_Call) RunAndReturn(run func(ctx context.Context, name string) (*Organization, error)) *MockOrganizationRepo_Create_Call { + _c.Call.Return(run) + return _c +} + +// Delete provides a mock function for the type MockOrganizationRepo +func (_mock *MockOrganizationRepo) Delete(ctx context.Context, ID uuid.UUID) error { + ret := _mock.Called(ctx, ID) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID) error); ok { + r0 = returnFunc(ctx, ID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockOrganizationRepo_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' +type MockOrganizationRepo_Delete_Call struct { + *mock.Call +} + +// Delete is a helper method to define mock.On call +// - ctx context.Context +// - ID uuid.UUID +func (_e *MockOrganizationRepo_Expecter) Delete(ctx interface{}, ID interface{}) *MockOrganizationRepo_Delete_Call { + return &MockOrganizationRepo_Delete_Call{Call: _e.mock.On("Delete", ctx, ID)} +} + +func (_c *MockOrganizationRepo_Delete_Call) Run(run func(ctx context.Context, ID uuid.UUID)) *MockOrganizationRepo_Delete_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 uuid.UUID + if args[1] != nil { + arg1 = args[1].(uuid.UUID) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockOrganizationRepo_Delete_Call) Return(err error) *MockOrganizationRepo_Delete_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockOrganizationRepo_Delete_Call) RunAndReturn(run func(ctx context.Context, ID uuid.UUID) error) *MockOrganizationRepo_Delete_Call { + _c.Call.Return(run) + return _c +} + +// FindByID provides a mock function for the type MockOrganizationRepo +func (_mock *MockOrganizationRepo) FindByID(ctx context.Context, orgID uuid.UUID) (*Organization, error) { + ret := _mock.Called(ctx, orgID) + + if len(ret) == 0 { + panic("no return value specified for FindByID") + } + + var r0 *Organization + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID) (*Organization, error)); ok { + return returnFunc(ctx, orgID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID) *Organization); ok { + r0 = returnFunc(ctx, orgID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*Organization) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok { + r1 = returnFunc(ctx, orgID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockOrganizationRepo_FindByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindByID' +type MockOrganizationRepo_FindByID_Call struct { + *mock.Call +} + +// FindByID is a helper method to define mock.On call +// - ctx context.Context +// - orgID uuid.UUID +func (_e *MockOrganizationRepo_Expecter) FindByID(ctx interface{}, orgID interface{}) *MockOrganizationRepo_FindByID_Call { + return &MockOrganizationRepo_FindByID_Call{Call: _e.mock.On("FindByID", ctx, orgID)} +} + +func (_c *MockOrganizationRepo_FindByID_Call) Run(run func(ctx context.Context, orgID uuid.UUID)) *MockOrganizationRepo_FindByID_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 uuid.UUID + if args[1] != nil { + arg1 = args[1].(uuid.UUID) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockOrganizationRepo_FindByID_Call) Return(organization *Organization, err error) *MockOrganizationRepo_FindByID_Call { + _c.Call.Return(organization, err) + return _c +} + +func (_c *MockOrganizationRepo_FindByID_Call) RunAndReturn(run func(ctx context.Context, orgID uuid.UUID) (*Organization, error)) *MockOrganizationRepo_FindByID_Call { + _c.Call.Return(run) + return _c +} + +// FindByName provides a mock function for the type MockOrganizationRepo +func (_mock *MockOrganizationRepo) FindByName(ctx context.Context, name string) (*Organization, error) { + ret := _mock.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for FindByName") + } + + var r0 *Organization + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string) (*Organization, error)); ok { + return returnFunc(ctx, name) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string) *Organization); ok { + r0 = returnFunc(ctx, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*Organization) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = returnFunc(ctx, name) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockOrganizationRepo_FindByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindByName' +type MockOrganizationRepo_FindByName_Call struct { + *mock.Call +} + +// FindByName is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockOrganizationRepo_Expecter) FindByName(ctx interface{}, name interface{}) *MockOrganizationRepo_FindByName_Call { + return &MockOrganizationRepo_FindByName_Call{Call: _e.mock.On("FindByName", ctx, name)} +} + +func (_c *MockOrganizationRepo_FindByName_Call) Run(run func(ctx context.Context, name string)) *MockOrganizationRepo_FindByName_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockOrganizationRepo_FindByName_Call) Return(organization *Organization, err error) *MockOrganizationRepo_FindByName_Call { + _c.Call.Return(organization, err) + return _c +} + +func (_c *MockOrganizationRepo_FindByName_Call) RunAndReturn(run func(ctx context.Context, name string) (*Organization, error)) *MockOrganizationRepo_FindByName_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function for the type MockOrganizationRepo +func (_mock *MockOrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*Organization, error) { + ret := _mock.Called(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 *Organization + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool) (*Organization, error)); ok { + return returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, *bool, []string, *bool) *Organization); ok { + r0 = returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*Organization) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, uuid.UUID, *bool, []string, *bool) error); ok { + r1 = returnFunc(ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockOrganizationRepo_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type MockOrganizationRepo_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - id uuid.UUID +// - blockOnPolicyViolation *bool +// - policiesAllowedHostnames []string +// - preventImplicitWorkflowCreation *bool +func (_e *MockOrganizationRepo_Expecter) Update(ctx interface{}, id interface{}, blockOnPolicyViolation interface{}, policiesAllowedHostnames interface{}, preventImplicitWorkflowCreation interface{}) *MockOrganizationRepo_Update_Call { + return &MockOrganizationRepo_Update_Call{Call: _e.mock.On("Update", ctx, id, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation)} +} + +func (_c *MockOrganizationRepo_Update_Call) Run(run func(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool)) *MockOrganizationRepo_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 uuid.UUID + if args[1] != nil { + arg1 = args[1].(uuid.UUID) + } + var arg2 *bool + if args[2] != nil { + arg2 = args[2].(*bool) + } + var arg3 []string + if args[3] != nil { + arg3 = args[3].([]string) + } + var arg4 *bool + if args[4] != nil { + arg4 = args[4].(*bool) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *MockOrganizationRepo_Update_Call) Return(organization *Organization, err error) *MockOrganizationRepo_Update_Call { + _c.Call.Return(organization, err) + return _c +} + +func (_c *MockOrganizationRepo_Update_Call) RunAndReturn(run func(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*Organization, error)) *MockOrganizationRepo_Update_Call { + _c.Call.Return(run) + return _c +} diff --git a/app/controlplane/pkg/biz/organization.go b/app/controlplane/pkg/biz/organization.go index 12a4f9eda..1787b14cf 100644 --- a/app/controlplane/pkg/biz/organization.go +++ b/app/controlplane/pkg/biz/organization.go @@ -39,13 +39,15 @@ type Organization struct { BlockOnPolicyViolation bool // PoliciesAllowedHostnames is an array of hostnames that are allowed to be used in the policies PoliciesAllowedHostnames []string + // PreventImplicitWorkflowCreation prevents workflows and projects from being created implicitly during attestation init + PreventImplicitWorkflowCreation 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) (*Organization, error) + Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*Organization, error) Delete(ctx context.Context, ID uuid.UUID) error } @@ -185,7 +187,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) (*Organization, error) { +func (uc *OrganizationUseCase) Update(ctx context.Context, userID, orgName string, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*Organization, error) { userUUID, err := uuid.Parse(userID) if err != nil { return nil, NewErrInvalidUUID(err) @@ -196,7 +198,7 @@ func (uc *OrganizationUseCase) Update(ctx context.Context, userID, orgName strin if err != nil { return nil, fmt.Errorf("failed to find memberships: %w", err) } else if membership == nil { - return nil, NewErrNotFound("organization") + return nil, NewErrNotFound("membership") } orgUUID, err := uuid.Parse(membership.Org.ID) @@ -205,7 +207,7 @@ func (uc *OrganizationUseCase) Update(ctx context.Context, userID, orgName strin } // Perform the update - org, err := uc.orgRepo.Update(ctx, orgUUID, blockOnPolicyViolation, policiesAllowedHostnames) + org, err := uc.orgRepo.Update(ctx, orgUUID, blockOnPolicyViolation, policiesAllowedHostnames, preventImplicitWorkflowCreation) if err != nil { return nil, fmt.Errorf("failed to update organization: %w", err) } else if org == nil { diff --git a/app/controlplane/pkg/biz/organization_integration_test.go b/app/controlplane/pkg/biz/organization_integration_test.go index 2471f6a4d..2337df5b3 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) + _, err := s.Organization.Update(ctx, s.user.ID, uuid.NewString(), 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) + _, err = s.Organization.Update(ctx, s.user.ID, org2.Name, 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) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, toPtrBool(true), 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"}) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{"foo.com", "bar.com"}, 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{}) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{}, 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"}) + got, err := s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, []string{"foo.com", "bar.com"}, 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) + got, err = s.Organization.Update(ctx, s.user.ID, s.org.Name, nil, nil, nil) s.NoError(err) s.Equal([]string{"foo.com", "bar.com"}, got.PoliciesAllowedHostnames) }) diff --git a/app/controlplane/pkg/biz/organization_test.go b/app/controlplane/pkg/biz/organization_test.go index 4162c12f8..2bbf161bc 100644 --- a/app/controlplane/pkg/biz/organization_test.go +++ b/app/controlplane/pkg/biz/organization_test.go @@ -21,7 +21,6 @@ import ( "testing" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" - repoM "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/mocks" "github.com/go-kratos/kratos/v2/log" "github.com/google/uuid" "github.com/stretchr/testify/mock" @@ -33,7 +32,7 @@ type organizationTestSuite struct { } func (s *organizationTestSuite) TestCreateWithRandomName() { - repo := repoM.NewOrganizationRepo(s.T()) + repo := biz.NewMockOrganizationRepo(s.T()) l := log.NewStdLogger(io.Discard) uc := biz.NewOrganizationUseCase(repo, nil, biz.NewAuditorUseCase(nil, l), nil, nil, nil, l) diff --git a/app/controlplane/pkg/biz/testhelpers/wire_gen.go b/app/controlplane/pkg/biz/testhelpers/wire_gen.go index a9fbb8d0e..0d4838b0b 100644 --- a/app/controlplane/pkg/biz/testhelpers/wire_gen.go +++ b/app/controlplane/pkg/biz/testhelpers/wire_gen.go @@ -82,7 +82,7 @@ func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, r } workflowContractUseCase := biz.NewWorkflowContractUseCase(workflowContractRepo, registry, auditorUseCase, logger) projectsRepo := data.NewProjectsRepo(dataData, logger) - workflowUseCase := biz.NewWorkflowUsecase(workflowRepo, projectsRepo, workflowContractUseCase, auditorUseCase, membershipUseCase, logger) + workflowUseCase := biz.NewWorkflowUsecase(workflowRepo, projectsRepo, workflowContractUseCase, auditorUseCase, membershipUseCase, organizationRepo, logger) workflowRunRepo := data.NewWorkflowRunRepo(dataData, logger) signingUseCase, err := biz.NewChainloopSigningUseCase(bootstrap, logger) if err != nil { diff --git a/app/controlplane/pkg/biz/workflow.go b/app/controlplane/pkg/biz/workflow.go index 149b6d93c..60d53b8dc 100644 --- a/app/controlplane/pkg/biz/workflow.go +++ b/app/controlplane/pkg/biz/workflow.go @@ -79,6 +79,8 @@ type WorkflowCreateOpts struct { // Owner identifies the user to be marked as owner of the project Owner *uuid.UUID + // ImplicitCreation indicates whether this workflow is being created implicitly via attestation init + ImplicitCreation bool } type WorkflowUpdateOpts struct { @@ -117,19 +119,24 @@ type WorkflowUseCase struct { contractUC *WorkflowContractUseCase auditorUC *AuditorUseCase membershipUC *MembershipUseCase + orgRepo OrganizationRepo logger *log.Helper } -func NewWorkflowUsecase(wfr WorkflowRepo, projectsRepo ProjectsRepo, schemaUC *WorkflowContractUseCase, auditorUC *AuditorUseCase, membershipUC *MembershipUseCase, logger log.Logger) *WorkflowUseCase { - return &WorkflowUseCase{wfRepo: wfr, contractUC: schemaUC, projectRepo: projectsRepo, auditorUC: auditorUC, membershipUC: membershipUC, logger: log.NewHelper(logger)} +var ErrImplicitWorkflowCreationDisabled = errors.New("implicit workflow and project creation is disabled for this organization") + +func NewWorkflowUsecase(wfr WorkflowRepo, projectsRepo ProjectsRepo, schemaUC *WorkflowContractUseCase, auditorUC *AuditorUseCase, membershipUC *MembershipUseCase, orgRepo OrganizationRepo, logger log.Logger) *WorkflowUseCase { + return &WorkflowUseCase{wfRepo: wfr, contractUC: schemaUC, projectRepo: projectsRepo, auditorUC: auditorUC, membershipUC: membershipUC, orgRepo: orgRepo, logger: log.NewHelper(logger)} } func (uc *WorkflowUseCase) Create(ctx context.Context, opts *WorkflowCreateOpts) (*Workflow, error) { if opts.Name == "" { return nil, errors.New("workflow name is required") - } else if opts.Project == "" { + } + if opts.Project == "" { return nil, errors.New("project name is required") - } else if opts.OrgID == "" { + } + if opts.OrgID == "" { return nil, errors.New("organization ID is required") } @@ -166,6 +173,21 @@ func (uc *WorkflowUseCase) Create(ctx context.Context, opts *WorkflowCreateOpts) return nil, fmt.Errorf("failed to parse org ID %q: %w", opts.OrgID, err) } + // Check if implicit creation is prevented by organization settings + if opts.ImplicitCreation { + org, err := uc.orgRepo.FindByID(ctx, orgUUID) + if err != nil { + return nil, fmt.Errorf("failed to find organization: %w", err) + } + if org == nil { + return nil, NewErrNotFound("organization") + } + + if org.PreventImplicitWorkflowCreation { + return nil, ErrImplicitWorkflowCreationDisabled + } + } + existingProject, _ := uc.projectRepo.FindProjectByOrgIDAndName(ctx, orgUUID, opts.Project) wf, err := uc.wfRepo.Create(ctx, opts) diff --git a/app/controlplane/pkg/biz/workflow_integration_test.go b/app/controlplane/pkg/biz/workflow_integration_test.go index 5cc81f5b7..c58aa648a 100644 --- a/app/controlplane/pkg/biz/workflow_integration_test.go +++ b/app/controlplane/pkg/biz/workflow_integration_test.go @@ -170,12 +170,26 @@ func (s *workflowIntegrationTestSuite) TestCreate() { name: "with all items", opts: &biz.WorkflowCreateOpts{OrgID: s.org.ID, Name: "another-name", Project: "project", Team: "team", Description: "description"}, }, + { + name: "implicit creation blocked when organization prevents it", + opts: &biz.WorkflowCreateOpts{OrgID: s.org.ID, Name: "blocked-workflow", Project: "blocked-project", ImplicitCreation: true}, + wantErrMsg: "implicit workflow and project creation is disabled", + }, + { + name: "explicit creation allowed even when organization prevents implicit creation", + opts: &biz.WorkflowCreateOpts{OrgID: s.org.ID, Name: "allowed-workflow", Project: "allowed-project", ImplicitCreation: false}, + }, } // Create one contract for testing _, err := s.WorkflowContract.Create(ctx, &biz.WorkflowContractCreateOpts{Name: "contract-1", OrgID: s.org.ID}) s.Require().NoError(err) + // Enable implicit workflow creation prevention for testing + orgID, _ := uuid.Parse(s.org.ID) + _, err = s.Repos.OrganizationRepo.Update(ctx, orgID, nil, nil, toPtrBool(true)) + s.Require().NoError(err) + for _, tc := range testCases { s.Run(tc.name, func() { got, err := s.Workflow.Create(ctx, tc.opts) diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20251107165851.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20251107165851.sql new file mode 100644 index 000000000..36a126b23 --- /dev/null +++ b/app/controlplane/pkg/data/ent/migrate/migrations/20251107165851.sql @@ -0,0 +1,2 @@ +-- Modify "organizations" table +ALTER TABLE "organizations" ADD COLUMN "prevent_implicit_workflow_creation" 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 a3a6191ee..e393ce55f 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:hspm2aeA53aPFKPqWqM6NdNeGc9R9kMrodA/EOV5Gyw= +h1:hG57vqhhKKahOOBTKnP7nkbUWTq0gp8AGqv1HxHqFi4= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -117,3 +117,4 @@ h1:hspm2aeA53aPFKPqWqM6NdNeGc9R9kMrodA/EOV5Gyw= 20251001215625.sql h1:adcp5r8CoL/JCfNgNZxBvY5pczlEHFH/IX64g/ji/4s= 20251007154203.sql h1:gRPipCNWs439gStSXVDxoSLqTw4SUPMiOe5fK1Y5V1Q= 20251010104841.sql h1:CRElEYC76B0I/Hg1wwYV2SpUX2CLAJyxN82sGCEBM7Y= +20251107165851.sql h1:JtEVxRcxE+4TfQ/0EfoDhxj70S1RPSql3aKvj1izJhA= diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 088e89aec..7014847a1 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -421,6 +421,7 @@ var ( {Name: "deleted_at", Type: field.TypeTime, Nullable: true}, {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}, } // 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 48d47b5d5..77a70a880 100644 --- a/app/controlplane/pkg/data/ent/mutation.go +++ b/app/controlplane/pkg/data/ent/mutation.go @@ -8606,44 +8606,45 @@ func (m *OrgInvitationMutation) ResetEdge(name string) error { // OrganizationMutation represents an operation that mutates the Organization nodes in the graph. type OrganizationMutation struct { config - op Op - typ string - id *uuid.UUID - name *string - created_at *time.Time - updated_at *time.Time - deleted_at *time.Time - block_on_policy_violation *bool - policies_allowed_hostnames *[]string - appendpolicies_allowed_hostnames []string - clearedFields map[string]struct{} - memberships map[uuid.UUID]struct{} - removedmemberships map[uuid.UUID]struct{} - clearedmemberships bool - workflow_contracts map[uuid.UUID]struct{} - removedworkflow_contracts map[uuid.UUID]struct{} - clearedworkflow_contracts bool - workflows map[uuid.UUID]struct{} - removedworkflows map[uuid.UUID]struct{} - clearedworkflows bool - cas_backends map[uuid.UUID]struct{} - removedcas_backends map[uuid.UUID]struct{} - clearedcas_backends bool - integrations map[uuid.UUID]struct{} - removedintegrations map[uuid.UUID]struct{} - clearedintegrations bool - api_tokens map[uuid.UUID]struct{} - removedapi_tokens map[uuid.UUID]struct{} - clearedapi_tokens bool - projects map[uuid.UUID]struct{} - removedprojects map[uuid.UUID]struct{} - clearedprojects bool - groups map[uuid.UUID]struct{} - removedgroups map[uuid.UUID]struct{} - clearedgroups bool - done bool - oldValue func(context.Context) (*Organization, error) - predicates []predicate.Organization + op Op + typ string + id *uuid.UUID + name *string + created_at *time.Time + updated_at *time.Time + deleted_at *time.Time + block_on_policy_violation *bool + policies_allowed_hostnames *[]string + appendpolicies_allowed_hostnames []string + prevent_implicit_workflow_creation *bool + clearedFields map[string]struct{} + memberships map[uuid.UUID]struct{} + removedmemberships map[uuid.UUID]struct{} + clearedmemberships bool + workflow_contracts map[uuid.UUID]struct{} + removedworkflow_contracts map[uuid.UUID]struct{} + clearedworkflow_contracts bool + workflows map[uuid.UUID]struct{} + removedworkflows map[uuid.UUID]struct{} + clearedworkflows bool + cas_backends map[uuid.UUID]struct{} + removedcas_backends map[uuid.UUID]struct{} + clearedcas_backends bool + integrations map[uuid.UUID]struct{} + removedintegrations map[uuid.UUID]struct{} + clearedintegrations bool + api_tokens map[uuid.UUID]struct{} + removedapi_tokens map[uuid.UUID]struct{} + clearedapi_tokens bool + projects map[uuid.UUID]struct{} + removedprojects map[uuid.UUID]struct{} + clearedprojects bool + groups map[uuid.UUID]struct{} + removedgroups map[uuid.UUID]struct{} + clearedgroups bool + done bool + oldValue func(context.Context) (*Organization, error) + predicates []predicate.Organization } var _ ent.Mutation = (*OrganizationMutation)(nil) @@ -9008,6 +9009,42 @@ func (m *OrganizationMutation) ResetPoliciesAllowedHostnames() { delete(m.clearedFields, organization.FieldPoliciesAllowedHostnames) } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (m *OrganizationMutation) SetPreventImplicitWorkflowCreation(b bool) { + m.prevent_implicit_workflow_creation = &b +} + +// PreventImplicitWorkflowCreation returns the value of the "prevent_implicit_workflow_creation" field in the mutation. +func (m *OrganizationMutation) PreventImplicitWorkflowCreation() (r bool, exists bool) { + v := m.prevent_implicit_workflow_creation + if v == nil { + return + } + return *v, true +} + +// OldPreventImplicitWorkflowCreation returns the old "prevent_implicit_workflow_creation" 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) OldPreventImplicitWorkflowCreation(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPreventImplicitWorkflowCreation is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPreventImplicitWorkflowCreation requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPreventImplicitWorkflowCreation: %w", err) + } + return oldValue.PreventImplicitWorkflowCreation, nil +} + +// ResetPreventImplicitWorkflowCreation resets all changes to the "prevent_implicit_workflow_creation" field. +func (m *OrganizationMutation) ResetPreventImplicitWorkflowCreation() { + m.prevent_implicit_workflow_creation = nil +} + // AddMembershipIDs adds the "memberships" edge to the Membership entity by ids. func (m *OrganizationMutation) AddMembershipIDs(ids ...uuid.UUID) { if m.memberships == nil { @@ -9474,7 +9511,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, 6) + fields := make([]string, 0, 7) if m.name != nil { fields = append(fields, organization.FieldName) } @@ -9493,6 +9530,9 @@ func (m *OrganizationMutation) Fields() []string { if m.policies_allowed_hostnames != nil { fields = append(fields, organization.FieldPoliciesAllowedHostnames) } + if m.prevent_implicit_workflow_creation != nil { + fields = append(fields, organization.FieldPreventImplicitWorkflowCreation) + } return fields } @@ -9513,6 +9553,8 @@ func (m *OrganizationMutation) Field(name string) (ent.Value, bool) { return m.BlockOnPolicyViolation() case organization.FieldPoliciesAllowedHostnames: return m.PoliciesAllowedHostnames() + case organization.FieldPreventImplicitWorkflowCreation: + return m.PreventImplicitWorkflowCreation() } return nil, false } @@ -9534,6 +9576,8 @@ func (m *OrganizationMutation) OldField(ctx context.Context, name string) (ent.V return m.OldBlockOnPolicyViolation(ctx) case organization.FieldPoliciesAllowedHostnames: return m.OldPoliciesAllowedHostnames(ctx) + case organization.FieldPreventImplicitWorkflowCreation: + return m.OldPreventImplicitWorkflowCreation(ctx) } return nil, fmt.Errorf("unknown Organization field %s", name) } @@ -9585,6 +9629,13 @@ func (m *OrganizationMutation) SetField(name string, value ent.Value) error { } m.SetPoliciesAllowedHostnames(v) return nil + case organization.FieldPreventImplicitWorkflowCreation: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPreventImplicitWorkflowCreation(v) + return nil } return fmt.Errorf("unknown Organization field %s", name) } @@ -9667,6 +9718,9 @@ func (m *OrganizationMutation) ResetField(name string) error { case organization.FieldPoliciesAllowedHostnames: m.ResetPoliciesAllowedHostnames() return nil + case organization.FieldPreventImplicitWorkflowCreation: + m.ResetPreventImplicitWorkflowCreation() + 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 23478a8b0..2e17f6bfe 100644 --- a/app/controlplane/pkg/data/ent/organization.go +++ b/app/controlplane/pkg/data/ent/organization.go @@ -31,6 +31,8 @@ type Organization struct { BlockOnPolicyViolation bool `json:"block_on_policy_violation,omitempty"` // PoliciesAllowedHostnames holds the value of the "policies_allowed_hostnames" field. 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"` // 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"` @@ -139,7 +141,7 @@ func (*Organization) scanValues(columns []string) ([]any, error) { switch columns[i] { case organization.FieldPoliciesAllowedHostnames: values[i] = new([]byte) - case organization.FieldBlockOnPolicyViolation: + case organization.FieldBlockOnPolicyViolation, organization.FieldPreventImplicitWorkflowCreation: values[i] = new(sql.NullBool) case organization.FieldName: values[i] = new(sql.NullString) @@ -206,6 +208,12 @@ func (o *Organization) assignValues(columns []string, values []any) error { return fmt.Errorf("unmarshal field policies_allowed_hostnames: %w", err) } } + case organization.FieldPreventImplicitWorkflowCreation: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field prevent_implicit_workflow_creation", values[i]) + } else if value.Valid { + o.PreventImplicitWorkflowCreation = value.Bool + } default: o.selectValues.Set(columns[i], values[i]) } @@ -299,6 +307,9 @@ func (o *Organization) String() string { builder.WriteString(", ") builder.WriteString("policies_allowed_hostnames=") builder.WriteString(fmt.Sprintf("%v", o.PoliciesAllowedHostnames)) + builder.WriteString(", ") + builder.WriteString("prevent_implicit_workflow_creation=") + builder.WriteString(fmt.Sprintf("%v", o.PreventImplicitWorkflowCreation)) 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 1eb7b9a72..f948fc628 100644 --- a/app/controlplane/pkg/data/ent/organization/organization.go +++ b/app/controlplane/pkg/data/ent/organization/organization.go @@ -27,6 +27,8 @@ const ( FieldBlockOnPolicyViolation = "block_on_policy_violation" // FieldPoliciesAllowedHostnames holds the string denoting the policies_allowed_hostnames field in the database. FieldPoliciesAllowedHostnames = "policies_allowed_hostnames" + // FieldPreventImplicitWorkflowCreation holds the string denoting the prevent_implicit_workflow_creation field in the database. + FieldPreventImplicitWorkflowCreation = "prevent_implicit_workflow_creation" // 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. @@ -112,6 +114,7 @@ var Columns = []string{ FieldDeletedAt, FieldBlockOnPolicyViolation, FieldPoliciesAllowedHostnames, + FieldPreventImplicitWorkflowCreation, } // ValidColumn reports if the column name is valid (part of the table columns). @@ -131,6 +134,8 @@ var ( DefaultUpdatedAt func() time.Time // DefaultBlockOnPolicyViolation holds the default value on creation for the "block_on_policy_violation" field. DefaultBlockOnPolicyViolation bool + // DefaultPreventImplicitWorkflowCreation holds the default value on creation for the "prevent_implicit_workflow_creation" field. + DefaultPreventImplicitWorkflowCreation bool // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) @@ -168,6 +173,11 @@ func ByBlockOnPolicyViolation(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldBlockOnPolicyViolation, opts...).ToFunc() } +// ByPreventImplicitWorkflowCreation orders the results by the prevent_implicit_workflow_creation field. +func ByPreventImplicitWorkflowCreation(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPreventImplicitWorkflowCreation, 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 71921b4a8..566974961 100644 --- a/app/controlplane/pkg/data/ent/organization/where.go +++ b/app/controlplane/pkg/data/ent/organization/where.go @@ -81,6 +81,11 @@ func BlockOnPolicyViolation(v bool) predicate.Organization { return predicate.Organization(sql.FieldEQ(FieldBlockOnPolicyViolation, v)) } +// PreventImplicitWorkflowCreation applies equality check predicate on the "prevent_implicit_workflow_creation" field. It's identical to PreventImplicitWorkflowCreationEQ. +func PreventImplicitWorkflowCreation(v bool) predicate.Organization { + return predicate.Organization(sql.FieldEQ(FieldPreventImplicitWorkflowCreation, v)) +} + // NameEQ applies the EQ predicate on the "name" field. func NameEQ(v string) predicate.Organization { return predicate.Organization(sql.FieldEQ(FieldName, v)) @@ -296,6 +301,16 @@ func PoliciesAllowedHostnamesNotNil() predicate.Organization { return predicate.Organization(sql.FieldNotNull(FieldPoliciesAllowedHostnames)) } +// PreventImplicitWorkflowCreationEQ applies the EQ predicate on the "prevent_implicit_workflow_creation" field. +func PreventImplicitWorkflowCreationEQ(v bool) predicate.Organization { + return predicate.Organization(sql.FieldEQ(FieldPreventImplicitWorkflowCreation, v)) +} + +// PreventImplicitWorkflowCreationNEQ applies the NEQ predicate on the "prevent_implicit_workflow_creation" field. +func PreventImplicitWorkflowCreationNEQ(v bool) predicate.Organization { + return predicate.Organization(sql.FieldNEQ(FieldPreventImplicitWorkflowCreation, 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 b28cde42a..db0c7283c 100644 --- a/app/controlplane/pkg/data/ent/organization_create.go +++ b/app/controlplane/pkg/data/ent/organization_create.go @@ -100,6 +100,20 @@ func (oc *OrganizationCreate) SetPoliciesAllowedHostnames(s []string) *Organizat return oc } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (oc *OrganizationCreate) SetPreventImplicitWorkflowCreation(b bool) *OrganizationCreate { + oc.mutation.SetPreventImplicitWorkflowCreation(b) + return oc +} + +// SetNillablePreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field if the given value is not nil. +func (oc *OrganizationCreate) SetNillablePreventImplicitWorkflowCreation(b *bool) *OrganizationCreate { + if b != nil { + oc.SetPreventImplicitWorkflowCreation(*b) + } + return oc +} + // SetID sets the "id" field. func (oc *OrganizationCreate) SetID(u uuid.UUID) *OrganizationCreate { oc.mutation.SetID(u) @@ -281,6 +295,10 @@ func (oc *OrganizationCreate) defaults() { v := organization.DefaultBlockOnPolicyViolation oc.mutation.SetBlockOnPolicyViolation(v) } + if _, ok := oc.mutation.PreventImplicitWorkflowCreation(); !ok { + v := organization.DefaultPreventImplicitWorkflowCreation + oc.mutation.SetPreventImplicitWorkflowCreation(v) + } if _, ok := oc.mutation.ID(); !ok { v := organization.DefaultID() oc.mutation.SetID(v) @@ -301,6 +319,9 @@ func (oc *OrganizationCreate) check() error { if _, ok := oc.mutation.BlockOnPolicyViolation(); !ok { return &ValidationError{Name: "block_on_policy_violation", err: errors.New(`ent: missing required field "Organization.block_on_policy_violation"`)} } + 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"`)} + } return nil } @@ -361,6 +382,10 @@ func (oc *OrganizationCreate) createSpec() (*Organization, *sqlgraph.CreateSpec) _spec.SetField(organization.FieldPoliciesAllowedHostnames, field.TypeJSON, value) _node.PoliciesAllowedHostnames = value } + if value, ok := oc.mutation.PreventImplicitWorkflowCreation(); ok { + _spec.SetField(organization.FieldPreventImplicitWorkflowCreation, field.TypeBool, value) + _node.PreventImplicitWorkflowCreation = value + } if nodes := oc.mutation.MembershipsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -613,6 +638,18 @@ func (u *OrganizationUpsert) ClearPoliciesAllowedHostnames() *OrganizationUpsert return u } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (u *OrganizationUpsert) SetPreventImplicitWorkflowCreation(v bool) *OrganizationUpsert { + u.Set(organization.FieldPreventImplicitWorkflowCreation, v) + return u +} + +// UpdatePreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field to the value that was provided on create. +func (u *OrganizationUpsert) UpdatePreventImplicitWorkflowCreation() *OrganizationUpsert { + u.SetExcluded(organization.FieldPreventImplicitWorkflowCreation) + 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: // @@ -748,6 +785,20 @@ func (u *OrganizationUpsertOne) ClearPoliciesAllowedHostnames() *OrganizationUps }) } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (u *OrganizationUpsertOne) SetPreventImplicitWorkflowCreation(v bool) *OrganizationUpsertOne { + return u.Update(func(s *OrganizationUpsert) { + s.SetPreventImplicitWorkflowCreation(v) + }) +} + +// UpdatePreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field to the value that was provided on create. +func (u *OrganizationUpsertOne) UpdatePreventImplicitWorkflowCreation() *OrganizationUpsertOne { + return u.Update(func(s *OrganizationUpsert) { + s.UpdatePreventImplicitWorkflowCreation() + }) +} + // Exec executes the query. func (u *OrganizationUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -1050,6 +1101,20 @@ func (u *OrganizationUpsertBulk) ClearPoliciesAllowedHostnames() *OrganizationUp }) } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (u *OrganizationUpsertBulk) SetPreventImplicitWorkflowCreation(v bool) *OrganizationUpsertBulk { + return u.Update(func(s *OrganizationUpsert) { + s.SetPreventImplicitWorkflowCreation(v) + }) +} + +// UpdatePreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field to the value that was provided on create. +func (u *OrganizationUpsertBulk) UpdatePreventImplicitWorkflowCreation() *OrganizationUpsertBulk { + return u.Update(func(s *OrganizationUpsert) { + s.UpdatePreventImplicitWorkflowCreation() + }) +} + // 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 656f20400..a6ae9efab 100644 --- a/app/controlplane/pkg/data/ent/organization_update.go +++ b/app/controlplane/pkg/data/ent/organization_update.go @@ -119,6 +119,20 @@ func (ou *OrganizationUpdate) ClearPoliciesAllowedHostnames() *OrganizationUpdat return ou } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (ou *OrganizationUpdate) SetPreventImplicitWorkflowCreation(b bool) *OrganizationUpdate { + ou.mutation.SetPreventImplicitWorkflowCreation(b) + return ou +} + +// SetNillablePreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field if the given value is not nil. +func (ou *OrganizationUpdate) SetNillablePreventImplicitWorkflowCreation(b *bool) *OrganizationUpdate { + if b != nil { + ou.SetPreventImplicitWorkflowCreation(*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...) @@ -480,6 +494,9 @@ func (ou *OrganizationUpdate) sqlSave(ctx context.Context) (n int, err error) { if ou.mutation.PoliciesAllowedHostnamesCleared() { _spec.ClearField(organization.FieldPoliciesAllowedHostnames, field.TypeJSON) } + if value, ok := ou.mutation.PreventImplicitWorkflowCreation(); ok { + _spec.SetField(organization.FieldPreventImplicitWorkflowCreation, field.TypeBool, value) + } if ou.mutation.MembershipsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -942,6 +959,20 @@ func (ouo *OrganizationUpdateOne) ClearPoliciesAllowedHostnames() *OrganizationU return ouo } +// SetPreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field. +func (ouo *OrganizationUpdateOne) SetPreventImplicitWorkflowCreation(b bool) *OrganizationUpdateOne { + ouo.mutation.SetPreventImplicitWorkflowCreation(b) + return ouo +} + +// SetNillablePreventImplicitWorkflowCreation sets the "prevent_implicit_workflow_creation" field if the given value is not nil. +func (ouo *OrganizationUpdateOne) SetNillablePreventImplicitWorkflowCreation(b *bool) *OrganizationUpdateOne { + if b != nil { + ouo.SetPreventImplicitWorkflowCreation(*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...) @@ -1333,6 +1364,9 @@ func (ouo *OrganizationUpdateOne) sqlSave(ctx context.Context) (_node *Organizat if ouo.mutation.PoliciesAllowedHostnamesCleared() { _spec.ClearField(organization.FieldPoliciesAllowedHostnames, field.TypeJSON) } + if value, ok := ouo.mutation.PreventImplicitWorkflowCreation(); ok { + _spec.SetField(organization.FieldPreventImplicitWorkflowCreation, 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 42baf38cc..b5548739f 100644 --- a/app/controlplane/pkg/data/ent/runtime.go +++ b/app/controlplane/pkg/data/ent/runtime.go @@ -205,6 +205,10 @@ func init() { organizationDescBlockOnPolicyViolation := organizationFields[5].Descriptor() // organization.DefaultBlockOnPolicyViolation holds the default value on creation for the block_on_policy_violation field. organization.DefaultBlockOnPolicyViolation = organizationDescBlockOnPolicyViolation.Default.(bool) + // organizationDescPreventImplicitWorkflowCreation is the schema descriptor for prevent_implicit_workflow_creation field. + organizationDescPreventImplicitWorkflowCreation := organizationFields[7].Descriptor() + // organization.DefaultPreventImplicitWorkflowCreation holds the default value on creation for the prevent_implicit_workflow_creation field. + organization.DefaultPreventImplicitWorkflowCreation = organizationDescPreventImplicitWorkflowCreation.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 0500588bc..b422f9988 100644 --- a/app/controlplane/pkg/data/ent/schema/organization.go +++ b/app/controlplane/pkg/data/ent/schema/organization.go @@ -51,6 +51,8 @@ func (Organization) Fields() []ent.Field { field.Bool("block_on_policy_violation").Default(false), // array of hostnames that are allowed to be used in the policies 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), } } diff --git a/app/controlplane/pkg/data/organization.go b/app/controlplane/pkg/data/organization.go index 15f5b4eea..75b921352 100644 --- a/app/controlplane/pkg/data/organization.go +++ b/app/controlplane/pkg/data/organization.go @@ -77,10 +77,11 @@ 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) (*biz.Organization, error) { +func (r *OrganizationRepo) Update(ctx context.Context, id uuid.UUID, blockOnPolicyViolation *bool, policiesAllowedHostnames []string, preventImplicitWorkflowCreation *bool) (*biz.Organization, error) { opts := r.data.DB.Organization.UpdateOneID(id). Where(organization.DeletedAtIsNil()). SetNillableBlockOnPolicyViolation(blockOnPolicyViolation). + SetNillablePreventImplicitWorkflowCreation(preventImplicitWorkflowCreation). SetUpdatedAt(time.Now()) if policiesAllowedHostnames != nil { @@ -107,9 +108,10 @@ func (r *OrganizationRepo) Delete(ctx context.Context, id uuid.UUID) error { func entOrgToBizOrg(eu *ent.Organization) *biz.Organization { return &biz.Organization{ Name: eu.Name, ID: eu.ID.String(), - CreatedAt: toTimePtr(eu.CreatedAt), - UpdatedAt: toTimePtr(eu.UpdatedAt), - BlockOnPolicyViolation: eu.BlockOnPolicyViolation, - PoliciesAllowedHostnames: eu.PoliciesAllowedHostnames, + CreatedAt: toTimePtr(eu.CreatedAt), + UpdatedAt: toTimePtr(eu.UpdatedAt), + BlockOnPolicyViolation: eu.BlockOnPolicyViolation, + PoliciesAllowedHostnames: eu.PoliciesAllowedHostnames, + PreventImplicitWorkflowCreation: eu.PreventImplicitWorkflowCreation, } }