github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/graphql/webhook_validation.go (about) 1 package graphql 2 3 import ( 4 "net/url" 5 6 validation "github.com/go-ozzo/ozzo-validation/v4" 7 "github.com/go-ozzo/ozzo-validation/v4/is" 8 "github.com/kyma-incubator/compass/components/director/internal/model" 9 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 10 "github.com/kyma-incubator/compass/components/director/pkg/webhook" 11 ) 12 13 var emptyApplicationLifecycleWebhookRequestObject = &webhook.ApplicationLifecycleWebhookRequestObject{ 14 Application: &Application{ 15 BaseEntity: &BaseEntity{}, 16 }, 17 } 18 19 var emptyFormationConfigurationChangeInput = &webhook.FormationConfigurationChangeInput{ 20 Assignment: &webhook.FormationAssignment{ 21 Value: "\"\"", 22 }, 23 ReverseAssignment: &webhook.FormationAssignment{ 24 Value: "\"\"", 25 }, 26 ApplicationTemplate: &webhook.ApplicationTemplateWithLabels{ 27 ApplicationTemplate: &model.ApplicationTemplate{}, 28 Labels: map[string]string{}, 29 }, 30 Application: &webhook.ApplicationWithLabels{ 31 Application: &model.Application{ 32 BaseEntity: &model.BaseEntity{}, 33 }, 34 Labels: map[string]string{}, 35 }, 36 Runtime: &webhook.RuntimeWithLabels{ 37 Runtime: &model.Runtime{}, 38 Labels: map[string]string{}, 39 }, 40 RuntimeContext: &webhook.RuntimeContextWithLabels{ 41 RuntimeContext: &model.RuntimeContext{}, 42 Labels: map[string]string{}, 43 }, 44 CustomerTenantContext: &webhook.CustomerTenantContext{}, 45 } 46 47 var emptyApplicationTenantMappingInput = &webhook.ApplicationTenantMappingInput{ 48 Assignment: &webhook.FormationAssignment{ 49 Value: "\"\"", 50 }, 51 ReverseAssignment: &webhook.FormationAssignment{ 52 Value: "\"\"", 53 }, 54 SourceApplicationTemplate: &webhook.ApplicationTemplateWithLabels{ 55 ApplicationTemplate: &model.ApplicationTemplate{}, 56 Labels: map[string]string{}, 57 }, 58 SourceApplication: &webhook.ApplicationWithLabels{ 59 Application: &model.Application{ 60 BaseEntity: &model.BaseEntity{}, 61 }, 62 Labels: map[string]string{}, 63 }, 64 TargetApplicationTemplate: &webhook.ApplicationTemplateWithLabels{ 65 ApplicationTemplate: &model.ApplicationTemplate{}, 66 Labels: map[string]string{}, 67 }, 68 TargetApplication: &webhook.ApplicationWithLabels{ 69 Application: &model.Application{ 70 BaseEntity: &model.BaseEntity{}, 71 }, 72 Labels: map[string]string{}, 73 }, 74 CustomerTenantContext: &webhook.CustomerTenantContext{}, 75 } 76 77 var emptyFormationLifecycleInput = &webhook.FormationLifecycleInput{ 78 Formation: &model.Formation{}, 79 CustomerTenantContext: &webhook.CustomerTenantContext{}, 80 } 81 82 var webhookTemplateInputByType = map[WebhookType]webhook.TemplateInput{ 83 WebhookTypeRegisterApplication: emptyApplicationLifecycleWebhookRequestObject, 84 WebhookTypeUnregisterApplication: emptyApplicationLifecycleWebhookRequestObject, 85 WebhookTypeConfigurationChanged: emptyFormationConfigurationChangeInput, 86 WebhookTypeApplicationTenantMapping: emptyApplicationTenantMappingInput, 87 WebhookTypeFormationLifecycle: emptyFormationLifecycleInput, 88 } 89 90 // Validate missing godoc 91 func (i WebhookInput) Validate() error { 92 if err := validation.ValidateStruct(&i, 93 validation.Field(&i.Type, validation.Required, validation.In(WebhookTypeConfigurationChanged, WebhookTypeApplicationTenantMapping, WebhookTypeRegisterApplication, WebhookTypeUnregisterApplication, WebhookTypeOpenResourceDiscovery, WebhookTypeFormationLifecycle)), 94 validation.Field(&i.URL, is.URL, validation.RuneLength(0, longStringLengthLimit)), 95 validation.Field(&i.CorrelationIDKey, validation.RuneLength(0, longStringLengthLimit)), 96 validation.Field(&i.Mode, validation.In(WebhookModeSync, WebhookModeAsync, WebhookModeAsyncCallback), validation.When(i.Type == WebhookTypeConfigurationChanged || i.Type == WebhookTypeApplicationTenantMapping || i.Type == WebhookTypeFormationLifecycle, validation.In(WebhookModeSync, WebhookModeAsyncCallback)).Else(validation.NotIn(WebhookModeAsyncCallback))), 97 validation.Field(&i.RetryInterval, validation.Min(0)), 98 validation.Field(&i.Timeout, validation.Min(0)), 99 validation.Field(&i.Auth), 100 ); err != nil { 101 return err 102 } 103 104 if i.URL == nil && i.URLTemplate == nil { 105 return apperrors.NewInvalidDataError("missing webhook url") 106 } 107 108 if i.URL != nil && i.URLTemplate != nil { 109 return apperrors.NewInvalidDataError("cannot provide both webhook url and url template") 110 } 111 112 if i.URL != nil { 113 _, err := url.ParseRequestURI(*i.URL) 114 if err != nil { 115 return apperrors.NewInvalidDataError("failed to parse webhook url: %s", err) 116 } 117 } 118 119 requestObject := webhookTemplateInputByType[i.Type] 120 if i.URLTemplate != nil { 121 if requestObject == nil { 122 return apperrors.NewInvalidDataError("missing template input for type: %s", i.Type) 123 } 124 if _, err := requestObject.ParseURLTemplate(i.URLTemplate); err != nil { 125 return apperrors.NewInvalidDataError("failed to parse webhook url template: %s", err) 126 } 127 } 128 129 if i.InputTemplate != nil { 130 if requestObject == nil { 131 return apperrors.NewInvalidDataError("missing template input for type: %s", i.Type) 132 } 133 if _, err := requestObject.ParseInputTemplate(i.InputTemplate); err != nil { 134 return apperrors.NewInvalidDataError("failed to parse webhook input template: %s", err) 135 } 136 } 137 138 if i.HeaderTemplate != nil { 139 if requestObject == nil { 140 return apperrors.NewInvalidDataError("missing template input for type: %s", i.Type) 141 } 142 if _, err := requestObject.ParseHeadersTemplate(i.HeaderTemplate); err != nil { 143 return apperrors.NewInvalidDataError("failed to parse webhook headers template: %s", err) 144 } 145 } 146 147 if i.OutputTemplate == nil && isOutTemplateMandatory(i.Type) { 148 return apperrors.NewInvalidDataError("outputTemplate is required for type: %v", i.Type) 149 } 150 151 var responseObject webhook.ResponseObject 152 if i.OutputTemplate != nil { 153 if _, err := responseObject.ParseOutputTemplate(i.OutputTemplate); err != nil { 154 return apperrors.NewInvalidDataError("failed to parse webhook output template: %s", err) 155 } 156 } 157 158 if i.Mode != nil && *i.Mode == WebhookModeAsync { 159 if i.StatusTemplate != nil { 160 if _, err := responseObject.ParseStatusTemplate(i.StatusTemplate); err != nil { 161 return apperrors.NewInvalidDataError("failed to parse webhook status template: %s", err) 162 } 163 } else { 164 return apperrors.NewInvalidDataError("missing webhook status template") 165 } 166 } 167 168 return nil 169 } 170 171 func isOutTemplateMandatory(webhookType WebhookType) bool { 172 switch webhookType { 173 case WebhookTypeRegisterApplication, 174 WebhookTypeUnregisterApplication: 175 return true 176 default: 177 return false 178 } 179 }