// Verifies if a tracked resource has a corresponding PATCH operation
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context)
        {
            ServiceDefinition serviceDefinition = (ServiceDefinition)context.Root;
            // enumerate all the PATCH operations
            IEnumerable <Operation> patchOperations = ValidationUtilities.GetOperationsByRequestMethod("patch", serviceDefinition);

            foreach (var op in patchOperations)
            {
                var reqModels = op.Parameters.Where(p => p.In == ParameterLocation.Body).Select(p => p.Schema?.Reference?.StripDefinitionPath()).Where(p => !string.IsNullOrEmpty(p));
                foreach (var reqModel in reqModels)
                {
                    // select all models that have properties set to required
                    var reqProps = ValidationUtilities.EnumerateRequiredProperties(reqModel, definitions);

                    // select all models that have properties with default values
                    var defValProps = ValidationUtilities.EnumerateDefaultValuedProperties(reqModel, definitions);

                    var modelHierarchy = ValidationUtilities.EnumerateModelHierarchy(reqModel, definitions);

                    foreach (var reqProp in reqProps)
                    {
                        var modelContainingReqProp = modelHierarchy.First(model => definitions[model].Required?.Contains(reqProp) == true);
                        yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(modelContainingReqProp).AppendProperty("required")), this, "required", op.OperationId, modelContainingReqProp, reqProp));
                    }

                    foreach (var defValProp in defValProps)
                    {
                        var modelContainingDefValProp = modelHierarchy.First(model => definitions[model].Properties?.Contains(defValProp) == true);
                        yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(modelContainingDefValProp).AppendProperty("properties").AppendProperty(defValProp.Key)), this, "default-valued", op.OperationId, modelContainingDefValProp, defValProp.Key));
                    }
                }
            }
        }
        /// <summary>
        /// Validation fails iof tracked resource fails to meet one of the four required criteria.
        /// </summary>
        /// <param name="definitions">Operation Definition to validate</param>
        /// <param name="formatParameters">The noun to be put in the failure message</param>
        /// <returns></returns>
        public override bool IsValid(Dictionary <string, Schema> definitions, RuleContext context, out object[] formatParameters)
        {
            IEnumerable <Operation> getOperations = ValidationUtilities.GetOperationsByRequestMethod("get", (ServiceDefinition)context.Root);

            foreach (KeyValuePair <string, Schema> definition in definitions)
            {
                if (!exemptedNames.IsMatch(definition.Key) && ValidationUtilities.IsTrackedResource(definition.Value, definitions))
                {
                    bool getCheck = getOperations.Any(operation =>
                                                      operation.Responses.Any(response =>
                                                                              response.Key.Equals("200") &&
                                                                              response.Value.Schema != null &&
                                                                              response.Value.Schema.Reference != null &&
                                                                              response.Value.Schema.Reference.EndsWith("/" + definition.Key)
                                                                              )
                                                      );
                    if (!getCheck)
                    {
                        formatParameters    = new object[2];
                        formatParameters[0] = definition.Key;
                        formatParameters[1] = 1;
                        return(false);
                    }

                    bool listByResourceGroupCheck = this.ListByXCheck(getOperations, listByRgRegEx, definition.Key, definitions);
                    if (!listByResourceGroupCheck)
                    {
                        formatParameters    = new object[2];
                        formatParameters[0] = definition.Key;
                        formatParameters[1] = 2;
                        return(false);
                    }

                    bool listBySubscriptionIdCheck = this.ListByXCheck(getOperations, listBySidRegEx, definition.Key, definitions);
                    if (!listBySubscriptionIdCheck)
                    {
                        formatParameters    = new object[2];
                        formatParameters[0] = definition.Key;
                        formatParameters[1] = 3;
                        return(false);
                    }

                    bool schemaResult = this.HandleSchema(definition.Value, definitions);
                    if (!schemaResult)
                    {
                        formatParameters    = new object[2];
                        formatParameters[0] = definition.Key;
                        formatParameters[1] = 4;
                        return(false);
                    }
                }
            }

            formatParameters = new object[0];
            return(true);
        }
Example #3
0
        /// <summary>
        /// Verifies if a tracked resource has a corresponding get operation
        /// </summary>
        /// <param name="definitions"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context)
        {
            // Retrieve the list of TrackedResources
            IEnumerable <string> trackedResources = context.TrackedResourceModels;

            // Retrieve the list of getOperations
            IEnumerable <Operation> getOperations = ValidationUtilities.GetOperationsByRequestMethod("get", context.Root);

            foreach (string trackedResource in trackedResources)
            {
                // check for 200 status response models since they correspond to a successful get operation
                if (!getOperations.Any(op => op.Responses.ContainsKey("200") && (trackedResource).Equals(op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath())))
                {
                    yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(trackedResource)), this, trackedResource));
                }
            }
        }
Example #4
0
        // Verifies if a tracked resource has a corresponding PATCH operation
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > paths, RuleContext context)
        {
            var serviceDefinition = context.Root;
            var ops           = ValidationUtilities.GetOperationsByRequestMethod("put", serviceDefinition);
            var putRespModels = ops.Select(op => (op.Responses?.ContainsKey("200") != true) ? null : op.Responses["200"].Schema?.Reference?.StripDefinitionPath());

            putRespModels = putRespModels.Where(modelName => !string.IsNullOrEmpty(modelName));
            var xmsResModels    = ValidationUtilities.GetXmsAzureResourceModels(serviceDefinition.Definitions);
            var violatingModels = putRespModels.Where(respModel => !ValidationUtilities.EnumerateModelHierarchy(respModel, serviceDefinition.Definitions).Intersect(xmsResModels).Any());

            foreach (var model in violatingModels)
            {
                var violatingOp     = ops.Where(op => (op.Responses?.ContainsKey("200") == true) && op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath() == model).First();
                var violatingPath   = ValidationUtilities.GetOperationIdPath(violatingOp.OperationId, paths);
                var violatingOpVerb = ValidationUtilities.GetOperationIdVerb(violatingOp.OperationId, violatingPath);
                yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(violatingPath.Key).AppendProperty(violatingOpVerb)), this, violatingOp.OperationId, model));
            }
        }
Example #5
0
        /// <summary>
        /// Verifies if a tracked resource has a corresponding ListBySubscription operation
        /// </summary>
        /// <param name="definitions"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context)
        {
            // Retrieve the list of TrackedResources
            IEnumerable <string> trackedResources = context.TrackedResourceModels;

            // Retrieve the list of getOperations
            IEnumerable <Operation> getOperations = ValidationUtilities.GetOperationsByRequestMethod("get", context.Root);

            foreach (string trackedResource in trackedResources)
            {
                bool listBySubscriptionsCheck = ValidationUtilities.ListByXCheck(getOperations, listBySidRegEx, trackedResource, definitions);

                if (!listBySubscriptionsCheck)
                {
                    yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(trackedResource)), this, trackedResource));
                }
            }
        }
        /// <summary>
        /// Verifies if a tracked resource has a corresponding patch operation
        /// </summary>
        /// <param name="definitions"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override IEnumerable<ValidationMessage> GetValidationMessages(Dictionary<string, Schema> definitions, RuleContext context)
        {
            ServiceDefinition serviceDefinition = (ServiceDefinition)context.Root;
            // enumerate all the PATCH operations
            IEnumerable<Operation> patchOperations = ValidationUtilities.GetOperationsByRequestMethod("patch", serviceDefinition);

            // enumerate all the models returned by all PATCH operations (200/201 responses)
            var respModels = patchOperations.Select(op => op.Responses.GetValueOrNull("200")?.Schema?.Reference?.StripDefinitionPath());
            respModels.Union(patchOperations.Select(op => op.Responses.GetValueOrNull("201")?.Schema?.Reference?.StripDefinitionPath())).Where(modelName => !string.IsNullOrEmpty(modelName));

            // find models that are not being returned by any of the PATCH operations
            var violatingModels = context.TrackedResourceModels.Except(respModels);

            foreach (var modelName in violatingModels)
            {
                yield return new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(modelName)), this, modelName);
            }
        }
Example #7
0
        /// Verifies if a PUT operation request and response schemas match
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > paths, RuleContext context)
        {
            var serviceDefinition = (ServiceDefinition)context.Root;
            var ops = ValidationUtilities.GetOperationsByRequestMethod("put", serviceDefinition);

            foreach (var op in ops)
            {
                // if PUT operation does not have any request parameters, skip, let some other validation rule handle it
                // if no 200 response exists, skip, let some other validation rule handle empty PUT response operations
                if (op.Parameters?.Any() != true || op.Responses?.ContainsKey("200") != true || serviceDefinition.Definitions?.Any() != true)
                {
                    continue;
                }

                // look for the request body schema in the operation parameters section as well as the global parameters section
                string reqBodySchema = null;
                if (op.Parameters.Any(p => p.In == ParameterLocation.Body))
                {
                    reqBodySchema = op.Parameters.First(p => p.In == ParameterLocation.Body).Schema?.Reference?.StripDefinitionPath();
                }
                else
                {
                    var opGlobalParams = op.Parameters.Where(p => serviceDefinition.Parameters.ContainsKey(p.Reference?.StripParameterPath() ?? ""));
                    if (opGlobalParams.Any())
                    {
                        reqBodySchema = opGlobalParams.FirstOrDefault(p => p.In == ParameterLocation.Body)?.Schema?.Reference?.StripDefinitionPath();
                    }
                }

                // if no body parameters were found, skip, let some other validation handle an empty body put operation
                if (string.IsNullOrEmpty(reqBodySchema) || !serviceDefinition.Definitions.ContainsKey(reqBodySchema))
                {
                    continue;
                }
                var respModel = op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath() ?? string.Empty;
                // if the 200 response schema does not match the request body parameter schema, flag violation
                if (respModel != reqBodySchema)
                {
                    var violatingPath   = ValidationUtilities.GetOperationIdPath(op.OperationId, paths);
                    var violatingOpVerb = ValidationUtilities.GetOperationIdVerb(op.OperationId, violatingPath);
                    yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(violatingPath.Key).AppendProperty(violatingOpVerb)), this, op.OperationId, reqBodySchema, respModel));
                }
            }
        }
Example #8
0
        // Verifies if a tracked resource has a corresponding get operation
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context)
        {
            ServiceDefinition       serviceDefinition = context.Root;
            IEnumerable <Operation> getOperations     = ValidationUtilities.GetOperationsByRequestMethod("get", serviceDefinition);

            foreach (KeyValuePair <string, Schema> definition in definitions)
            {
                if (context.TrackedResourceModels.Contains(definition.Key.StripDefinitionPath()))
                {
                    // check for 200 status response models since they correspond to a successful get operation
                    if (!getOperations.Any(op => op.Responses.ContainsKey("200") && (op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath()) == definition.Key))
                    {
                        // if no GET operation returns current tracked resource as a response,
                        // the tracked resource does not have a corresponding get operation
                        yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path), this, definition.Key.StripDefinitionPath()));
                    }
                }
            }
        }
Example #9
0
        // Verifies if a tracked resource has a corresponding patch operation
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context)
        {
            ServiceDefinition       serviceDefinition = (ServiceDefinition)context.Root;
            IEnumerable <Operation> patchOperations   = ValidationUtilities.GetOperationsByRequestMethod("patch", serviceDefinition);
            var respDefinitions = ValidationUtilities.GetResponseModelDefinitions(serviceDefinition);

            foreach (KeyValuePair <string, Schema> definition in definitions)
            {
                if (respDefinitions.Contains(definition.Key) && ValidationUtilities.IsTrackedResource(definition.Value, definitions))
                {
                    if (!patchOperations.Any(op => (op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath()) == definition.Key))
                    {
                        // if no patch operation returns current tracked resource as a response,
                        // the tracked resource does not have a corresponding patch operation
                        yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path), this, definition.Key.StripDefinitionPath()));
                    }
                }
            }
        }